Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backup and restore with pg_dumpall #38

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ ENV S3_S3V4 'no'
ENV SCHEDULE ''
ENV PASSPHRASE ''
ENV BACKUP_KEEP_DAYS ''
ENV BACKUP_ALL 'false'

ADD src/run.sh run.sh
ADD src/env.sh env.sh
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,22 @@ services:
SCHEDULE: '@weekly' # optional
BACKUP_KEEP_DAYS: 7 # optional
PASSPHRASE: passphrase # optional
BACKUP_ALL: 'false' # optional
S3_REGION: region
S3_ACCESS_KEY_ID: key
S3_SECRET_ACCESS_KEY: secret
S3_BUCKET: my-bucket
S3_PREFIX: backup
POSTGRES_HOST: postgres
POSTGRES_DATABASE: dbname
POSTGRES_DATABASE: dbname # optional if BACKUP_ALL is 'true'
POSTGRES_USER: user
POSTGRES_PASSWORD: password
```

- Images are tagged by the major PostgreSQL version supported: `11`, `12`, `13`, `14`, or `15`.
- The `SCHEDULE` variable determines backup frequency. See go-cron schedules documentation [here](http://godoc.org/github.com/robfig/cron#hdr-Predefined_schedules). Omit to run the backup immediately and then exit.
- If `PASSPHRASE` is provided, the backup will be encrypted using GPG.
- If `BACKUP_ALL` is `'true'`, all databases will be backed up. Otherwise, only `POSTGRES_DATABASE` will be backed up.
- Run `docker exec <container name> sh backup.sh` to trigger a backup ad-hoc.
- If `BACKUP_KEEP_DAYS` is set, backups older than this many days will be deleted from S3.
- Set `S3_ENDPOINT` if you're using a non-AWS S3-compatible storage provider.
Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ services:
SCHEDULE: '@weekly' # optional
BACKUP_KEEP_DAYS: 7 # optional
PASSPHRASE: passphrase # optional
BACKUP_ALL: 'true' # optional
S3_REGION:
S3_ACCESS_KEY_ID:
S3_SECRET_ACCESS_KEY:
S3_BUCKET:
S3_PREFIX: backup
POSTGRES_HOST: postgres
POSTGRES_DATABASE: postgres
POSTGRES_DATABASE: postgres # optional if BACKUP_ALL is true
POSTGRES_USER: user
POSTGRES_PASSWORD: password
41 changes: 27 additions & 14 deletions src/backup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,40 @@ set -o pipefail

source ./env.sh

echo "Creating backup of $POSTGRES_DATABASE database..."
pg_dump --format=custom \
-h $POSTGRES_HOST \
-p $POSTGRES_PORT \
-U $POSTGRES_USER \
-d $POSTGRES_DATABASE \
$PGDUMP_EXTRA_OPTS \
> db.dump
if [ "$BACKUP_ALL" = "true" ]; then
echo "Creating backup of all databases..."
file_ext="dump.gz"
pg_dumpall --clean \
-h $POSTGRES_HOST \
-p $POSTGRES_PORT \
-U $POSTGRES_USER \
$PGDUMP_EXTRA_OPTS \
> db.dump

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we want to pipe directly to gzip here?
| gzip > db.dump.gz

gzip db.dump
else
echo "Creating backup of $POSTGRES_DATABASE database..."
file_ext="dump"
pg_dump --format=custom \
-h $POSTGRES_HOST \
-p $POSTGRES_PORT \
-U $POSTGRES_USER \
-d $POSTGRES_DATABASE \
$PGDUMP_EXTRA_OPTS \
> db.dump
fi

timestamp=$(date +"%Y-%m-%dT%H:%M:%S")
s3_uri_base="s3://${S3_BUCKET}/${S3_PREFIX}/${POSTGRES_DATABASE}_${timestamp}.dump"
s3_uri_base="s3://${S3_BUCKET}/${S3_PREFIX}/${POSTGRES_DATABASE}_${timestamp}.${file_ext}"

if [ -n "$PASSPHRASE" ]; then
echo "Encrypting backup..."
rm -f db.dump.gpg
gpg --symmetric --batch --passphrase "$PASSPHRASE" db.dump
rm db.dump
local_file="db.dump.gpg"
rm -f db.$file_ext.gpg
gpg --symmetric --batch --passphrase "$PASSPHRASE" db.$file_ext
rm db.$file_ext
local_file="db.${file_ext}.gpg"
s3_uri="${s3_uri_base}.gpg"
else
local_file="db.dump"
local_file="db.${file_ext}"
s3_uri="$s3_uri_base"
fi

Expand Down
2 changes: 1 addition & 1 deletion src/env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ if [ -z "$S3_BUCKET" ]; then
exit 1
fi

if [ -z "$POSTGRES_DATABASE" ]; then
if [ "$BACKUP_ALL" != "true" ] && [ -z "$POSTGRES_DATABASE" ]; then
echo "You need to set the POSTGRES_DATABASE environment variable."
exit 1
fi
Expand Down
27 changes: 20 additions & 7 deletions src/restore.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ source ./env.sh

s3_uri_base="s3://${S3_BUCKET}/${S3_PREFIX}"

if [ "$BACKUP_ALL" = "true" ]; then
file_ext=".dump.gz"
else
file_ext=".dump"
fi

if [ -z "$PASSPHRASE" ]; then
file_type=".dump"
file_type=$file_ext
else
file_type=".dump.gpg"
file_type="${file_ext}.gpg"
fi

if [ $# -eq 1 ]; then
Expand All @@ -31,14 +37,21 @@ aws $aws_args s3 cp "${s3_uri_base}/${key_suffix}" "db${file_type}"

if [ -n "$PASSPHRASE" ]; then
echo "Decrypting backup..."
gpg --decrypt --batch --passphrase "$PASSPHRASE" db.dump.gpg > db.dump
rm db.dump.gpg
gpg --decrypt --batch --passphrase "$PASSPHRASE" db$file_type > db$file_ext
rm db$file_type
fi

conn_opts="-h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -d $POSTGRES_DATABASE"
conn_opts="-h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER"

if [ "$BACKUP_ALL" = "true" ]; then
gunzip db.dump.gz
echo "Restoring all databases..."
psql -f db.dump $conn_opts
else
echo "Restoring from backup..."
pg_restore $conn_opts -d $POSTGRES_DATABASE --clean --if-exists db.dump
fi

echo "Restoring from backup..."
pg_restore $conn_opts --clean --if-exists db.dump
rm db.dump

echo "Restore complete."