Commit b3dee02d authored by nimrod's avatar nimrod
Browse files

Merge branch 'docker-snapshots'

parents 56201092 1aba2885
Loading
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
#!/bin/sh
set -eu

# Cleanup of snapshots, added as trap so it's always executed even in case of a
# failure or ctrl+c.
cleanup () {
    btrfs subvolume delete "$snapshot"
}

usage () {
    echo "Usage: $(basename "$0") DESTINATION" >&2
    exit 1
}

get_mountpoint () {
    df --output=target "$1" | tail +2
}

get_snapshot () {
    name="$1"
    mountpoint="$(docker volume inspect --format '{{ .Mountpoint }}' "$name" )"
    snapshot="$(dirname "$mountpoint")/snapshot)"
    echo "$snapshot"
}

if [ "$#" -ne 1 ]
then
    usage
elif [ ! -d "$1" ]
then
    echo "Destinaton $1 not found or is not a directory." >&2
    exit 1
elif [ "$(id -u)" -ne 0 ]
then
    echo "This program must run as root." >&2
    exit 1
elif ! command -v btrfs >/dev/null
then
    echo 'btrfs-progs must be installed.' >&2
    exit 1
elif ! docker info --format '{{ .ServerVersion }}' >/dev/null
then
    echo 'Docker must be installed and running.' >&2
    exit 1
elif ! df --type=btrfs /var/lib/docker/volumes >/dev/null
then
    echo "Docker volumes are not on a btrfs filesystem." >&2
    exit 1
elif ! df --type=btrfs "$1" >/dev/null
then
    echo "Destination $1 is not on a btrfs filesystem." >&2
    exit 1
elif [ "$(df --output=target /var/lib/docker/volumes)" != "$(df --output=target "$1")" ]
then
    echo "The destination $1 is not on the same btrfs volume as the Docker volumes." >&2
    exit 1
elif [ -z "$(docker volume ls --filter label=snapshot=true --format '{{ .Name }}')" ]
then
    echo "No Docker volumes marked for backup, exiting." >&2
    exit 1
fi

dest="$1"
root_volume="$(get_mountpoint /var/lib/docker/volumes)"
snapshot="$(mktemp --dry-run "--tmpdir=$root_volume")"
trap 'cleanup' INT QUIT EXIT TERM
btrfs subvolume snapshot "$root_volume" "$snapshot"

for name in $(docker volume ls --filter label=snapshot=true --format '{{ .Name }}')
do
    echo "Backing up $name."
    mountpoint="$(docker volume inspect --format '{{ .Mountpoint }}' "$name")"
    src="$snapshot/${mountpoint#$root_volume/}"
    # shellcheck disable=SC2115
    [ ! -e "$dest/$name" ] || rm -rf "$dest/$name"
    cp --archive --force --reflink=always "$src" "$dest/$name"
done
+9 −0
Original line number Diff line number Diff line
# vim: filetype=systemd
[Unit]
Description=Docker volume backup (dvb)
ConditionACPower=true
After=local-fs.target

[Service]
Type=exec
ExecStart=dvb /var/backups/docker-volumes
+10 −0
Original line number Diff line number Diff line
# vim: filetype=systemd
[Unit]
Description=Docker volume backup (dvb)

[Timer]
OnCalendar=weekly
RandomizedDelaySec=21600

[Install]
WantedBy=multi-user.target
+4 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
      {{ (ansible_facts.mounts|selectattr("device", "equalto", device)|first)["mount"] }}
    # yamllint enable rule:line-length
  tags: [scrub]
  notify:
    - Systemd daemon reload

- name: Enable btrfs scrub timers
  ansible.builtin.systemd:
@@ -46,6 +48,8 @@
    mode: 0o0644
    src: btrfs_check.{{ item }}.j2
  vars: *vars
  notify:
    - Systemd daemon reload

- name: Enable the btrfs check timers
  ansible.builtin.systemd:
+33 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
    mode: 0o0644
  notify:
    - Systemd daemon reload
    - Restart Docker

- name: Allow access from the toolbox container
  ansible.builtin.copy:
@@ -54,3 +55,35 @@
    direction: in
    interface: docker0
    rule: allow

- name: Create the Docker volume backup destination directory
  ansible.builtin.file:
    group: backup
    mode: 0o0750
    owner: root
    path: /var/backups/docker-volumes
    state: directory

- name: Copy the Docker volume backup script
  ansible.builtin.copy:
    dest: /usr/local/bin/
    mode: preserve
    src: dvb

- name: Copy the Docker volume backup service and timer
  loop:
    - service
    - timer
  ansible.builtin.copy:
    dest: /etc/systemd/system/dvb.{{ item }}
    mode: 0o0644
    src: dvb.{{ item }}
  notify:
    - Systemd daemon reload

- name: Enable the Docker volume backup timer
  ansible.builtin.systemd:
    enabled: true
    name: dvb.timer
  notify:
    - Systemd daemon reload
Loading