mirror of
https://github.com/garraflavatra/docker-volume-s3-backup.git
synced 2025-05-17 13:14:38 +00:00
Adapt postgres-baskup-s3 to backup Docker volumes instead of Postgres databases
This commit is contained in:
parent
ecb08ff41c
commit
513f9af69f
@ -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
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,5 @@
|
|||||||
.idea
|
.idea
|
||||||
.env
|
.env
|
||||||
|
.DS_Store
|
||||||
|
.env*
|
||||||
|
!.env.example
|
||||||
|
18
Dockerfile
18
Dockerfile
@ -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']
|
||||||
|
@ -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
|
||||||
|
87
README.md
87
README.md
@ -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
|
|
||||||
|
@ -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
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
37
src/env.sh
37
src/env.sh
@ -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
|
|
||||||
|
@ -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/*
|
||||||
|
@ -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
|
@ -1,4 +1,4 @@
|
|||||||
#! /bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
3
test_image/Dockerfile
Normal file
3
test_image/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM scratch
|
||||||
|
|
||||||
|
COPY data/ /data
|
1
test_image/data/file
Normal file
1
test_image/data/file
Normal file
@ -0,0 +1 @@
|
|||||||
|
test file
|
1
test_image/data/nested/file
Normal file
1
test_image/data/nested/file
Normal file
@ -0,0 +1 @@
|
|||||||
|
nested test file
|
Loading…
x
Reference in New Issue
Block a user