Deprecate generic container volume backup/restore

Previously, all container volumes initialized via the `container-volume`
service would have local rotating backups performed by pushing `tar`
archives to the `/var/lib/backups/coreos-home-server` directory.

This proved to be a simple and effective mechanism for storing historic
volume state locally; however, the use-case for historic backup is
usually data loss, either partial (e.g. by deleting files inadvertently)
or complete (e.g. by loss of disk), which is likely better mitigated by
more concrete mechanisms of retention.

In addition, this need to store historic volume state locally, in its
totality, proved to be a barrier for performing partial backups, which
is an issue especially for larger volumes.

This commit deprecates this simple, generic volume backup/restore
mechanism, and instead has us rely directly on Rclone reading from the
volume in question.
This commit is contained in:
Alex Palaistras 2024-04-01 13:41:32 +01:00
parent 3cdf8b8c98
commit fe30677a46
13 changed files with 33 additions and 122 deletions

View File

@ -1,52 +0,0 @@
#!/usr/bin/env bash
#
# Archive all files in source directory into destination directory.
set -euo pipefail
# Parse command-line arguments.
unset SRCDIR DESTDIR BASENAME
while getopts 's:d:n:' arg; do
case "${arg}" in
s) SRCDIR="${OPTARG}" ;;
d) DESTDIR="${OPTARG}" ;;
n) BASENAME="${OPTARG}-" ;;
*) echo "Unknown argument '${arg}' given. Exiting." >&2 && exit 1 ;;
esac
done
# Check and return true if source files are newer than any archive already created.
function archive-should-update() {
local latest="${DESTDIR}/${BASENAME}latest.tar.gz"
if ! test -e "${latest}"; then
return 0
elif test "$(find "${SRCDIR}" -type f -newer "${latest}" -print -quit | wc -l)" -gt 0; then
return 0
fi
return 1
}
# Create compressed archive for source path into destination path for pre-defined, date-based name.
function archive-create() {
local name="${BASENAME}$(date +%w%H)"
# Create uncompressed archive for source path and compress separately to ensure minimal blocking.
tar --verbose --create --file "${DESTDIR}/${name}.tar" --directory "${SRCDIR}" .
gzip --force "${DESTDIR}/${name}.tar"
# Point the latest archive to a "special" name for future use.
(cd /backup && ln --symbolic --force "${name}.tar.gz" "${BASENAME}latest.tar.gz")
}
# Entry-point for script. Create tar archive for source directory into destination directory, checking
# for any changes since last run, and ensuring files are archived correctly for subsequent restore.
function main() {
if archive-should-update "${SRCDIR}" "${DESTDIR}"; then
archive-create "${SRCDIR}" "${DESTDIR}"
fi
}
main "$@"

View File

@ -1,15 +0,0 @@
[Unit]
Description=Backup for Container Volume %I
[Service]
Type=oneshot
SyslogIdentifier=%N
ExecStartPre=/bin/install --mode 0700 --directory %S/backups/coreos-home-server/%i
ExecStart=/bin/podman run --replace --rm --name %p-%i --entrypoint /opt/container-volume-backup \
--volume %i:/data:z,ro \
--volume %E/coreos-home-server/base/service:/opt:z,ro \
--volume %S/backups/coreos-home-server/%i:/backup:z \
docker.io/debian:bullseye-slim -s /data -d /backup -n "%i"
[Install]
WantedBy=multi-user.target

View File

@ -1,16 +0,0 @@
[Unit]
Description=Restore from Backup for Container Volume %I
ConditionFileNotEmpty=%S/backups/coreos-home-server/%i/%i-latest.tar.gz
[Service]
Type=oneshot
SyslogIdentifier=%N
ExecStart=/bin/podman run --replace --rm --name %p-%i --entrypoint /bin/bash \
--volume %i:/data:z \
--volume %S/backups/coreos-home-server/%i:/backup:z,ro \
docker.io/debian:bullseye-slim -c \
'test -n "$(ls -A /data)" && echo "Volume %i is not empty, skipping." && exit 0; \
tar --verbose --extract --file "/backup/%i-latest.tar.gz" --directory /data'
[Install]
WantedBy=multi-user.target

View File

