feat: add workaround for qBittorrent 5.2.0 stale lock issue with init container
Some checks failed
validate / lint (push) Failing after 1s
Some checks failed
validate / lint (push) Failing after 1s
This commit is contained in:
parent
e757850c3b
commit
663337f818
@ -159,6 +159,18 @@ real.
|
|||||||
table, ACCEPT + established/related return inserted into the
|
table, ACCEPT + established/related return inserted into the
|
||||||
`PIA-VLAN50` chain (not `FORWARD` directly), and source-NAT/MASQUERADE
|
`PIA-VLAN50` chain (not `FORWARD` directly), and source-NAT/MASQUERADE
|
||||||
scoped to `10.10.50.0/24` on `pia-wg` only.
|
scoped to `10.10.50.0/24` on `pia-wg` only.
|
||||||
|
- Clamps TCP MSS on the `pia-wg` forward path (`pia_mss_clamp_enabled:
|
||||||
|
true`, `iptables -t mangle ... TCPMSS --clamp-mss-to-pmtu`, scoped to
|
||||||
|
SYN packets sourced from `10.10.50.0/24` outbound on `pia-wg` only, in
|
||||||
|
`PostUp`/`PreDown` alongside the rules above). Confirmed needed live
|
||||||
|
(2026-08-25), not enabled speculatively: a real download hung with a
|
||||||
|
TLS read timeout on the larger handshake response while small
|
||||||
|
requests worked fine, and a direct `ping -M do -s 1450` test from a
|
||||||
|
VLAN 50 pod confirmed the real path MTU is `pia-wg`'s `1420` (the ICMP
|
||||||
|
"Frag needed" reply arrives correctly from minisforum itself — our own
|
||||||
|
side relays PMTU discovery fine, so the black hole is further out, on
|
||||||
|
PIA's network or the remote server's own path, where clamping the MSS
|
||||||
|
up front avoids needing that ICMP round-trip at all).
|
||||||
- Installs an observability-only health check (`pia-gateway-healthcheck
|
- Installs an observability-only health check (`pia-gateway-healthcheck
|
||||||
.timer`, every `pia_healthcheck_interval_sec`) that logs interface,
|
.timer`, every `pia_healthcheck_interval_sec`) that logs interface,
|
||||||
handshake age, rule/route, and firewall-policy state to the journal. It
|
handshake age, rule/route, and firewall-policy state to the journal. It
|
||||||
@ -171,9 +183,6 @@ real.
|
|||||||
every run — `tasks/assert-baseline.yaml` fails loudly if that's already
|
every run — `tasks/assert-baseline.yaml` fails loudly if that's already
|
||||||
wrong).
|
wrong).
|
||||||
- Does not enable IPv6 forwarding or any IPv6 handling for VLAN 50.
|
- Does not enable IPv6 forwarding or any IPv6 handling for VLAN 50.
|
||||||
- Does not enable MSS clamping (`pia_mss_clamp_enabled: false` by
|
|
||||||
default) — flip only after Phase 5 canary MTU testing shows it's
|
|
||||||
actually needed.
|
|
||||||
- Does not modify `ansible/roles/wireguard` (the separate `wg0` home-VPN
|
- Does not modify `ansible/roles/wireguard` (the separate `wg0` home-VPN
|
||||||
server role) or its interface.
|
server role) or its interface.
|
||||||
|
|
||||||
|
|||||||
@ -103,12 +103,21 @@ pia_lan_interface: enp1s0
|
|||||||
# minisforum would route toward that source itself.
|
# minisforum would route toward that source itself.
|
||||||
pia_rp_filter_mode: 2
|
pia_rp_filter_mode: 2
|
||||||
|
|
||||||
# MSS clamping on the pia-wg forward path — OFF by default. plan.md is
|
# MSS clamping on the pia-wg forward path — ON. Confirmed needed live
|
||||||
# explicit: do not guess this. Flip to true only after Phase 5 canary
|
# (2026-08-25), not guessed: a real JDownloader download to
|
||||||
# MTU/path-MTU testing (large-packet ping with DF set, across the
|
# sbs237.sbsf.tech hung indefinitely (TLS read timeout waiting for the
|
||||||
# VLAN 50 -> Flint -> minisforum -> pia-wg path) shows fragmentation or
|
# server's handshake response — small requests like a CDN version check
|
||||||
# black-holing that clamping fixes.
|
# worked fine, only the larger TLS response never arrived). Verified
|
||||||
pia_mss_clamp_enabled: false
|
# with the exact test plan.md called for before flipping this: `ping -M
|
||||||
|
# do -s 1450 -c 3 1.1.1.1` from a VLAN 50 pod returned `From 10.10.40.53
|
||||||
|
# Frag needed and DF set (mtu = 1420)` — our own PMTU discovery between
|
||||||
|
# the pod and minisforum works correctly, which means the black hole is
|
||||||
|
# further out (PIA's network or the remote server's own path), not on
|
||||||
|
# our side — exactly the class of problem MSS clamping fixes by
|
||||||
|
# avoiding the need for that ICMP round-trip at all, clamping the MSS
|
||||||
|
# at the TCP handshake instead of relying on mid-connection PMTU
|
||||||
|
# discovery that something further along the path may not relay back.
|
||||||
|
pia_mss_clamp_enabled: true
|
||||||
|
|
||||||
# Health check cadence and thresholds. The check only observes and logs —
|
# Health check cadence and thresholds. The check only observes and logs —
|
||||||
# see tasks/healthcheck.yaml — it must never itself open the kill switch.
|
# see tasks/healthcheck.yaml — it must never itself open the kill switch.
|
||||||
|
|||||||
@ -167,6 +167,48 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: config
|
- name: config
|
||||||
mountPath: /config
|
mountPath: /config
|
||||||
|
# Works around a real upstream qBittorrent 5.2.0 bug
|
||||||
|
# (qbittorrent/qBittorrent#24164, confirmed against the actual
|
||||||
|
# issue thread, not assumed): 5.2.0 switched its single-instance
|
||||||
|
# lock from the old fcntl-based QtLockedFile to Qt's QLockFile,
|
||||||
|
# which embeds a PID + hostname. If the previous shutdown wasn't
|
||||||
|
# clean, 5.2.0 can't parse/verify the stale lock, assumes another
|
||||||
|
# instance holds it, tries to hand off over the (also stale)
|
||||||
|
# ipc-socket, that fails too, and it exits immediately — then
|
||||||
|
# restarts, hits the same stale lock, and repeats forever (a
|
||||||
|
# crash loop, not a slow startup — confirmed live 2026-08-25 from
|
||||||
|
# this exact pod: PID incrementing every ~1-2s, 80% CPU, WebUI
|
||||||
|
# never listening). Every Kubernetes pod restart gets a new
|
||||||
|
# hostname (the pod name), which is exactly the kind of
|
||||||
|
# environment where the lock's embedded hostname can't be
|
||||||
|
# trusted to match — plausibly why this surfaces more here than
|
||||||
|
# on a stable bare-metal/VM host.
|
||||||
|
#
|
||||||
|
# Unconditionally clearing the lock on every start is safe
|
||||||
|
# specifically in this Deployment: strategy: Recreate plus a
|
||||||
|
# single replica plus a ReadWriteOnce PVC together guarantee
|
||||||
|
# Kubernetes itself never runs two instances against this config
|
||||||
|
# concurrently — by the time this init container runs, any
|
||||||
|
# previous instance is already fully terminated. So there is no
|
||||||
|
# scenario here where the lock could be legitimately held by a
|
||||||
|
# still-running peer.
|
||||||
|
- name: qbittorrent-clear-stale-lock
|
||||||
|
image: nicolaka/netshoot:v0.11
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -eu
|
||||||
|
rm -fv /config/qBittorrent/lockfile /config/qBittorrent/ipc-socket
|
||||||
|
echo "stale lock/IPC state cleared (if any was present)"
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /config
|
||||||
containers:
|
containers:
|
||||||
- name: qbittorrent
|
- name: qbittorrent
|
||||||
image: lscr.io/linuxserver/qbittorrent:5.2.0
|
image: lscr.io/linuxserver/qbittorrent:5.2.0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user