Files
zorruno-backupdockerscript/README.md
T

158 lines
5.0 KiB
Markdown

# Zorruno Docker Backup Scripts
Modular backup scripts for Docker Compose servers such as Panda and Beaver.
Each server has its own untracked `.env` and `containers.txt`, while all script
logic remains common and can be updated through Git.
## Pipeline
`backup.sh` runs these stages in order:
1. `stages/10-containers.sh` — stop, archive, pull, start and verify projects.
2. `methods/20-rclone.sh` — copy archives to an rclone destination when enabled.
3. `methods/30-smb.sh` — copy archives to a mounted SMB share when enabled.
4. `stages/90-prune.sh` — retain the newest configured number locally.
Every stage can also be run directly. The old `docker-backup.sh` name invokes
the container archive stage, while `dockerbackup_prune.sh` invokes the local
prune stage. Use the new `backup.sh` for the complete pipeline.
## Requirements
- Bash 4 or later
- Docker with `docker compose`, or legacy `docker-compose`
- GNU `tar` with zstd support
- `flock`
- `rclone` only when the rclone method is enabled
- `rsync` and `mountpoint` only when the SMB method is enabled
The account running the scripts must be allowed to control Docker and read all
files under `/dockervolumes`.
## Installation on Beaver
```bash
sudo git clone https://home.fox.co.nz/gitea/zorruno/zorruno-backupdockerscript.git /backupdockerscripts
cd /backupdockerscripts
sudo cp .env.example .env
sudo cp containers.txt containers.local.txt
sudo chmod 600 .env
sudo chmod +x backup.sh docker-backup.sh dockerbackup_prune.sh stages/*.sh methods/*.sh
```
Edit `.env`. Beaver's Docker source is already represented by:
```bash
SOURCE_BASE_DIR="/dockervolumes"
BACKUP_HOSTNAME="beaver"
```
Choose and create a local staging path for `BACKUP_ROOT`. `/dockerbackups` is
the default, but it should be on a filesystem with enough free space to hold
at least `KEEP_COUNT` copies of every listed project.
Edit Beaver's untracked `containers.local.txt`. Each active line can be either a running
container name or a directory name beneath `/dockervolumes`. Blank lines and
text after `#` are ignored. If several entries resolve to the same Compose
project directory, that project is backed up only once. Keeping this host-local
file out of Git prevents a pull on Panda or Beaver from replacing its list.
## Configuration
Copy `.env.example` to `.env`; `.env` is ignored by Git. Important values:
| Variable | Purpose |
|---|---|
| `SOURCE_BASE_DIR` | Parent of Compose project directories |
| `BACKUP_ROOT` | Local archive staging and retention tree |
| `CONTAINERS_FILE` | Absolute path, or path relative to this repository |
| `BACKUP_HOSTNAME` | Host folder/name embedded in archive filenames |
| `BACKUP_METHODS` | Ordered method names, default `rclone smb` |
| `ZSTD_EXTRA_OPTS` | Options passed to `zstd`, default `-T0 -12` |
| `KEEP_COUNT` | Local archives retained per Compose project |
| `PULL_IMAGES` | Pull images before restarting (`1` or `0`) |
### Rclone
```bash
RCLONE_ENABLED=1
RCLONE_REMOTE="gdrive:dockerbackups"
```
Archives are copied beneath `<remote>/<BACKUP_HOSTNAME>/`. The method uses
`rclone copy`, so it does not delete older destination files. Set
`RCLONE_HOST_SUBDIR=0` when `RCLONE_REMOTE` already names the final host-specific
destination; otherwise the host name is appended automatically.
### SMB
Mount the SMB share through `/etc/fstab` or a systemd mount unit; do not put SMB
credentials in this repository. Then configure:
```bash
SMB_ENABLED=1
SMB_MOUNT="/mnt/dockerbackups"
SMB_HOST_SUBDIR=1
```
The script refuses to copy unless `SMB_MOUNT` is an actual mount point. This
prevents a failed network mount from silently filling the server's root disk.
## Running
Run the complete pipeline:
```bash
sudo /backupdockerscripts/backup.sh
```
Preview all stages without stopping containers, copying, or deleting:
```bash
sudo /backupdockerscripts/backup.sh --dry-run
```
Run individual parts:
```bash
sudo stages/10-containers.sh --dry-run
sudo methods/20-rclone.sh --dry-run --force
sudo methods/30-smb.sh --dry-run --force
sudo stages/90-prune.sh --dry-run
```
`--force` runs a transfer method even when its `*_ENABLED` value is false. It
still requires the method's destination to be configured and available.
## Adding another backup method
Add an executable script named `methods/NN-name.sh`, for example
`methods/40-restic.sh`. It should load `lib/common.sh`, accept `--dry-run`, and
return a non-zero status on failure. Add its short name to `.env`:
```bash
BACKUP_METHODS="rclone smb restic"
```
The main pipeline discovers the numbered file from the short name and runs it
after the earlier methods. A failed method stops the pipeline, so pruning will
not run after a failed transfer.
## Archive and restore format
Archives are stored as:
```text
<BACKUP_ROOT>/<project>/<host>.<project>.<date_time>.tar.zst
```
Each archive contains the project's top-level directory rather than absolute
paths. Example restore into an empty temporary directory:
```bash
mkdir -p /tmp/docker-restore
tar --zstd -xf backup.tar.zst -C /tmp/docker-restore
```
Inspect and verify restored content before replacing a live project.