Adds restic role to create an automatic daily backup

This commit is contained in:
Maximilian Kratz 2023-02-11 15:59:19 +01:00
parent a9782b5fd7
commit 0b0b6f2123
8 changed files with 199 additions and 0 deletions

2
.gitignore vendored
View File

@ -16,3 +16,5 @@ vars/minio.yml
vars/woodpecker_production.yml
vars/woodpecker_staging.yml
vars/backup.yml

View File

@ -19,6 +19,8 @@ Automation to create/configure the infrastructure for all services related to [f
- Replace the dummy values with the real ones (values are only available after the manual creation of an OAuth2 app)
- Copy `vars/minio.yml.example` to `vars/minio.yml`
- Replace the dummy values with the real ones
- Copy `vars/backup.yml.example` to `vars/backup.yml`
- Replace the dummy values with the real ones
## Terraform

8
backup.yaml Normal file
View File

@ -0,0 +1,8 @@
---
- name: Check SSH port
import_playbook: ssh.yaml
- name: Deploy backup
hosts: production
roles:
- restic
become: true

View File

@ -7,3 +7,5 @@
import_playbook: forgejo-staging.yaml
- name: Forgejo production
import_playbook: forgejo-prod.yaml
- name: Backup
import_playbook: backup.yaml

View File

@ -0,0 +1,75 @@
---
- name: Include backup vars
ansible.builtin.include_vars:
file: backup.yml
name: backup_config
- name: Install restic dependencies
ansible.builtin.apt:
name:
- fuse
- bzip2
- pigz
state: present
- name: Download restic
ansible.builtin.get_url:
url: "https://github.com/restic/restic/releases/download/v{{ backup_config.restic_version }}/restic_{{ backup_config.restic_version }}_linux_amd64.bz2"
dest: "/tmp/restic_{{ backup_config.restic_version }}_linux_amd64.bz2"
- name: Extract restic
command: "bzip2 -d /tmp/restic_{{ backup_config.restic_version }}_linux_amd64.bz2"
args:
creates: "/tmp/restic_{{ backup_config.restic_version }}_linux_amd64"
- name: Create restic directory
ansible.builtin.file:
path: /opt/restic
state: directory
mode: '0755'
- name: Install restic
ansible.builtin.copy:
remote_src: true
src: "/tmp/restic_{{ backup_config.restic_version }}_linux_amd64"
dest: "/opt/restic/restic"
mode: 0755
- name: Remove downloaded file
ansible.builtin.file:
path: "/tmp/restic_{{ backup_config.restic_version }}_linux_amd64"
state: absent
- name: Copy scripts
ansible.builtin.template:
src: "{{ item }}.j2"
dest: /opt/restic/{{ item }}
mode: 0755
loop:
- backup.sh
- restore.sh
- name: Create log folder
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: 0644
loop:
- /var/log/restic
- name: Create empty log file
ansible.builtin.copy:
content: ""
dest: /var/log/restic/backup.log
force: false
group: sys
owner: root
mode: 0644
- name: Add daily cronjob for backups
ansible.builtin.cron:
name: "restic backup"
user: root
minute: "0"
hour: "4"
job: "/opt/restic/backup.sh >> /var/log/restic/backup.log"

View File

@ -0,0 +1,60 @@
#!/bin/bash
set -e
# Set crypto passphrase for encryption
export AWS_ACCESS_KEY_ID={{ backup_config.access_key }}
export AWS_SECRET_ACCESS_KEY={{ backup_config.secret_key }}
export RESTIC_PASSWORD={{ backup_config.restic_key }}
export RESTIC_REPOSITORY={{ backup_config.restic_target }}
restic="/opt/restic/restic"
dir_prefix="/backup/dbs"
# Write beginning date to backup log
echo 'Backup date' $(date)'.'
echo ' '
# Create database dump folders
mkdir -p $dir_prefix/forgejo/postgres
mkdir -p $dir_prefix/woodpecker/postgres
# Remove previous dumps
rm -f $dir_prefix/forgejo/postgres/dump.sql
rm -f $dir_prefix/woodpecker/postgres/dump.sql
# Dump databases
docker exec -t forgejo_db_1 pg_dumpall -c -U forgejo > $dir_prefix/forgejo/postgres/dump.sql
docker exec -t woodpecker_woodpecker-database_1 pg_dumpall -c -U postgres > $dir_prefix/woodpecker/postgres/dump.sql
# Check if repo must be initialized
if $restic cat config >/dev/null 2>&1; then
echo 'Repo was already initialized'
else
echo 'Repo not initialized.'
$restic init
fi
# Unlock lock of repo
$restic unlock
# Do a backup
$restic --verbose backup /var/log /var/lib/docker/volumes /srv /backup
$restic --verbose backup /etc /opt
$restic --verbose backup /home /root
# Clean up older backups
$restic --verbose forget --keep-last 5 --keep-daily 14 --keep-weekly 4 --keep-monthly 24
# Data clean up
$restic --verbose prune
# Write end to log file
echo ' '
echo '============================'
echo ' '
# Unset ENVs
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset RESTIC_PASSWORD
unset RESTIC_REPOSITORY

View File

@ -0,0 +1,39 @@
#!/bin/bash
set -e
# Set crypto passphrase for encryption
export AWS_ACCESS_KEY_ID={{ backup_config.access_key }}
export AWS_SECRET_ACCESS_KEY={{ backup_config.secret_key }}
export RESTIC_PASSWORD={{ backup_config.restic_key }}
export RESTIC_REPOSITORY={{ backup_config.restic_target }}
restic="/opt/restic/restic"
dir_prefix="/backup/dbs"
# Write beginning date to backup log
echo 'Restore date' $(date)'.'
echo ' '
# Unlock lock of repo
$restic unlock
# Show snapshots
$restic snapshots
# Restore the latest backup to /tmp/restic/restore
mkdir -p /tmp/restic/restore
# One of each paths is enough to match filter
$restic --verbose restore latest --target /tmp/restic/restore --path "/var/log" --host "{{prod_url}}"
$restic --verbose restore latest --target /tmp/restic/restore --path "/etc" --host "{{prod_url}}"
$restic --verbose restore latest --target /tmp/restic/restore --path "/root" --host "{{prod_url}}"
# Write end to log file
echo ' '
echo '============================'
echo ' '
# Unset ENVs
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset RESTIC_PASSWORD
unset RESTIC_REPOSITORY

11
vars/backup.yml.example Normal file
View File

@ -0,0 +1,11 @@
---
#
# Backup configuration
#
restic_version: "0.15.1"
restic_target: "s3:https://s3.TODO.com/BUCKET"
restic_key: "TODO"
access_key: "TODO"
secret_key: "TODO"