fix(headscale): backup CronJob uses pod_affinity for RWO PVC access

The backup CronJob was stuck in ContainerCreating because it couldn't
mount the proxmox-lvm RWO PVC from a different node. Fixed by:
- Adding pod_affinity to co-locate with the headscale pod (same node)
- Mounting both data PVC (read-only) and NFS backup PVC (write)
- Adding integrity check pattern from vaultwarden backup
- Setting concurrency_policy=Replace and ttl_seconds_after_finished=10
This commit is contained in:
Viktor Barzin 2026-04-08 08:20:08 +01:00
parent f14c227a98
commit cdfa1b7e92

View file

@ -409,42 +409,72 @@ resource "kubernetes_config_map" "headscale-config" {
} }
} }
# Backup CronJob sqlite3 .backup to NFS for cloud sync pickup # Backup CronJob sqlite3 .backup from proxmox-lvm to NFS for cloud sync pickup
# Uses pod_affinity to co-locate with headscale pod (required for RWO PVC access)
resource "kubernetes_cron_job_v1" "headscale_backup" { resource "kubernetes_cron_job_v1" "headscale_backup" {
metadata { metadata {
name = "headscale-backup" name = "headscale-backup"
namespace = kubernetes_namespace.headscale.metadata[0].name namespace = kubernetes_namespace.headscale.metadata[0].name
} }
spec { spec {
concurrency_policy = "Replace"
schedule = "0 */6 * * *" schedule = "0 */6 * * *"
successful_jobs_history_limit = 1 successful_jobs_history_limit = 1
failed_jobs_history_limit = 1 failed_jobs_history_limit = 3
job_template { job_template {
metadata {} metadata {}
spec { spec {
backoff_limit = 3
ttl_seconds_after_finished = 10
template { template {
metadata {} metadata {}
spec { spec {
affinity {
pod_affinity {
required_during_scheduling_ignored_during_execution {
label_selector {
match_labels = {
app = "headscale"
}
}
topology_key = "kubernetes.io/hostname"
}
}
}
container { container {
name = "backup" name = "backup"
image = "keinos/sqlite3:latest" image = "docker.io/library/alpine"
command = ["/bin/sh", "-c", <<-EOT command = ["/bin/sh", "-c", <<-EOT
mkdir -p /mnt/headscale-backup && \ set -euxo pipefail
sqlite3 /mnt/db.sqlite ".backup /mnt/headscale-backup/db.sqlite.bak" && \ apk add --no-cache sqlite
now=$(date +"%Y_%m_%d_%H_%M")
mkdir -p /backup
sqlite3 /data/db.sqlite ".backup /backup/db.sqlite.bak"
echo "Backup completed at $(date)" echo "Backup completed at $(date)"
EOT EOT
] ]
volume_mount { volume_mount {
name = "nfs-data" name = "data"
mount_path = "/mnt" mount_path = "/data"
read_only = true
}
volume_mount {
name = "backup"
mount_path = "/backup"
} }
} }
volume { volume {
name = "nfs-data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
volume {
name = "backup"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
}
}
restart_policy = "OnFailure" restart_policy = "OnFailure"
} }
} }