diff --git a/Maintainers.md b/Maintainers.md new file mode 100644 index 0000000..042157a --- /dev/null +++ b/Maintainers.md @@ -0,0 +1,154 @@ +# For Maintainers + +From the perspective of the recipe maintainer, backup/restore is just more +`deploy: ...` labels. Tools can read these labels and then perform the +backup/restore logic. + +## Tools + +Two of the current "blessed" options are, which both implement the [backupbot specification](link to spec) +- [`backup-bot-two`](https://git.coopcloud.tech/coop-cloud/backup-bot-two) +- [`abra`](https://git.coopcloud.tech/coop-cloud/abra) + +### `backup-bot-two` + +`backup-bot-two` is a recipe which gets deployed on the server, it can perform automatic backups. +Please see the [`README.md`](https://git.coopcloud.tech/coop-cloud/backup-bot-two#backupbot-ii) for the full docs. + +### `abra` + +`abra` will read labels and store backups in `~/.abra/backups/...` . +It also provides an integration for `backup-bot-two`. + +## Backup + +### How to Configure backups + +Unless otherwise stated all labels should be added to the main service (which should be named `app`). + +1. Enable backups for the recipe: +You need to enable backups for the recipe by adding the following label: +``` +backupbot.backup=true +``` + +2. Decide wich volumes should be backed up: +By default all volumes will be backed up. To disable a certain volume you can add the following label: +``` +backupbot.backup.volumes.{volume_name}=false +``` + +3. Decide which path should be backed up on each volume +By default all files get backed up for a volume. To only include certain paths you can add the following label: +``` +backupbot.backup.volumes.{volume_name}.path=/mypath1/foo,/mypath2/bar +``` + +Note: You can include multiple paths by providing a comma seperated list +Note: All paths are specified relativ to the volume root + +4. Run commands before the backup +For certain services like a database it is not reccomend to just backup files, because the backup might end up in a corrupted state. Instead it is reccomended to make a database dump. You can run arbitrary commands in any container before the files are backed up. +To do this add the following label to the service on which you want the command being run: +``` +backupbot.backup.pre-hook=mysqldump -u root -pghost ghost --tab /var/lib/foo +``` + +5. Run commands after the backup +Sometimes you want to clean up after the backup. You can run arbitrary commands in any container after the files were backed up. +To do this add the following label to the service on which you want the command being run: +``` +backupbot.backup.post-hook=rm -rf /var/lib/mysql-files/* +``` + +### Testing the backup + +To test that your backup is configured correctly you can deploy the recipe you are working on in a test app either [locally](link to local server deployment) or on a test server. + +After the deployment is succesfull run the backup and inspect its content + +``` +abra app backup myrecipe.example.com +tar -tf ~/.abra/backups/mybackup +``` + +## Restore + +When restoring an app, it takes the files from a backup and copies them to their correct location. +In the case of restoring database tables, you can use the `pre-hook` & `post-hook` commands to run the insertion logic. + +## Pre and Post hooks + +To back up some services correctly it involves more than just copying a few files from one location to another. Some services already have specific backup tools that allow taking a coherent snapshot of its data like `mysqldump`. +The pre and post hooks can be used to prepare the files which should get backed up and clean up afterwards. + +Here are some examples: + +### Example 1: Execute simple command +``` +backupbot.backup.pre-hook: "echo 'foo' > /path/to/volume/bar.txt +``` + +### Example 2: Access environment variable +``` +backupbot.backup.pre-hook: "cat $${POSTGRES_PASSWORD_FILE}" +``` + +### Example 3: Access secret +``` +backupbot.backup.pre-hook: "cat /var/run/secrets/mysupersecret" +``` + +``` +backupbot.backup.pre-hook: 'mysqldump -p"$$(cat /run/secrets/mysupersecret)" mydatabase' +``` + +### Example 4: Complex script +Sometimes the logic to backup up a service can get quite complex. In that case it might be easier to add a script (via mount or config) inside the container and call that from the pre and post hook: +``` +backupbot.backup.pre-hook: "/scripts/my-pre-backup-scripts" +backupbot.backup.post-hook: "/scripts/my-post-backup-scripts" +``` + +## Configuration Examples + +### Mariadb + +``` +services: + db: + image: mariadb + volumes: + - "mariadb:/var/lib/mysql" + deploy: + labels: + backupbot.backup: "true" + backupbot.backup.pre-hook: "sh -c 'mariadb-dump --single-transaction -u root -p\"$$(cat /run/secrets/db_root_password)\" wordpress | gzip > /var/lib/mysql/dump.sql.gz'" + backupbot.backup.volume.mariadb.path: "dump.sql.gz" + backupbot.backup.post-hook: "rm -f /var/lib/mysql/dump.sql.gz" + backupbot.restore: "true" + backupbot.restore.post-hook: "sh -c 'gzip -d /var/lib/mysql/dump.sql.gz && mariadb -u root -p\"$$(cat /run/secrets/db_root_password)\" wordpress < /var/lib/mysql/dump.sql && rm -f /var/lib/mysql/dump.sql'" +``` + +### Postgres + +``` +version: '3.8' + +services: + db: + image: "postgres" + volumes: + - "postgres:/var/lib/postgresql/data" + secrets: + - db_password + deploy: + labels: + backupbot.backup: "true" + backupbot.backup.pre-hook: "PGPASSWORD=$$(cat $${POSTGRES_PASSWORD_FILE}) pg_dump -U $${POSTGRES_USER} $${POSTGRES_DB} > /var/lib/postgresql/data/backup.sql" + backupbot.backup.post-hook: "rm -rf /var/lib/postgresql/data/backup.sql" + backupbot.backup.volume.postgres.path: "backup.sql" + +volumes: + postgres: +``` diff --git a/Specification.md b/Specification.md index d3f7a7d..1975854 100644 --- a/Specification.md +++ b/Specification.md @@ -22,7 +22,6 @@ By default all files MUST be backed up on a volume. `backupbot.backup.volumes.{v ### Pre/Post Hooks A `backupbot.backup.pre-hook` and `backupbot.backup.post-hook` MAY be set on a service. When set the command MUST be executed inside the running container of the service before/after backing up files. -The command MUST have access to all environment variables inside the container. There is no guaranteed order in which different hooks MUST be executed. ### Output