@ -1,7 +1,5 @@
[Unit]
Description=Container Volume for %I
Wants=container-volume-restore@%i.service container-volume-backup@%i.timer
After=container-volume-restore@%i.service
[Service]
Type=oneshot

View File

@ -37,7 +37,7 @@ RSPAMD_CONTROLLER_PASSWORD=password
# Configuration for Rclone.
RCLONE_REMOTE_TYPE=local
RCLONE_REMOTE_PATH=/data/rclone
RCLONE_REMOTE_PATH=/local
RCLONE_CRYPT_PASSWORD=3NYQAySloaAVy4CxtVkAset0mz9KDlhT
RCLONE_CRYPT_SALT=jqsQXp_MPwBPIzw69TkmSp7ScuA

View File

@ -1,3 +0,0 @@
[Unit]
Wants=rclone-push@var-lib-backups-coreos\x2dhome\x2dserver-%i.service
Before=rclone-push@var-lib-backups-coreos\x2dhome\x2dserver-%i.service

View File

@ -1,3 +0,0 @@
[Unit]
Wants=rclone-pull@var-lib-backups-coreos\x2dhome\x2dserver-%i.service
Before=rclone-pull@var-lib-backups-coreos\x2dhome\x2dserver-%i.service

View File

@ -0,0 +1,2 @@
[Unit]
Wants=rclone-push-volume@%i.timer

View File

@ -0,0 +1,15 @@
[Unit]
Description=Rclone Pull for Volume %I
Wants=[email protected] container-volume@%i.service
After=[email protected] container-volume@%i.service
[Service]
Type=oneshot
SyslogIdentifier=%N
Environment=SOURCE=crypt:%i
ExecCondition=/bin/bash -c 'test -n "$(ls --almost-all $(podman volume mount %i))"; status=$?; podman volume unmount %i; exit $status'
ExecStartPre=/bin/install --mode 0700 -d %S/backups/coreos-home-server/%i
ExecStart=/bin/podman run --rm --env-file %E/coreos-home-server/rclone/rclone.env --user root --volume %i:/mnt:z --volume %S/backups/coreos-home-server/%i:/local:z localhost/rclone:latest sync ${SOURCE} /mnt
[Install]
WantedBy=multi-user.target

View File

@ -1,15 +0,0 @@
[Unit]
Description=Rclone Pull for /%I
Wants=[email protected]
After=[email protected]
ConditionDirectoryNotEmpty=!/%I
[Service]
Type=oneshot
SyslogIdentifier=%N
Environment=SOURCE=crypt:%i
ExecStartPre=/bin/install --mode 0700 -d /%I
ExecStart=/bin/podman run --rm --env-file %E/coreos-home-server/rclone/rclone.env --user root --volume /%I:/data:z localhost/rclone:latest sync ${SOURCE} /data
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,14 @@
[Unit]
Description=Rclone Push for Volume %I
Wants=[email protected]
After=[email protected]
[Service]
Type=oneshot
SyslogIdentifier=%N
Environment=DESTINATION=crypt:%i
ExecStartPre=/bin/install --mode 0700 -d %S/backups/coreos-home-server/%i
ExecStart=/bin/podman run --rm --env-file %E/coreos-home-server/rclone/rclone.env --user root --volume %i:/mnt:z,ro --volume %S/backups/coreos-home-server/%i:/local:z localhost/rclone:latest sync /mnt ${DESTINATION}
[Install]
WantedBy=multi-user.target

View File

@ -1,5 +1,5 @@
[Unit]
Description=Scheduled Backup for Container Volume %i
Description=Scheduled Rclone Push for Volume %I
[Timer]
OnCalendar=02:00

View File

@ -1,14 +0,0 @@
[Unit]
Description=Rclone Push for /%I
Wants=[email protected]
After=[email protected]
ConditionDirectoryNotEmpty=/%I
[Service]
Type=oneshot
SyslogIdentifier=%N
Environment=DESTINATION=crypt:%i
ExecStart=/bin/podman run --rm --env-file %E/coreos-home-server/rclone/rclone.env --user root --volume /%I:/data:z localhost/rclone:latest sync /data ${DESTINATION}
[Install]
WantedBy=multi-user.target