1
0
mirror of https://github.com/garraflavatra/docker-volume-s3-backup.git synced 2025-05-17 05:14:37 +00:00

Adapt postgres-baskup-s3 to backup Docker volumes instead of Postgres databases

This commit is contained in:
Romein van Buren 2025-05-04 13:18:07 +02:00
parent ecb08ff41c
commit 513f9af69f
No known key found for this signature in database
15 changed files with 100 additions and 149 deletions

View File

@ -1,22 +1,13 @@
name: build and push images name: Build and push image
on: on:
push: push:
branches: ['master'] branches: ['main']
jobs: jobs:
build-and-push-image: build-and-push-image:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
include:
- { postgres: 12, alpine: '3.12' }
- { postgres: 13, alpine: '3.14' }
- { postgres: 14, alpine: '3.16' }
- { postgres: 15, alpine: '3.17' }
- { postgres: 16, alpine: '3.19' }
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -38,9 +29,7 @@ jobs:
with: with:
context: . context: .
push: true push: true
tags: ${{ github.repository }}:${{ matrix.postgres }} tags: ${{ github.repository }}:latest
build-args: |
ALPINE_VERSION=${{ matrix.alpine }}
platforms: | platforms: |
linux/amd64 linux/amd64
linux/arm64 linux/arm64

5
.gitignore vendored
View File

@ -1,2 +1,5 @@
.idea .idea
.env .env
.DS_Store
.env*
!.env.example

View File

@ -1,18 +1,14 @@
ARG ALPINE_VERSION FROM alpine:3.21
FROM alpine:${ALPINE_VERSION}
ARG TARGETARCH RUN mkdir /data
ADD src/install.sh install.sh ADD src/install.sh install.sh
RUN sh install.sh && rm install.sh RUN sh install.sh && rm install.sh
ENV POSTGRES_DATABASE ''
ENV POSTGRES_HOST ''
ENV POSTGRES_PORT 5432
ENV POSTGRES_USER ''
ENV POSTGRES_PASSWORD ''
ENV PGDUMP_EXTRA_OPTS ''
ENV S3_ACCESS_KEY_ID '' ENV S3_ACCESS_KEY_ID ''
ENV S3_SECRET_ACCESS_KEY '' ENV S3_SECRET_ACCESS_KEY ''
ENV S3_ACCESS_KEY ''
ENV S3_SECRET_KEY ''
ENV S3_BUCKET '' ENV S3_BUCKET ''
ENV S3_REGION 'us-west-1' ENV S3_REGION 'us-west-1'
ENV S3_PATH 'backup' ENV S3_PATH 'backup'
@ -25,6 +21,6 @@ ENV BACKUP_KEEP_DAYS ''
ADD src/run.sh run.sh ADD src/run.sh run.sh
ADD src/env.sh env.sh ADD src/env.sh env.sh
ADD src/backup.sh backup.sh ADD src/backup.sh backup.sh
ADD src/restore.sh restore.sh # ADD src/restore.sh restore.sh -- not ready yet
CMD ["sh", "run.sh"] CMD ['sh', 'run.sh']

View File

