restic: Add stack

Adapted from cloudserve-infrastructure, implements a backup stack using
restic. The actual backups have to be implemented by individual other
roles but this sets up initialization, pruning and checking of a repository.
This commit is contained in:
Marty Oehme 2025-07-17 21:38:35 +02:00
parent 93876315ca
commit 86d49a756b
Signed by: Marty
GPG key ID: 4E535BC19C61886E
7 changed files with 146 additions and 0 deletions

View file

@ -54,3 +54,8 @@
ansible.builtin.import_role:
name: grocy
tags: grocy
- name: Set up Restic stack
ansible.builtin.import_role:
name: restic
tags: restic

49
roles/restic/README.md Normal file
View file

@ -0,0 +1,49 @@
# restic
Backup maintenance stack.
Takes care of regularly pruning the backup repository and checking its integrity.
Currently only supports S3 as a backend.
## Defaults
```yaml
restic_timezone: US/Chicago
```
The timezone to be used for the cronjob.
```yaml
restic_version: latest
```
The docker image version to be used in stack creation.
```yaml
restic_repo: s3.eu-central-1.wasabisys.com/myrepo
restic_pass: <restic-pass>
```
The repository url and the restic repository password.
See the restic documentation for more information.
```yaml
restic_s3_key: <s3-key>
restic_s3_secret: <s3-secret>
```
The restic S3 credentials, i.e. the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
```yaml
restic_prune_cron: 0 0 4 * * *
restic_forget_args: --prune --keep-last 14 --keep-daily 2 --keep-weekly 2
```
The default prune and forget cronjob schedule and arguments: Prune the repository every day at 4:00 AM and keep the last 14 snapshots, 2 daily snapshots and 2 weekly snapshots.
```yaml
restic_check_cron: 0 15 5 * * *
restic_check_args: --read-data-subset=5%
```
The default check cronjob schedule and arguments: Check the repository integrity every day at 5:15 AM and in addition to structural checks, read 5 randomly chosen % for a data integrity check.

View file

@ -0,0 +1,24 @@
---
# inherited from global
restic_enable: true
restic_tz: "{{ timezone | default('America/Chicago') }}"
restic_version: latest
restic_auto_init: true
restic_prune_cron: 0 0 4 * * * # go-cron starts with seconds in first pos
restic_forget_args: --prune --keep-last 14 --keep-daily 2 --keep-weekly 2
restic_check_cron: 0 30 4 * * SUN
restic_check_args: --read-data-subset=15%
restic_repo: /opt/stack_restic_backup
restic_pass: my-restic-pass
restic_s3_key:
restic_s3_secret:
# S3 example
# restic_repo: s3.eu-central-1.wasabisys.com/myrepo
# restic_pass: <restic-pass>
# restic_s3_key: <s3-key>
# restic_s3_secret: <s3-secret>

View file

@ -0,0 +1,7 @@
---
galaxy_info:
author: Marty Oehme
description: Installs a restic-based backup maintenance stack.
license: GPL-3.0-only
min_ansible_version: "2.9"
galaxy_tags: []

View file

@ -0,0 +1,17 @@
---
- name: Create local backup directory
ansible.builtin.file:
state: directory
path: "{{ restic_repo }}"
owner: root
group: root
mode: 0770
when: restic_repo is regex('^/.+')
- name: Deploy restic to compose
community.docker.docker_compose_v2:
project_name: restic
definition: "{{ lookup('template', 'docker-compose.yaml.j2') | from_yaml }}"
remove_orphans: true
wait: true
wait_timeout: 60

View file

@ -0,0 +1,36 @@
services:
prune:
image: "mazzolino/restic:{{ restic_version }}"
hostname: docker
environment:
- "TZ={{ restic_tz }}"
- "SKIP_INIT={{ not restic_auto_init }}"
- "RUN_ON_STARTUP=true"
- "PRUNE_CRON={{ restic_prune_cron }}"
- "RESTIC_FORGET_ARGS={{ restic_forget_args }}"
- "RESTIC_REPOSITORY={{ restic_repo }}"
- "RESTIC_PASSWORD={{ restic_pass }}"
- "AWS_ACCESS_KEY_ID={{ restic_s3_key }}"
- "AWS_SECRET_ACCESS_KEY={{ restic_s3_secret }}"
{% if restic_repo is regex('^/.+') %}
volumes:
- "{{ restic_repo }}:{{ restic_repo }}"
{% endif %}
check:
image: "mazzolino/restic:{{ restic_version }}"
hostname: docker
environment:
- "TZ={{ restic_tz }}"
- "SKIP_INIT=true" # only run init on one container to avoid race cond
- "RUN_ON_STARTUP=false"
- "CHECK_CRON={{ restic_check_cron }}"
- "RESTIC_CHECK_ARGS={{ restic_check_args }}"
- "RESTIC_REPOSITORY={{ restic_repo }}"
- "RESTIC_PASSWORD={{ restic_pass }}"
- "AWS_ACCESS_KEY_ID={{ restic_s3_key }}"
- "AWS_SECRET_ACCESS_KEY={{ restic_s3_secret }}"
{% if restic_repo is regex('^/.+') %}
volumes:
- "{{ restic_repo }}:{{ restic_repo }}"
{% endif %}

View file

@ -0,0 +1,8 @@
---
stack_name: restic
stack_image: "mazzolino/restic"
stack_compose: "{{ lookup('template', 'docker-stack.yml.j2') | from_yaml }}"
backup_enable: true