ef8dc293e5
ProtonVPN does not NAT ICMP to external IPs (1.1.1.1, 8.8.8.8), causing the periodic small health check to always fail and restart the VPN loop. 10.2.0.1 (WireGuard gateway) responds to ICMP at ~28ms and remains reachable as long as the WireGuard tunnel itself is up.
193 lines
6.7 KiB
YAML
193 lines
6.7 KiB
YAML
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: fornax-worker-WORKER_ID
|
|
namespace: media
|
|
labels:
|
|
app: fornax-worker-WORKER_ID
|
|
app.kubernetes.io/part-of: fornax
|
|
app.kubernetes.io/component: worker
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: fornax-worker-WORKER_ID
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: fornax-worker-WORKER_ID
|
|
spec:
|
|
initContainers:
|
|
- name: tun-setup
|
|
image: busybox:latest
|
|
securityContext:
|
|
privileged: true
|
|
command:
|
|
- sh
|
|
- -c
|
|
- >-
|
|
mkdir -p /dev/net &&
|
|
[ -c /dev/net/tun ] || mknod /dev/net/tun c 10 200 &&
|
|
chmod 666 /dev/net/tun &&
|
|
sysctl -w net.ipv6.conf.all.disable_ipv6=1 || true &&
|
|
ip route flush table 51820 2>/dev/null || true &&
|
|
ip rule del priority 101 2>/dev/null || true &&
|
|
ip rule del table 51820 2>/dev/null || true
|
|
- name: qbt-config-patch
|
|
image: busybox:latest
|
|
command:
|
|
- sh
|
|
- -c
|
|
- |
|
|
CONF=/config/qBittorrent/qBittorrent.conf
|
|
HASH='@ByteArray(HqYj1eGsdXlQ4CSy597Y9A==:J9hsJIlU5FYfHb5rY5qQoIpVpTijryS/H+CE07oMtplL/ytneBVFd2tfVJtqGjhdht8tEi4wmqSSlqTgEu444w==)'
|
|
mkdir -p /config/qBittorrent
|
|
if [ -f "$CONF" ]; then
|
|
if grep -q "Password_PBKDF2" "$CONF"; then
|
|
sed -i "s|WebUI\\\\Password_PBKDF2=.*|WebUI\\\\Password_PBKDF2=\"$HASH\"|" "$CONF"
|
|
else
|
|
sed -i "/^\\[Preferences\\]/a WebUI\\\\Password_PBKDF2=\"$HASH\"" "$CONF"
|
|
fi
|
|
fi
|
|
echo "Password hash set."
|
|
volumeMounts:
|
|
- mountPath: /config
|
|
name: config
|
|
containers:
|
|
- name: gluetun
|
|
image: ghcr.io/qdm12/gluetun:latest
|
|
imagePullPolicy: Always
|
|
securityContext:
|
|
capabilities:
|
|
add:
|
|
- NET_ADMIN
|
|
env:
|
|
- name: VPN_SERVICE_PROVIDER
|
|
value: custom
|
|
- name: VPN_TYPE
|
|
value: wireguard
|
|
- name: WIREGUARD_PRIVATE_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: fornax-worker-WORKER_ID-secrets
|
|
key: PROTONVPN_PRIVATE_KEY
|
|
- name: WIREGUARD_PUBLIC_KEY
|
|
value: PLACEHOLDER_PUBLIC_KEY
|
|
- name: WIREGUARD_ADDRESSES
|
|
value: 10.2.0.2/32
|
|
- name: WIREGUARD_ENDPOINT_IP
|
|
value: PLACEHOLDER_ENDPOINT_IP
|
|
- name: WIREGUARD_ENDPOINT_PORT
|
|
value: "51820"
|
|
- name: DOT
|
|
value: "off"
|
|
- name: DNS_UPSTREAM_RESOLVER_TYPE
|
|
value: "plain"
|
|
- name: DNS_UPSTREAM_PLAIN_ADDRESSES
|
|
value: "10.43.0.10:53"
|
|
- name: HEALTH_TARGET_ADDRESS
|
|
value: "api.protonvpn.ch:443,account.proton.me:443"
|
|
- name: HEALTH_ICMP_TARGET_IPS
|
|
value: "10.2.0.1"
|
|
- name: FIREWALL_OUTBOUND_SUBNETS
|
|
value: 10.42.0.0/16,10.43.0.0/16
|
|
ports:
|
|
- containerPort: 8888
|
|
name: proxy
|
|
resources:
|
|
requests:
|
|
cpu: 50m
|
|
memory: 128Mi
|
|
limits:
|
|
cpu: 200m
|
|
memory: 512Mi
|
|
volumeMounts:
|
|
- mountPath: /tmp/gluetun
|
|
name: gluetun-data
|
|
- name: portforward-helper
|
|
image: alpine:latest
|
|
imagePullPolicy: Always
|
|
env:
|
|
- name: COORDINATOR_URL
|
|
value: "https://fornax.neuralplatform.ai"
|
|
- name: WORKER_ID
|
|
value: "WORKER_ID"
|
|
command:
|
|
- sh
|
|
- -c
|
|
- |
|
|
until apk add -q curl 2>/dev/null; do sleep 5; done
|
|
echo "Watching /tmp/gluetun/forwarded_port for assigned port..."
|
|
TTL=300
|
|
while true; do
|
|
if [ -f /tmp/gluetun/forwarded_port ]; then
|
|
PORT=$(cat /tmp/gluetun/forwarded_port)
|
|
if [ -n "$PORT" ] && [ "$PORT" != "0" ]; then
|
|
echo "$(date): Forwarded port: $PORT - updating qBittorrent"
|
|
curl -s -c /tmp/qbt.txt -X POST http://localhost:8080/api/v2/auth/login \
|
|
-d "username=admin&password=adminadmin" >/dev/null 2>&1
|
|
curl -s -b /tmp/qbt.txt -X POST http://localhost:8080/api/v2/app/setPreferences \
|
|
-d "json={\"listen_port\":$PORT,\"random_port\":false}" >/dev/null 2>&1
|
|
echo "$(date): qBittorrent listen port set to $PORT"
|
|
# Notify coordinator of port lease
|
|
if [ -n "$COORDINATOR_URL" ] && [ -n "$WORKER_ID" ]; then
|
|
curl -s -X POST "$COORDINATOR_URL/api/v2/workers/$WORKER_ID/port-lease" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"port\": $PORT, \"ttlSeconds\": $TTL}" >/dev/null 2>&1 || true
|
|
echo "$(date): Coordinator notified of port $PORT (TTL: ${TTL}s)"
|
|
fi
|
|
else
|
|
echo "$(date): Port file empty, waiting..."
|
|
fi
|
|
else
|
|
echo "$(date): Waiting for gluetun to write port file..."
|
|
fi
|
|
sleep 45
|
|
done
|
|
resources:
|
|
requests:
|
|
cpu: 10m
|
|
memory: 32Mi
|
|
limits:
|
|
cpu: 50m
|
|
memory: 96Mi
|
|
volumeMounts:
|
|
- mountPath: /tmp/gluetun
|
|
name: gluetun-data
|
|
- name: qbittorrent
|
|
image: lscr.io/linuxserver/qbittorrent:latest
|
|
imagePullPolicy: Always
|
|
env:
|
|
- name: PUID
|
|
value: "1000"
|
|
- name: PGID
|
|
value: "1000"
|
|
- name: TZ
|
|
value: America/Chicago
|
|
- name: WEBUI_PORT
|
|
value: "8080"
|
|
ports:
|
|
- containerPort: 8080
|
|
name: webui
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 256Mi
|
|
limits:
|
|
cpu: 500m
|
|
memory: 1Gi
|
|
volumeMounts:
|
|
- mountPath: /config
|
|
name: config
|
|
- mountPath: /media
|
|
name: media
|
|
volumes:
|
|
- name: gluetun-data
|
|
emptyDir: {}
|
|
- name: config
|
|
persistentVolumeClaim:
|
|
claimName: fornax-worker-WORKER_ID-config
|
|
- name: media
|
|
persistentVolumeClaim:
|
|
claimName: media-data
|