@ -1,6 +1,8 @@
MIT License MIT License
Copyright (c) 2017 Johannes Schickling Copyright (c) 2017 Johannes Schickling
Copyright (c) 2022 Elliott Shugerman
Copyright (c) 2025 Romein van Buren
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,18 +1,24 @@
# Introduction # docker-volume-s3-backup
This project provides Docker images to periodically back up a PostgreSQL database to AWS S3, and to restore from the backup as needed.
## Introduction
This project provides a Docker image that periodically backs up a Docker volume to AWS S3, and can restore a backup as needed.
## Usage
### Backup
Example `docker-compose.yml`:
# Usage
## Backup
```yaml ```yaml
services: services:
postgres: my_service:
image: postgres:16 image: ...
environment: volumes:
POSTGRES_USER: user data:/app/some-data-dir
POSTGRES_PASSWORD: password
backup: volume_backup:
image: eeshugerman/postgres-backup-s3:16 image: smartyellow/docker-volume-s3-backup
environment: environment:
SCHEDULE: '@weekly' # optional SCHEDULE: '@weekly' # optional
BACKUP_KEEP_DAYS: 7 # optional BACKUP_KEEP_DAYS: 7 # optional
@ -22,66 +28,53 @@ services:
S3_SECRET_ACCESS_KEY: secret S3_SECRET_ACCESS_KEY: secret
S3_BUCKET: my-bucket S3_BUCKET: my-bucket
S3_PREFIX: backup S3_PREFIX: backup
POSTGRES_HOST: postgres
POSTGRES_DATABASE: dbname
POSTGRES_USER: user
POSTGRES_PASSWORD: password
``` ```
- Images are tagged by the major PostgreSQL version supported: `12`, `13`, `14`, `15` or `16`.
- 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. - 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 `PASSPHRASE` is provided, the backup will be encrypted using GPG.
- Run `docker exec <container name> sh backup.sh` to trigger a backup ad-hoc. - 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. - 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. - Set `S3_ENDPOINT` if you're using a non-AWS S3-compatible storage provider.
## Restore ### Restore
> [!CAUTION] > [!CAUTION]
> DATA LOSS! All database objects will be dropped and re-created. > DATA LOSS! All database objects will be dropped and re-created.
### ... from latest backup #### ... from latest backup
```sh ```sh
docker exec <container name> sh restore.sh docker exec <container_name> sh restore.sh
``` ```
> [!NOTE] > [!NOTE]
> If your bucket has more than a 1000 files, the latest may not be restored -- only one S3 `ls` command is used > If your bucket has more than a 1000 files, the latest may not be restored -- only one S3 `ls` command is used
### ... from specific backup #### ... from specific backup
```sh ```sh
docker exec <container name> sh restore.sh <timestamp> docker exec <container_name> sh restore.sh <timestamp>
``` ```
# Development ## Development
## Build the image locally
`ALPINE_VERSION` determines Postgres version compatibility. See [`build-and-push-images.yml`](.github/workflows/build-and-push-images.yml) for the latest mapping. ### Run a simple test environment with Docker Compose
```sh
DOCKER_BUILDKIT=1 docker build --build-arg ALPINE_VERSION=3.14 .
```
## Run a simple test environment with Docker Compose
```sh ```sh
cp template.env .env cp template.env .env
# fill out your secrets/params in .env # fill out your secrets/params in .env
docker compose up -d docker compose up -d
``` ```
# Acknowledgements ## Acknowledgements
This project is a fork and re-structuring of @schickling's [postgres-backup-s3](https://github.com/schickling/dockerfiles/tree/master/postgres-backup-s3) and [postgres-restore-s3](https://github.com/schickling/dockerfiles/tree/master/postgres-restore-s3).
## Fork goals This project is a modification of the excellent [`eeshugerman/postgres-backup-s3`](https://github.com/eeshugerman/postgres-backup-s3), which in turn is a fork and re-structuring of [`schickling/postgres-backup-s3`](https://github.com/schickling/dockerfiles/tree/master/postgres-backup-s3) and [`schickling/postgres-restore-s3`](https://github.com/schickling/dockerfiles/tree/master/postgres-restore-s3).
These changes would have been difficult or impossible merge into @schickling's repo or similarly-structured forks.
- dedicated repository
- automated builds
- support multiple PostgreSQL versions
- backup and restore with one image
## Other changes and features ## Copyright
- some environment variables renamed or removed
- uses `pg_dump`'s `custom` format (see [docs](https://www.postgresql.org/docs/10/app-pgdump.html)) Copyright (c) 2017 Johannes Schickling
- drop and re-create all database objects on restore
- backup blobs and all schemas by default Copyright (c) 2022 Elliott Shugerman
- no Python 2 dependencies
- filter backups on S3 by database name Copyright (c) 2025 [Romein van Buren](mailto:romein@smartyellow.nl)
- support encrypted (password-protected) backups
- support for restoring from a specific backup by timestamp Licensed under the MIT license.
- support for auto-removal of old backups

View File

@ -1,28 +1,19 @@
# this file is here to facilitate development/testing # This file is here to facilitate development/testing.
# See the readme for a list of configuration options.
# Copy the .env.example and add in your S3 credentials.
# $ docker compose up -d --build --force-recreate # $ docker compose up -d --build --force-recreate
services: services:
postgres: test:
image: postgres:14 build: test_image
environment: volumes:
POSTGRES_USER: user - data:/data
POSTGRES_PASSWORD: password
backup: backup:
build: build: .
context: . env_file: .env
args:
ALPINE_VERSION: '3.16'
environment: environment:
SCHEDULE: '@weekly' # optional SCHEDULE: '* * * * *'
BACKUP_KEEP_DAYS: 7 # optional BACKUP_KEEP_DAYS: 7
PASSPHRASE: passphrase # optional PASSPHRASE: passphrase
S3_REGION: S3_PREFIX: backup-test
S3_ACCESS_KEY_ID:
S3_SECRET_ACCESS_KEY:
S3_BUCKET:
S3_PREFIX: backup
POSTGRES_HOST: postgres
POSTGRES_DATABASE: postgres
POSTGRES_USER: user
POSTGRES_PASSWORD: password

View File

