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:
push:
branches: ['master']
branches: ['main']
jobs:
build-and-push-image:
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:
- name: Checkout repository
uses: actions/checkout@v2
@ -38,9 +29,7 @@ jobs:
with:
context: .
push: true
tags: ${{ github.repository }}:${{ matrix.postgres }}
build-args: |
ALPINE_VERSION=${{ matrix.alpine }}
tags: ${{ github.repository }}:latest
platforms: |
linux/amd64
linux/arm64

5
.gitignore vendored
View File

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

View File

@ -1,18 +1,14 @@
ARG ALPINE_VERSION
FROM alpine:${ALPINE_VERSION}
ARG TARGETARCH
FROM alpine:3.21
RUN mkdir /data
ADD src/install.sh 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_SECRET_ACCESS_KEY ''
ENV S3_ACCESS_KEY ''
ENV S3_SECRET_KEY ''
ENV S3_BUCKET ''
ENV S3_REGION 'us-west-1'
ENV S3_PATH 'backup'
@ -25,6 +21,6 @@ ENV BACKUP_KEEP_DAYS ''
ADD src/run.sh run.sh
ADD src/env.sh env.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
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
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,18 +1,24 @@
# Introduction
This project provides Docker images to periodically back up a PostgreSQL database to AWS S3, and to restore from the backup as needed.
# docker-volume-s3-backup
## 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
services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
my_service:
image: ...
volumes:
data:/app/some-data-dir
backup:
image: eeshugerman/postgres-backup-s3:16
volume_backup:
image: smartyellow/docker-volume-s3-backup
environment:
SCHEDULE: '@weekly' # optional
BACKUP_KEEP_DAYS: 7 # optional
@ -22,66 +28,53 @@ services:
S3_SECRET_ACCESS_KEY: secret
S3_BUCKET: my-bucket
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.
- 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.
- Set `S3_ENDPOINT` if you're using a non-AWS S3-compatible storage provider.
## Restore
### Restore
> [!CAUTION]
> DATA LOSS! All database objects will be dropped and re-created.
### ... from latest backup
#### ... from latest backup
```sh
docker exec <container name> sh restore.sh
docker exec <container_name> sh restore.sh
```
> [!NOTE]
> 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
docker exec <container name> sh restore.sh <timestamp>
docker exec <container_name> sh restore.sh <timestamp>
```
# 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.
```sh
DOCKER_BUILDKIT=1 docker build --build-arg ALPINE_VERSION=3.14 .
```
## Run a simple test environment with Docker Compose
## Development
### Run a simple test environment with Docker Compose
```sh
cp template.env .env
# fill out your secrets/params in .env
docker compose up -d
```
# 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).
## Acknowledgements
## Fork goals
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
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).
## Other changes and features
- some environment variables renamed or removed
- uses `pg_dump`'s `custom` format (see [docs](https://www.postgresql.org/docs/10/app-pgdump.html))
- drop and re-create all database objects on restore
- backup blobs and all schemas by default
- no Python 2 dependencies
- filter backups on S3 by database name
- support encrypted (password-protected) backups
- support for restoring from a specific backup by timestamp
- support for auto-removal of old backups
## Copyright
Copyright (c) 2017 Johannes Schickling
Copyright (c) 2022 Elliott Shugerman
Copyright (c) 2025 [Romein van Buren](mailto:romein@smartyellow.nl)
Licensed under the MIT license.

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
services:
postgres:
image: postgres:14
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
test:
build: test_image
volumes:
- data:/data
backup:
build:
context: .
args:
ALPINE_VERSION: '3.16'
build: .
env_file: .env
environment:
SCHEDULE: '@weekly' # optional
BACKUP_KEEP_DAYS: 7 # optional
PASSPHRASE: passphrase # optional
S3_REGION:
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
SCHEDULE: '* * * * *'
BACKUP_KEEP_DAYS: 7
PASSPHRASE: passphrase
S3_PREFIX: backup-test

View File

@ -1,31 +1,25 @@
#! /bin/sh
#!/bin/sh
set -eu
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
echo "Creating backup..."
tar -xzf dump.tar.gz /data
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
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 dump.tar.gz.gpg
gpg --symmetric --batch --passphrase "$PASSPHRASE" dump.tar.gz
rm dump.tar.gz
local_file="dump.tar.gz.gpg"
s3_uri="${s3_uri_base}.gpg"
else
local_file="db.dump"
local_file="dump.tar.gz"
s3_uri="$s3_uri_base"
fi

View File

@ -3,29 +3,8 @@ if [ -z "$S3_BUCKET" ]; then
exit 1
fi
if [ -z "$POSTGRES_DATABASE" ]; then
echo "You need to set the POSTGRES_DATABASE 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."
if [ -z "$BACKUP_NAME" ]; then
echo "You need to set the BACKUP_NAME environment variable."
exit 1
fi
@ -35,12 +14,20 @@ else
aws_args="--endpoint-url $S3_ENDPOINT"
fi
if [ -n "$S3_ACCESS_KEY_ID" ]; then
export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID
fi
if [ -n "$S3_ACCESS_KEY" ]; then
export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY
fi
if [ -n "$S3_SECRET_ACCESS_KEY" ]; then
export AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY
fi
if [ -n "$S3_SECRET_KEY" ]; then
export AWS_SECRET_ACCESS_KEY=$S3_SECRET_KEY
fi
export AWS_DEFAULT_REGION=$S3_REGION
export PGPASSWORD=$POSTGRES_PASSWORD

View File

@ -1,19 +1,12 @@
#! /bin/sh
#!/bin/sh
set -eux
set -o pipefail
apk update
apk add gnupg aws-cli
# install pg_dump
apk add postgresql-client
# install gpg
apk add gnupg
apk add aws-cli
# install go-cron
# Install go-cron
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
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
apk del curl
# cleanup
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 -o pipefail

View File

@ -1,4 +1,4 @@
#! /bin/sh
#!/bin/sh
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