FigJam Diagram: Seedbox Sync — rsync CronJob (expires 2026-04-13)
A Kubernetes CronJob that runs every 4 hours to sync completed downloads from the RapidSeedbox to the NAS staging area, then triggers Radarr and Sonarr to import the new content.
0 */4 * * * (every 4 hours)media--partial for byte-level resume on interrupted transfers| Resource | Kind | Details |
|---|---|---|
seedbox-sync-script |
ConfigMap | sync.sh inline script |
seedbox-sync |
CronJob | 0 */4 * * *, Forbid concurrency |
Never commit these to git. Create out-of-band:
kubectl create secret generic seedbox-ssh -n media \
--from-literal=SSH_HOST=45.128.27.65 \
--from-literal=SSH_PORT=2222 \
--from-literal=SSH_USER=<username> \
--from-literal=SSH_PASS=<password>
The arr-api-keys secret must also exist in the media namespace (consumed by the sync container for Radarr/Sonarr API calls):
kubectl create secret generic arr-api-keys -n media \
--from-literal=RADARR_API_KEY=<key> \
--from-literal=SONARR_API_KEY=<key>
Legacy: A
seedbox-sftpsecret (rclone SFTP format) still exists in the namespace but is no longer used.
Runs as root (runAsUser: 0) to install rsync, sshpass, and openssh-client from Alpine apk, then copies binaries and shared libraries to an emptyDir /tools volume. Also writes a minimal /etc/passwd entry for svc-rclone (UID 10012) so SSH can resolve the current user.
This pattern avoids building a custom image with pre-baked tools.
Runs as svc-rclone (UID 10012, GID 10000) — the NAS service account with write access to the full media tree. Uses the binaries from /tools and runs sync.sh from the ConfigMap.
| Flag | Purpose |
|---|---|
--partial |
Keep partially transferred files for resume |
--partial-dir=.rsync-partial |
Store partials in hidden dir (prevents arr apps importing incomplete files) |
--compress |
Compress during transfer |
--bwlimit=512000 |
Limit to ~500 MiB/s (half of 2Gbps home link) |
--timeout=300 |
Drop stalled connections after 5 minutes |
--chmod=Dg+w,Fg+r |
Ensure media-services group (GID 10000) can read/write |
--exclude='.incomplete/' |
Skip in-progress downloads |
--exclude='*.part' |
Skip partial files |
| Exit Code | Meaning | Action |
|---|---|---|
| 0 | Success | Trigger Radarr + Sonarr scans |
| 23 | Partial transfer (some files skipped) | Treated as success — will retry next run |
| 24 | Vanished source files (seedbox deleted) | Treated as success |
| Other | Transfer error | Job fails, Kubernetes retries (backoffLimit: 3) |
| Container Path | NAS Subpath | NFS PVC |
|---|---|---|
/media |
(root) |
rclone-nfs-pvc |
/media/staging/ |
staging/ |
Rsync destination |
NAS NFS export: 192.168.30.10:/volume1/media — see Storage Architecture
| Setting | Value |
|---|---|
| Schedule | 0 */4 * * * (00:00, 04:00, 08:00, ...) |
| Concurrency | Forbid — no overlap |
| backoffLimit | 3 |
| activeDeadlineSeconds | None — initial syncs can be 200+ GiB at ~3 MiB/s; rsync --partial handles interrupts |
| successfulJobsHistoryLimit | 3 |
| failedJobsHistoryLimit | 3 |
No Prometheus metrics. Monitor via:
kubectl logs -n media -l app.kubernetes.io/name=seedbox-sync --tail=50| Service | Role |
|---|---|
| Radarr | Receives DownloadedMoviesScan trigger after sync |
| Sonarr | Receives DownloadedEpisodesScan trigger after sync |
| qBittorrent | Downloads torrents to seedbox; this job syncs the results |
| Storage Architecture | NFS PV layout and NAS service accounts |
kubernetes/apps/media/rclone-sync.yaml