diff --git a/abra.sh b/abra.sh index d6cf678..30b222f 100644 --- a/abra.sh +++ b/abra.sh @@ -1 +1,2 @@ -export GHOST_ENTRYPOINT_VERSION=v1 \ No newline at end of file +export GHOST_ENTRYPOINT_VERSION=v1 +export MYSQL_BACKUP_VERSION=v1 diff --git a/compose.yml b/compose.yml index 38c60b7..f3ab954 100644 --- a/compose.yml +++ b/compose.yml @@ -51,7 +51,7 @@ services: - "traefik.http.middlewares.${STACK_NAME}-redirect.redirectscheme.permanent=true" - "backupbot.backup=true" - "backupbot.backup.path=/var/lib/ghost/content" - - "coop-cloud.${STACK_NAME}.version=1.2.0+6.21.2-alpine" + - "coop-cloud.${STACK_NAME}.version=1.3.0+6.21.2-alpine" healthcheck: test: ["CMD", "wget", "--header=X-Forwarded-Proto: https", "--spider", "-q", "http://localhost:2368/ghost/api/admin/site"] interval: 30s @@ -67,14 +67,19 @@ services: MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password secrets: - db_password + configs: + - source: mysql_backup + target: /mysql_backup.sh + mode: 0555 volumes: - "mysql:/var/lib/mysql" deploy: labels: - "backupbot.backup=true" - - "backupbot.backup.pre-hook=mysqldump -u root -p\"$$(cat /run/secrets/db_password)\" ghost --tab /var/lib/mysql-files/" - - "backupbot.backup.post-hook=rm -rf /var/lib/mysql-files/*" - - "backupbot.backup.path=/var/lib/mysql-files/" + - "backupbot.backup.pre-hook=/mysql_backup.sh backup" + - "backupbot.backup.post-hook=rm -f /var/lib/mysql/backup.sql.gz" + - "backupbot.backup.path=/var/lib/mysql/backup.sql.gz" + - "backupbot.restore.post-hook=/mysql_backup.sh restore" healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p\"$$(cat /run/secrets/db_password)\""] @@ -103,4 +108,7 @@ secrets: configs: ghost_entrypoint: name: ${STACK_NAME}_ghost_entrypoint_${GHOST_ENTRYPOINT_VERSION} - file: entrypoint.sh \ No newline at end of file + file: entrypoint.sh + mysql_backup: + name: ${STACK_NAME}_mysql_backup_${MYSQL_BACKUP_VERSION} + file: mysql_backup.sh \ No newline at end of file diff --git a/mysql_backup.sh b/mysql_backup.sh new file mode 100755 index 0000000..10a58b4 --- /dev/null +++ b/mysql_backup.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# MySQL backup/restore hook for the `db` service. Invoked by backupbot-two via: +# backupbot.backup.pre-hook = "/mysql_backup.sh backup" +# backupbot.backup.path = "/var/lib/mysql/backup.sql.gz" +# backupbot.restore.post-hook = "/mysql_backup.sh restore" +# Backup dumps the `ghost` DB to a single gzipped file inside the mysql data volume; backupbot +# archives it. Restore reimports it. The previous recipe shipped a `mysqldump --tab` backup with NO +# restore hook (and the mysql data volume itself was not backed up), so a restored backup silently +# kept the live, un-restored DB state — data loss on restore. + +set -e + +BACKUP_FILE="/var/lib/mysql/backup.sql.gz" +export MYSQL_PWD="$(cat "${MYSQL_ROOT_PASSWORD_FILE:-/run/secrets/db_password}")" +DB_NAME="ghost" + +function backup { + mysqldump -u root --single-transaction --routines --triggers --databases "$DB_NAME" | gzip > "$BACKUP_FILE" +} + +function restore { + # --databases dump carries CREATE DATABASE/USE + per-table DROP+CREATE (mysqldump default), so the + # reimport deterministically rebuilds every table from the archived dump. + gunzip -c "$BACKUP_FILE" | mysql -u root +} + +$@