feat: update JDownloader deployment for VLAN 50 migration with enhanced network configuration and egress guard
Some checks failed
validate / lint (push) Failing after 1s
Some checks failed
validate / lint (push) Failing after 1s
This commit is contained in:
parent
2f7ec5f5b1
commit
756fa120b3
@ -1,6 +1,25 @@
|
||||
# Apply: kubectl apply -f manifests/media/jdownloader.yaml
|
||||
# Delete: kubectl delete -f manifests/media/jdownloader.yaml
|
||||
# Description: JDownloader deployment with Ingress at jdownloader.home.arpa.
|
||||
#
|
||||
# *** VLAN 50 MIGRATION — DO NOT PUSH TO main WITHOUT SEPARATE, EXPLICIT
|
||||
# APPROVAL — AND ONLY AFTER qBittorrent (manifests/media/
|
||||
# qbittorrent.yaml) HAS BEEN LIVE, VALIDATED, AND SOAKED. plan.md is
|
||||
# explicit: migrate qBittorrent first, soak, then JDownloader,
|
||||
# independently soaked — do not batch them. ***
|
||||
# Same VLAN 50/Multus design as qbittorrent.yaml (see that file's header
|
||||
# for the full precondition list — pia-gateway, vlan50-parent, and
|
||||
# manifests/multus/ all applied and verified first). One difference:
|
||||
# JDownloader has no reliably-persistent, file-editable interface-bind
|
||||
# setting the way qBittorrent's qBittorrent.conf does (its own
|
||||
# preferences aren't a simple INI this repo can safely patch), so this
|
||||
# migration relies on the network-namespace egress guard alone for
|
||||
# enforcement, exactly as plan.md anticipates for JDownloader
|
||||
# specifically ("application-level interface binding may be weaker or
|
||||
# unavailable... the namespace egress guard is mandatory").
|
||||
# `media` has selfHeal+automated sync already configured — pushing this
|
||||
# file deploys it immediately. Rollback copy, not synced by any
|
||||
# Application: manifests/media/rollback/jdownloader-gluetun.yaml.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@ -17,66 +36,65 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app: jdownloader
|
||||
annotations:
|
||||
k8s.v1.cni.cncf.io/networks: |
|
||||
[{"name": "vlan50", "namespace": "downloads", "interface": "net1", "ips": ["10.10.50.11/24"]}]
|
||||
spec:
|
||||
# Hard-pinned to nik-debian, not just node-role: storage — see
|
||||
# qbittorrent.yaml for why.
|
||||
nodeSelector:
|
||||
node-role: storage
|
||||
containers:
|
||||
- name: gluetun
|
||||
image: qmcgaw/gluetun:v3.41
|
||||
kubernetes.io/hostname: nik-debian
|
||||
# No cluster DNS/CoreDNS resolution needed or provided here — see
|
||||
# qbittorrent.yaml for the full reasoning (identical here: this pod
|
||||
# never looks up an in-cluster service by name).
|
||||
dnsPolicy: None
|
||||
dnsConfig:
|
||||
nameservers:
|
||||
- "10.10.40.53"
|
||||
initContainers:
|
||||
# NET_ADMIN lives here ONLY. No qBittorrent-style config-bind
|
||||
# sibling init container — see this file's header for why
|
||||
# JDownloader relies on the egress guard alone.
|
||||
- name: vlan50-egress-guard
|
||||
image: nicolaka/netshoot:v0.11
|
||||
command: ["/bin/sh", "/scripts/guard.sh"]
|
||||
env:
|
||||
- name: VLAN50_GATEWAY
|
||||
value: "10.10.50.1"
|
||||
- name: TECHNITIUM_IP
|
||||
value: "10.10.40.53"
|
||||
- name: POD_CIDR
|
||||
value: "10.42.0.0/16"
|
||||
- name: SERVICE_CIDR
|
||||
value: "10.43.0.0/16"
|
||||
- name: NODE_IP
|
||||
value: "10.10.40.20"
|
||||
- name: EXPECTED_VLAN50_IP
|
||||
value: "10.10.50.11"
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- NET_ADMIN
|
||||
env:
|
||||
- name: VPN_SERVICE_PROVIDER
|
||||
value: private internet access
|
||||
- name: VPN_TYPE
|
||||
value: openvpn
|
||||
- name: SERVER_REGIONS
|
||||
value: JP Tokyo,Taiwan,Hong Kong
|
||||
# value: US Seattle,US Oregon,US Silicon Valley
|
||||
- name: OPENVPN_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: pia-credentials
|
||||
key: OPENVPN_USER
|
||||
- name: OPENVPN_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: pia-credentials
|
||||
key: OPENVPN_PASSWORD
|
||||
- name: FIREWALL_OUTBOUND_SUBNETS
|
||||
value: "10.42.0.0/16,10.43.0.0/16,10.10.40.0/24"
|
||||
- name: BLOCK_IPV6
|
||||
value: "on"
|
||||
startupProbe:
|
||||
exec:
|
||||
command:
|
||||
- /gluetun-entrypoint
|
||||
- healthcheck
|
||||
periodSeconds: 10
|
||||
failureThreshold: 60
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /gluetun-entrypoint
|
||||
- healthcheck
|
||||
periodSeconds: 30
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /gluetun-entrypoint
|
||||
- healthcheck
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
drop: ["ALL"]
|
||||
# NET_RAW alongside NET_ADMIN: the guard script's
|
||||
# arping-based duplicate-address and gateway-reachability
|
||||
# checks need it — see
|
||||
# vlan50-egress-guard-script.yaml's header comment.
|
||||
add: ["NET_ADMIN", "NET_RAW"]
|
||||
volumeMounts:
|
||||
- name: tun
|
||||
mountPath: /dev/net/tun
|
||||
- name: guard-script
|
||||
mountPath: /scripts
|
||||
containers:
|
||||
- name: jdownloader
|
||||
image: jlesage/jdownloader-2:latest
|
||||
ports:
|
||||
- containerPort: 5800
|
||||
# No securityContext capability restriction here, deliberately
|
||||
# — jlesage/jdownloader-2 uses the same docker-baseimage-gui
|
||||
# PUID/GID pattern as linuxserver's images (USER_ID/GROUP_ID
|
||||
# below): starts as root, its own init chowns /config to the
|
||||
# requested uid/gid and drops privileges from there. See
|
||||
# qbittorrent.yaml's app container for the fuller version of
|
||||
# this reasoning — same conclusion, same kind of image.
|
||||
env:
|
||||
- name: USER_ID
|
||||
value: "1000"
|
||||
@ -112,6 +130,12 @@ spec:
|
||||
image: python:3.12-alpine
|
||||
ports:
|
||||
- containerPort: 9667
|
||||
# Unlike the jdownloader container above, this is a plain
|
||||
# Python base image with no PUID/GID privilege-drop machinery
|
||||
# to preserve — dropping all capabilities here is safe.
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 5m
|
||||
@ -149,8 +173,10 @@ spec:
|
||||
|
||||
# .torrent files aren't handled by JDownloader's crawler (no BT
|
||||
# plugin), so fetch the raw file ourselves instead of writing a
|
||||
# crawljob. This container shares gluetun's netns, so the fetch
|
||||
# is still VPN-routed same as JDownloader's own downloads.
|
||||
# crawljob. This container shares the pod's network namespace
|
||||
# (and its vlan50-egress-guard init container's routes/rules),
|
||||
# so the fetch is still VPN-routed same as JDownloader's own
|
||||
# downloads.
|
||||
if basename.lower().endswith('.torrent'):
|
||||
safe_name = basename.replace('/', '_').replace('\\', '_')
|
||||
try:
|
||||
@ -183,10 +209,6 @@ spec:
|
||||
|
||||
http.server.HTTPServer(('0.0.0.0', 9667), Handler).serve_forever()
|
||||
volumes:
|
||||
- name: tun
|
||||
hostPath:
|
||||
path: /dev/net/tun
|
||||
type: CharDevice
|
||||
- name: config
|
||||
hostPath:
|
||||
path: /data/jdownloader
|
||||
@ -195,6 +217,10 @@ spec:
|
||||
hostPath:
|
||||
path: /mnt/storage/dl
|
||||
type: Directory
|
||||
- name: guard-script
|
||||
configMap:
|
||||
name: vlan50-egress-guard-script
|
||||
defaultMode: 365 # octal 0555, r-xr-xr-x
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user