@ -1,31 +1,25 @@
#! /bin/sh #!/bin/sh
set -eu set -eu
set -o pipefail set -o pipefail
source ./env.sh source ./env.sh
echo "Creating backup of $POSTGRES_DATABASE database..." echo "Creating backup..."
pg_dump --format=custom \ tar -xzf dump.tar.gz /data
-h $POSTGRES_HOST \
-p $POSTGRES_PORT \
-U $POSTGRES_USER \
-d $POSTGRES_DATABASE \
$PGDUMP_EXTRA_OPTS \
> db.dump
timestamp=$(date +"%Y-%m-%dT%H:%M:%S") 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}/${BACKUP_NAME}_${timestamp}.dump"
if [ -n "$PASSPHRASE" ]; then if [ -n "$PASSPHRASE" ]; then
echo "Encrypting backup..." echo "Encrypting backup..."
rm -f db.dump.gpg rm -f dump.tar.gz.gpg
gpg --symmetric --batch --passphrase "$PASSPHRASE" db.dump gpg --symmetric --batch --passphrase "$PASSPHRASE" dump.tar.gz
rm db.dump rm dump.tar.gz
local_file="db.dump.gpg" local_file="dump.tar.gz.gpg"
s3_uri="${s3_uri_base}.gpg" s3_uri="${s3_uri_base}.gpg"
else else
local_file="db.dump" local_file="dump.tar.gz"
s3_uri="$s3_uri_base" s3_uri="$s3_uri_base"
fi fi

View File

@ -3,29 +3,8 @@ if [ -z "$S3_BUCKET" ]; then
exit 1 exit 1
fi fi
if [ -z "$POSTGRES_DATABASE" ]; then if [ -z "$BACKUP_NAME" ]; then
echo "You need to set the POSTGRES_DATABASE environment variable." echo "You need to set the BACKUP_NAME environment variable."
exit 1
fi
if [ -z "$POSTGRES_HOST" ]; then
# https://docs.docker.com/network/links/#environment-variables
if [ -n "$POSTGRES_PORT_5432_TCP_ADDR" ]; then
POSTGRES_HOST=$POSTGRES_PORT_5432_TCP_ADDR
POSTGRES_PORT=$POSTGRES_PORT_5432_TCP_PORT
else
echo "You need to set the POSTGRES_HOST environment variable."
exit 1
fi
fi
if [ -z "$POSTGRES_USER" ]; then
echo "You need to set the POSTGRES_USER environment variable."
exit 1
fi
if [ -z "$POSTGRES_PASSWORD" ]; then
echo "You need to set the POSTGRES_PASSWORD environment variable."
exit 1 exit 1
fi fi
@ -35,12 +14,20 @@ else
aws_args="--endpoint-url $S3_ENDPOINT" aws_args="--endpoint-url $S3_ENDPOINT"
fi fi
if [ -n "$S3_ACCESS_KEY_ID" ]; then if [ -n "$S3_ACCESS_KEY_ID" ]; then
export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID
fi fi
if [ -n "$S3_ACCESS_KEY" ]; then
export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY
fi
if [ -n "$S3_SECRET_ACCESS_KEY" ]; then if [ -n "$S3_SECRET_ACCESS_KEY" ]; then
export AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY export AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY
fi fi
if [ -n "$S3_SECRET_KEY" ]; then
export AWS_SECRET_ACCESS_KEY=$S3_SECRET_KEY
fi
export AWS_DEFAULT_REGION=$S3_REGION export AWS_DEFAULT_REGION=$S3_REGION
export PGPASSWORD=$POSTGRES_PASSWORD

View File

@ -1,19 +1,12 @@
#! /bin/sh #!/bin/sh
set -eux set -eux
set -o pipefail set -o pipefail
apk update apk update
apk add gnupg aws-cli
# install pg_dump # Install go-cron
apk add postgresql-client
# install gpg
apk add gnupg
apk add aws-cli
# install go-cron
apk add curl apk add curl
curl -L https://github.com/ivoronin/go-cron/releases/download/v0.0.5/go-cron_0.0.5_linux_${TARGETARCH}.tar.gz -O curl -L https://github.com/ivoronin/go-cron/releases/download/v0.0.5/go-cron_0.0.5_linux_${TARGETARCH}.tar.gz -O
tar xvf go-cron_0.0.5_linux_${TARGETARCH}.tar.gz tar xvf go-cron_0.0.5_linux_${TARGETARCH}.tar.gz
@ -22,6 +15,4 @@ mv go-cron /usr/local/bin/go-cron
chmod u+x /usr/local/bin/go-cron chmod u+x /usr/local/bin/go-cron
apk del curl apk del curl
# cleanup
rm -rf /var/cache/apk/* rm -rf /var/cache/apk/*

View File

@ -1,4 +1,4 @@
#! /bin/sh #!/bin/sh
set -u # `-e` omitted intentionally, but i can't remember why exactly :'( set -u # `-e` omitted intentionally, but i can't remember why exactly :'(
set -o pipefail set -o pipefail

View File

@ -1,4 +1,4 @@
#! /bin/sh #!/bin/sh
set -eu set -eu

3
test_image/Dockerfile Normal file
View File

@ -0,0 +1,3 @@
FROM scratch
COPY data/ /data

1
test_image/data/file Normal file
View File

@ -0,0 +1 @@
test file

View File

@ -0,0 +1 @@
nested test file