--- apiVersion: apps/v1 kind: Deployment metadata: name: qbittorrent namespace: media labels: app: qbittorrent app.kubernetes.io/name: qbittorrent app.kubernetes.io/component: download-client vpn: "true" spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: qbittorrent template: metadata: labels: app: qbittorrent vpn: "true" spec: containers: # Gluetun VPN Sidecar - MUST be first container - name: gluetun image: qmcgaw/gluetun:latest securityContext: capabilities: add: - NET_ADMIN env: - name: TZ valueFrom: configMapKeyRef: name: media-config key: TZ # Mullvad credentials from secret - name: WIREGUARD_PRIVATE_KEY valueFrom: secretKeyRef: name: mullvad-vpn key: WIREGUARD_PRIVATE_KEY - name: WIREGUARD_ADDRESSES valueFrom: secretKeyRef: name: mullvad-vpn key: WIREGUARD_ADDRESSES envFrom: - configMapRef: name: gluetun-config # Gluetun needs /dev/net/tun volumeMounts: - name: tun-device mountPath: /dev/net/tun - name: gluetun-data mountPath: /gluetun ports: # All ports must be on Gluetun container since it owns the network - name: http containerPort: 8080 protocol: TCP - name: torrent-tcp containerPort: 6881 protocol: TCP - name: torrent-udp containerPort: 6881 protocol: UDP - name: http-proxy containerPort: 8888 protocol: TCP resources: requests: memory: "128Mi" cpu: "50m" limits: memory: "512Mi" cpu: "500m" livenessProbe: exec: command: - /gluetun-entrypoint - healthcheck initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 readinessProbe: exec: command: - /gluetun-entrypoint - healthcheck initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 5 # qBittorrent - uses Gluetun's network namespace - name: qbittorrent image: lscr.io/linuxserver/qbittorrent:latest envFrom: - configMapRef: name: media-config volumeMounts: - name: config mountPath: /config subPath: qbittorrent - name: downloads mountPath: /downloads - name: init-script mountPath: /custom-cont-init.d/qbittorrent-init.sh subPath: qbittorrent-init.sh resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "1Gi" cpu: "1000m" # Note: No ports here - they're on the gluetun container # Health check via localhost since we share network namespace livenessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 60 periodSeconds: 30 timeoutSeconds: 10 readinessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 volumes: - name: tun-device hostPath: path: /dev/net/tun type: CharDevice - name: gluetun-data emptyDir: {} - name: config persistentVolumeClaim: claimName: media-config - name: downloads persistentVolumeClaim: claimName: media-downloads - name: init-script configMap: name: qbittorrent-init-script defaultMode: 0755 --- apiVersion: v1 kind: Service metadata: name: qbittorrent namespace: media labels: app: qbittorrent spec: type: NodePort selector: app: qbittorrent ports: - name: http port: 8080 targetPort: 8080 nodePort: 30080 protocol: TCP # Note: Torrent ports are not exposed externally when using VPN # Peers will connect via VPN IP, not node IP