diff --git a/Dockerfile b/Dockerfile index 974fa56..7bf6ec2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,12 @@ FROM alpine:3.11 RUN apk update \ - && apk add --no-cache \ - rsyslog rsyslog-tls \ - ca-certificates openssl \ - bash \ - && update-ca-certificates - -COPY dockerbuild/rsyslog.conf /etc/rsyslog.conf - -RUN wget https://raw.githubusercontent.com/silinternational/runny/0.2/runny \ - -O /usr/local/bin/runny \ - && chmod +x /usr/local/bin/runny + && apk add --no-cache bash ARG restic_ver=0.9.6 -RUN wget https://github.com/restic/restic/releases/download/v${restic_ver}/restic_${restic_ver}_linux_amd64.bz2 \ - -O /tmp/restic.bz2 \ +RUN wget -O /tmp/restic.bz2 \ + https://github.com/restic/restic/releases/download/v${restic_ver}/restic_${restic_ver}_linux_amd64.bz2 \ && bunzip2 /tmp/restic.bz2 \ && chmod +x /tmp/restic \ && mv /tmp/restic /usr/local/bin/restic @@ -24,5 +14,4 @@ RUN wget https://github.com/restic/restic/releases/download/v${restic_ver}/resti COPY application/ /data/ WORKDIR /data -ENTRYPOINT ["./entrypoint.sh"] -CMD ["crond -f"] +CMD ["./entrypoint.sh"] diff --git a/README.md b/README.md index cf9a9b7..81beb15 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# docker-restic-backup +# restic-backup-restore Docker image to initialize, backup to, and restore from a Restic repository on AWS S3. ## How to use it @@ -14,27 +14,23 @@ Docker image to initialize, backup to, and restore from a Restic repository on A 3. `AWS_DEFAULT_REGION` - AWS default region for S3 bucket -4. `CRON_SCHEDULE="0 2 * * *"` - Schedule for cron job, _defaults to every day at 2:00 AM_ [syntax reference](https://en.wikipedia.org/wiki/Cron) +4. `FSBACKUP_MODE=[init|backup|restore]` - `init` initializes the Restic repository at `$RESTIC_REPOSITORY` (only do this once); `backup` performs a backup; `restore` performs a restoration. -5. `FSBACKUP_MODE=[init|backup|restore]` - `init` initializes the Restic repository at `$RESTIC_REPOSITORY` (only do this once); `backup` performs a backup; `restore` performs a restoration. +5. `RESTIC_BACKUP_ARGS` - additional arguments to pass to 'restic backup' command -6. `LOGENTRIES_KEY` - (optional) If provided, the image will send command output to syslog with priority `user.info`. +6. `RESTIC_FORGET_ARGS` - additional arguments to pass to 'restic forget --prune' command (e.g., --keep-daily 7 --keep-weekly 5 --keep-monthly 3 --keep-yearly 2) -7. `RESTIC_BACKUP_ARGS` - additional arguments to pass to 'restic backup' command +7. `RESTIC_HOST` - hostname to be used for the backup -8. `RESTIC_FORGET_ARGS` - additional arguments to pass to 'restic forget --prune' command (e.g., --keep-daily 7 --keep-weekly 5 --keep-monthly 3 --keep-yearly 2) +8. `RESTIC_PASSWORD` - password for the Restic repository -9. `RESTIC_HOST` - hostname to be used for the backup +9. `RESTIC_REPOSITORY` - Restic repository location (e.g., 's3:s3.amazonaws.com/bucketname/restic') -10. `RESTIC_PASSWORD` - password for the Restic repository +10. `RESTIC_TAG` - tag to apply to the backup -11. `RESTIC_REPOSITORY` - Restic repository location (e.g., 's3:s3.amazonaws.com/bucketname/restic') +11. `SOURCE_PATH` - full path to the source directory to be backed up -12. `RESTIC_TAG` - tag to apply to the backup - -13. `SOURCE_PATH` - full path to the source directory to be backed up - -14. `TARGET_PATH` - full path to the target directory to be restored to (usually the same as the SOURCE\_PATH) +12. `TARGET_PATH` - full path to the target directory to be restored to (usually the same as the SOURCE\_PATH) It's recommended that your S3 bucket **NOT** have versioning turned on. Old versions of Restic's repository files are not useful. diff --git a/application/backup.sh b/application/backup.sh index 1c78560..68cf5f6 100755 --- a/application/backup.sh +++ b/application/backup.sh @@ -1,29 +1,53 @@ #!/usr/bin/env sh -logger -p user.info "Started backup..." +STATUS=0 + +echo "restic-backup-restore: backup: Started" +echo "restic-backup-restore: Backing up ${SOURCE_PATH}" start=$(date +%s) -runny /usr/local/bin/restic backup --host ${RESTIC_HOST} --tag ${RESTIC_TAG} ${RESTIC_BACKUP_ARGS} ${SOURCE_PATH} +/usr/local/bin/restic backup --host ${RESTIC_HOST} --tag ${RESTIC_TAG} ${RESTIC_BACKUP_ARGS} ${SOURCE_PATH} || STATUS=$? end=$(date +%s) -logger -p user.info "Backup completed in $(expr ${end} - ${start}) seconds." +if [ $STATUS -ne 0 ]; then + echo "restic-backup-restore: FATAL: Backup returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds." + exit $STATUS +else + echo "restic-backup-restore: Backup completed in $(expr ${end} - ${start}) seconds." +fi start=$(date +%s) -runny /usr/local/bin/restic forget --host ${RESTIC_HOST} ${RESTIC_FORGET_ARGS} --prune +/usr/local/bin/restic forget --host ${RESTIC_HOST} ${RESTIC_FORGET_ARGS} --prune || STATUS=$? end=$(date +%s) -logger -p user.info "Backup pruning completed in $(expr ${end} - ${start}) seconds." +if [ $STATUS -ne 0 ]; then + echo "restic-backup-restore: FATAL: Backup pruning returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds." + exit $STATUS +else + echo "restic-backup-restore: Backup pruning completed in $(expr ${end} - ${start}) seconds." +fi start=$(date +%s) -runny /usr/local/bin/restic check +/usr/local/bin/restic check || STATUS=$? end=$(date +%s) -logger -p user.info "Repository check completed in $(expr ${end} - ${start}) seconds." +if [ $STATUS -ne 0 ]; then + echo "restic-backup-restore: FATAL: Repository check returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds." + exit $STATUS +else + echo "restic-backup-restore: Repository check completed in $(expr ${end} - ${start}) seconds." +fi start=$(date +%s) -runny /usr/local/bin/restic unlock +/usr/local/bin/restic unlock || STATUS=$? end=$(date +%s) -logger -p user.info "Repository unlock completed in $(expr ${end} - ${start}) seconds." +if [ $STATUS -ne 0 ]; then + echo "restic-backup-restore: FATAL: Repository unlock returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds." + exit $STATUS +else + echo "restic-backup-restore: Repository unlock completed in $(expr ${end} - ${start}) seconds." +fi -logger -p user.info "...completed backup." +echo "restic-backup-restore: backup: Completed" +exit $STATUS diff --git a/application/entrypoint.sh b/application/entrypoint.sh index 015439d..9df46db 100755 --- a/application/entrypoint.sh +++ b/application/entrypoint.sh @@ -1,14 +1,18 @@ #!/usr/bin/env sh -if [ "${LOGENTRIES_KEY}" ]; then - sed -i /etc/rsyslog.conf -e "s/LOGENTRIESKEY/${LOGENTRIES_KEY}/" - rsyslogd - sleep 10 # ensure rsyslogd is running before we may need to send logs to it -else - logger -p user.error "Missing LOGENTRIES_KEY environment variable" -fi +STATUS=0 + +case "${FSBACKUP_MODE}" in + init|backup|restore) + /data/${FSBACKUP_MODE}.sh || STATUS=$? + ;; + *) + echo restic-backup-restore: FATAL: Unknown FSBACKUP_MODE: ${FSBACKUP_MODE} + exit 1 +esac -# default to every day at 2 am when no schedule is provided -echo "${CRON_SCHEDULE:=0 2 * * *} runny /data/${FSBACKUP_MODE}.sh" >> /etc/crontabs/root +if [ $STATUS -ne 0 ]; then + echo restic-backup-restore: Non-zero exit: $STATUS +fi -runny $1 +exit $STATUS diff --git a/application/init.sh b/application/init.sh index fd5554e..0735631 100755 --- a/application/init.sh +++ b/application/init.sh @@ -1,11 +1,19 @@ #!/usr/bin/env sh -logger -p user.info "Started Restic repository initialization..." +STATUS=0 + +echo "restic-backup-restore: init: Started" start=$(date +%s) -runny /usr/local/bin/restic init +/usr/local/bin/restic init || STATUS=$? end=$(date +%s) -logger -p user.info "Repository initialization completed in $(expr ${end} - ${start}) seconds." +if [ $STATUS -ne 0 ]; then + echo "restic-backup-restore: FATAL: Repository initialization returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds." + exit $STATUS +else + echo "restic-backup-restore: Repository initialization completed in $(expr ${end} - ${start}) seconds. +fi -logger -p user.info "...completed repository initialization." +echo "restic-backup-restore: init: Completed" +exit $STATUS diff --git a/application/restore.sh b/application/restore.sh index 49e5673..73835c6 100755 --- a/application/restore.sh +++ b/application/restore.sh @@ -1,17 +1,31 @@ #!/usr/bin/env sh -logger -p user.info "Restoring ${RESTIC_RESTORE_ID}..." +STATUS=0 + +echo "restic-backup-restore: restore: Started" +echo "restic-backup-restore: Restoring ${RESTIC_RESTORE_ID} to ${TARGET_PATH}" start=$(date +%s) -runny /usr/local/bin/restic restore ${RESTIC_RESTORE_ID} --host ${RESTIC_HOST} --tag ${RESTIC_TAG} --target ${TARGET_PATH} +/usr/local/bin/restic restore ${RESTIC_RESTORE_ID} --host ${RESTIC_HOST} --tag ${RESTIC_TAG} --target ${TARGET_PATH} || STATUS=$? end=$(date +%s) -logger -p user.info "Restoration completed in $(expr ${end} - ${start}) seconds." +if [ $STATUS -ne 0 ]; then + echo "restic-backup-restore: FATAL: Restore returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds." + exit $STATUS +else + echo "restic-backup-restore: Restore completed in $(expr ${end} - ${start}) seconds." +fi start=$(date +%s) -runny /usr/local/bin/restic unlock +/usr/local/bin/restic unlock || STATUS=$? end=$(date +%s) -logger -p user.info "Repository unlock completed in $(expr ${end} - ${start}) seconds." +if [ $STATUS -ne 0 ]; then + echo "restic-backup-restore: FATAL: Repository unlock returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds." + exit $STATUS +else + echo "restic-backup-restore: Repository unlock completed in $(expr ${end} - ${start}) seconds." +fi -logger -p user.info "...completed restore." +echo "restic-backup-restore: restore: Completed" +exit $STATUS diff --git a/dockerbuild/rsyslog.conf b/dockerbuild/rsyslog.conf deleted file mode 100644 index 2a2b661..0000000 --- a/dockerbuild/rsyslog.conf +++ /dev/null @@ -1,16 +0,0 @@ -# if you experience problems, check: -# http://www.rsyslog.com/troubleshoot - -$ModLoad imuxsock # provides support for local system logging (e.g. via logger command) - -# -# Configure TLS (logentries-specific example: https://docs.logentries.com/docs/rsyslog/) -# -$DefaultNetstreamDriverCAFile /etc/ssl/certs/ca-certificates.crt -$ActionSendStreamDriver gtls -$ActionSendStreamDriverMode 1 -$ActionSendStreamDriverAuthMode x509/name -$ActionSendStreamDriverPermittedPeer *.logentries.com - -$template LogentriesFormat,"LOGENTRIESKEY %msg%\n" -*.emerg,*.alert,*.crit,*.err,*.warning,user.* @@data.logentries.com:443;LogentriesFormat diff --git a/local.env.dist b/local.env.dist index 7a7a659..c3624d7 100644 --- a/local.env.dist +++ b/local.env.dist @@ -1,9 +1,7 @@ AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION= -CRON_SCHEDULE= FSBACKUP_MODE= -LOGENTRIES_KEY= RESTIC_BACKUP_ARGS= RESTIC_FORGET_ARGS= RESTIC_HOST=