feat(backup): Add restic backup
Restic backup creates a snapper snapshot of the root system which it then chroots into and starts a restic backup to a (wasabi) S3 bucket to. Intended to roughly follow this <https://codeberg.org/silmaril/my-restic-solution> solution to achieve restic backup of the _newest_ snapshot of my live root system.
This commit is contained in:
parent
2400bbf1af
commit
19162e2af3
6 changed files with 131 additions and 1 deletions
roles/backup
|
@ -1,2 +1,12 @@
|
|||
---
|
||||
# user_name: # required for snapper templates
|
||||
|
||||
restic_repository:
|
||||
restic_password:
|
||||
restic_s3_id:
|
||||
restic_s3_key:
|
||||
|
||||
restic_daily: 3
|
||||
restic_weekly: 2
|
||||
restic_monthly: 6
|
||||
restic_yearly: 1
|
||||
|
|
53
roles/backup/files/snapstic
Executable file
53
roles/backup/files/snapstic
Executable file
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
shopt -s expand_aliases
|
||||
|
||||
# Restic snapshot backup script
|
||||
msg() { # $1=message string $2=unit
|
||||
printf "[%s] %s\n" "${2:-snapstic}" "$1"
|
||||
}
|
||||
|
||||
config="${SNAPSTIC_RESTIC_CONFIG:-root}"
|
||||
restic_conf="/etc/restic/${config}/restic.conf"
|
||||
snapper_snapshot_dir="${SNAPSTIC_SNAPSHOT_DIR:-/.snapshots}"
|
||||
# snapper_config="${SNAPSTIC_SNAPPER_CONFIG}" # TODO: call snapper with associated conf if exists?
|
||||
|
||||
source "$restic_conf"
|
||||
|
||||
trap cleanup 1 2 3 6
|
||||
cleanup() {
|
||||
msg "unmount restic configuration"
|
||||
umount "${snap_dir}/.snapshots"
|
||||
umount "${snap_dir}/tmp"
|
||||
exit
|
||||
}
|
||||
|
||||
msg "create snapper snapshot"
|
||||
snap_num=$(snapper create --cleanup-algorithm number --description 'restic' --print-number)
|
||||
snap_dir="${snapper_snapshot_dir}/${snap_num}/snapshot"
|
||||
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
msg "no backup options selected"
|
||||
fi
|
||||
|
||||
msg "mount restic configuration to ephemeral dir"
|
||||
mount --bind "/etc/restic/${config}" "${snap_dir}/.snapshots"
|
||||
msg "mount restic cache dir"
|
||||
mount --bind "/tmp" "${snap_dir}/tmp"
|
||||
|
||||
if [[ $* == *"backup"* ]]; then
|
||||
msg "backup in chrooted $snap_dir"
|
||||
chroot "$snap_dir" /bin/bash -c '. /.snapshots/restic.conf && AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" RESTIC_REPOSITORY=$RESTIC_REPOSITORY RESTIC_PASSWORD="$RESTIC_PASSWORD" /usr/bin/restic backup --tag "snapstic" --files-from="/.snapshots/include" --exclude-file="/.snapshots/exclude" --exclude "/.snapshots" --exclude-caches --no-cache'
|
||||
fi
|
||||
|
||||
if [[ $* == *"forget"* ]]; then
|
||||
msg "forget snapshots in $snap_dir"
|
||||
chroot "$snap_dir" /bin/bash -c '. /.snapshots/restic.conf && DAILY=$DAILY WEEKLY=$WEEKLY MONTHLY=$MONTHLY YEARLY=$YEARLY AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" RESTIC_REPOSITORY=$RESTIC_REPOSITORY RESTIC_PASSWORD="$RESTIC_PASSWORD" /usr/bin/restic forget --tag "snapstic" --group-by "paths,tags" --keep-daily="${DAILY:-0}" --keep-weekly="${WEEKLY:-0}" --keep-monthly="${MONTHLY:-0}" --keep-yearly="${YEARLY:-0}" --no-cache'
|
||||
fi
|
||||
|
||||
if [[ $* == *"stats"* ]]; then
|
||||
msg "display repo stats"
|
||||
chroot "$snap_dir" /bin/bash -c '. /.snapshots/restic.conf && AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" RESTIC_REPOSITORY=$RESTIC_REPOSITORY RESTIC_PASSWORD="$RESTIC_PASSWORD" /usr/bin/restic stats --no-cache'
|
||||
fi
|
||||
|
||||
msg "done"
|
|
@ -2,4 +2,10 @@
|
|||
import_tasks: snapper.yaml
|
||||
tags:
|
||||
- btrfs
|
||||
- snapshots
|
||||
- snapper
|
||||
|
||||
- name: Set up restic backups
|
||||
import_tasks: restic.yaml
|
||||
tags:
|
||||
- btrfs
|
||||
- restic
|
||||
|
|
52
roles/backup/tasks/restic.yaml
Normal file
52
roles/backup/tasks/restic.yaml
Normal file
|
@ -0,0 +1,52 @@
|
|||
- name: Install restic
|
||||
community.general.xbps:
|
||||
name:
|
||||
- restic
|
||||
state: present
|
||||
tags: packages
|
||||
|
||||
- name: Ensure restic configuration directory exists
|
||||
ansible.builtin.file:
|
||||
dest: "/etc/restic/root"
|
||||
state: directory
|
||||
|
||||
- name: Create restic root backup configuration
|
||||
ansible.builtin.template:
|
||||
src: restic.conf.j2
|
||||
dest: "/etc/restic/root/restic.conf"
|
||||
mode: 0600
|
||||
force: true # ensure contents are always exact
|
||||
|
||||
- name: Ensure files and exclude files exist # Only change if necessary
|
||||
ansible.builtin.file:
|
||||
dest: "/etc/restic/root/{{ item }}"
|
||||
state: touch
|
||||
modification_time: preserve
|
||||
access_time: preserve
|
||||
loop:
|
||||
- include
|
||||
- exclude
|
||||
|
||||
- name: Create include files # TODO: Rename file to include?
|
||||
ansible.builtin.copy:
|
||||
content: "/"
|
||||
dest: "/etc/restic/root/include"
|
||||
force: true # ensure contents are always exact
|
||||
|
||||
- name: Install snapstic script
|
||||
ansible.builtin.copy:
|
||||
src: snapstic
|
||||
dest: "/usr/bin/snapstic"
|
||||
mode: 0744
|
||||
|
||||
- name: Ensure restic configuration directory exists
|
||||
ansible.builtin.file:
|
||||
dest: "/etc/cron.weekly"
|
||||
state: directory
|
||||
|
||||
- name: Add snapstic to weekly cronjobs
|
||||
ansible.builtin.copy:
|
||||
content: "#!/bin/sh\n\nsnapstic backup"
|
||||
dest: "/etc/cron.weekly/snapstic"
|
||||
mode: 0755
|
||||
force: true # ensure contents are always exact
|
9
roles/backup/templates/restic.conf.j2
Normal file
9
roles/backup/templates/restic.conf.j2
Normal file
|
@ -0,0 +1,9 @@
|
|||
RESTIC_REPOSITORY='{{ restic_repository }}'
|
||||
AWS_ACCESS_KEY_ID='{{ restic_s3_id }}'
|
||||
AWS_SECRET_ACCESS_KEY='{{ restic_s3_key }}'
|
||||
RESTIC_PASSWORD='{{ restic_password }}'
|
||||
RESTIC_CACHE_DIR=/var/tmp
|
||||
DAILY={{ restic_daily }}
|
||||
WEEKLY={{ restic_weekly }}
|
||||
MONTHLY={{ restic_monthly }}
|
||||
YEARLY={{ restic_yearly }}
|
Loading…
Reference in a new issue