a73x

deploy/server/backup-pull.sh

Ref:   Size: 1.6 KiB   History

#!/usr/bin/env bash
# Off-node half of the eitri-server backup: copy the nightly sqlite backups out
# of the PVC to this machine. Run from cron on a box with kubectl access; the
# PVC is local-path on a single node, so an off-node copy is the only thing that
# survives losing that node.
#   DEST defaults to ~/eitri-backups; override: DEST=/mnt/backups ./backup-pull.sh
#
# The server image is distroless (no tar/shell), so `kubectl cp` against the
# server pod cannot work. Instead we run a short-lived alpine helper pinned to
# the same node, mounting the same PVC (local-path RWO permits co-mounting on
# one node), and stream the backups dir out through it.
set -euo pipefail
DEST="${DEST:-$HOME/eitri-backups}"
NS=eitri
POD=eitri-backup-pull
mkdir -p "$DEST"

cleanup() { kubectl -n "$NS" delete pod "$POD" --ignore-not-found --wait=false >/dev/null 2>&1 || true; }
trap cleanup EXIT

kubectl -n "$NS" delete pod "$POD" --ignore-not-found >/dev/null 2>&1 || true
kubectl -n "$NS" run "$POD" --image=alpine:3.20 --restart=Never \
  --overrides='{"spec":{"nodeSelector":{"kubernetes.io/hostname":"vnic-1"},"containers":[{"name":"'"$POD"'","image":"alpine:3.20","command":["sleep","3600"],"volumeMounts":[{"name":"data","mountPath":"/data","readOnly":true}]}],"volumes":[{"name":"data","persistentVolumeClaim":{"claimName":"eitri-server-data"}}]}}' \
  >/dev/null
kubectl -n "$NS" wait --for=condition=Ready "pod/$POD" --timeout=120s >/dev/null

kubectl -n "$NS" exec "$POD" -- tar cf - -C /data backups | tar xf - -C "$DEST"
find "$DEST" -name 'eitri-*.db' -mtime +60 -delete
echo "backup-pull: $DEST/backups"