Skip to content

Commit 5a8132b

Browse files
authored
Merge pull request #1 from silinternational/develop
Develop
2 parents 3423f9f + 37f3b51 commit 5a8132b

File tree

14 files changed

+327
-0
lines changed

14 files changed

+327
-0
lines changed

.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.aes
2+
codeship-services.yml
3+
codeship-steps.yml
4+
dockercfg

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# local config files
2+
aws.env
3+
local.env
4+
5+
*.aes
6+
7+
dockercfg

Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM alpine:3.15
2+
3+
RUN apk update \
4+
&& apk add --no-cache \
5+
bash \
6+
postgresql12-client
7+
8+
COPY application/ /data/
9+
WORKDIR /data
10+
11+
CMD ["./entrypoint.sh"]

Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
start: restore backup
2+
3+
restore: db
4+
docker-compose up -d restore
5+
6+
backup: db
7+
docker-compose up -d backup
8+
9+
db:
10+
docker-compose up -d db
11+
12+
clean:
13+
docker-compose kill
14+
docker system prune -f

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# postgresql-backup-restore-fs
2+
Service to backup and/or restore a PostgreSQL database to/from a local filesystem directory
3+
4+
## How to use it
5+
1. Create a directory on the filesystem to hold your backups
6+
2. Supply all appropriate environment variables
7+
3. Run a backup and check your directory for that backup
8+
9+
### Environment variables
10+
`MODE` Valid values: `backup`, `restore`
11+
12+
`DB_HOST` hostname of the database server
13+
14+
`DB_NAME` name of the database
15+
16+
`DB_OPTIONS` optional arguments to supply to the backup or restore commands
17+
18+
`DB_ROOTPASSWORD` password for the `DB_ROOTUSER`
19+
20+
`DB_ROOTUSER` database administrative user, typically "postgres" for PostgreSQL databases
21+
22+
`DB_USERPASSWORD` password for the `DB_USER`
23+
24+
`DB_USER` user that accesses the database (PostgreSQL "role")
25+
26+
`BACKUP_DIR` e.g., _/path/to/database-backups_ **NOTE: no trailing slash**
27+
28+
>**Versioning of the backup file is left as an exercise for the user. This script will overwrite an existing backup file.**
29+
30+
## Docker Hub
31+
This image is built automatically on Docker Hub as [silintl/postgresql-backup-restore-fs](https://hub.docker.com/r/silintl/postgresql-backup-restore-fs/)
32+
33+
## Playing with it locally
34+
You'll need [Docker](https://www.docker.com/get-docker), [Docker Compose](https://docs.docker.com/compose/install/), and [Make](https://www.gnu.org/software/make/).
35+
36+
1. cd .../postgres-backup-restore-fs
37+
2. mkdir ./mybackups
38+
3. cp -p test/world.sql.gz ./mybackups
39+
4. `make db` # creates the Postgres DB server
40+
5. `make restore` # restores the DB dump file
41+
6. `docker ps -a` # get the Container ID of the exited restore container
42+
7. `docker logs <containerID>` # review the restoration log messages
43+
8. `make backup` # create a new DB dump file
44+
9. `docker ps -a` # get the Container ID of the exited backup container
45+
10. `docker logs <containerID>` # review the backup log messages
46+
11. `make restore` # restore the DB dump file from the new backup
47+
12. `docker ps -a` # get the Container ID of the exited restore container
48+
13. `docker logs <containerID>` # review the restoration log messages
49+
14. `make clean` # remove containers and network
50+
15. `docker volume ls` # find the volume ID of the Postgres data container
51+
16. `docker volume rm <volumeID>` # remove the data volume
52+
17. `docker images` # list existing images
53+
18. `docker image rm <imageID ...>` # remove images no longer needed

application/backup.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env sh
2+
3+
STATUS=0
4+
5+
echo "postgresql-backup-restore-fs: backup: Started"
6+
7+
echo "postgresql-backup-restore-fs: Backing up ${DB_NAME}"
8+
9+
start=$(date +%s)
10+
$(PGPASSWORD=${DB_USERPASSWORD} pg_dump --host=${DB_HOST} --username=${DB_USER} --create --clean ${DB_OPTIONS} --dbname=${DB_NAME} > /tmp/${DB_NAME}.sql) || STATUS=$?
11+
end=$(date +%s)
12+
13+
if [ $STATUS -ne 0 ]; then
14+
echo "postgresql-backup-restore-fs: FATAL: Backup of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
15+
exit $STATUS
16+
else
17+
echo "postgresql-backup-restore-fs: Backup of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds, ($(stat -c %s /tmp/${DB_NAME}.sql) bytes)."
18+
fi
19+
20+
start=$(date +%s)
21+
gzip -f /tmp/${DB_NAME}.sql || STATUS=$?
22+
end=$(date +%s)
23+
24+
if [ $STATUS -ne 0 ]; then
25+
echo "postgresql-backup-restore-fs: FATAL: Compressing backup of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
26+
exit $STATUS
27+
else
28+
echo "postgresql-backup-restore-fs: Compressing backup of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
29+
fi
30+
31+
start=$(date +%s)
32+
mv /tmp/${DB_NAME}.sql.gz ${BACKUP_DIR} || STATUS=$?
33+
end=$(date +%s)
34+
35+
if [ $STATUS -ne 0 ]; then
36+
echo "postgresql-backup-restore-fs: FATAL: Copy backup to ${BACKUP_DIR} of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
37+
exit $STATUS
38+
else
39+
echo "postgresql-backup-restore-fs: Copy backup to ${BACKUP_DIR} of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
40+
fi
41+
42+
echo "postgresql-backup-restore-fs: backup: Completed"

application/entrypoint.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env sh
2+
3+
# hostname:port:database:username:password
4+
echo ${DB_HOST}:*:*:${DB_USER}:${DB_USERPASSWORD} > /root/.pgpass
5+
echo ${DB_HOST}:*:*:${DB_ROOTUSER}:${DB_ROOTPASSWORD} >> /root/.pgpass
6+
chmod 600 /root/.pgpass
7+
8+
STATUS=0
9+
10+
case "${MODE}" in
11+
backup|restore)
12+
/data/${MODE}.sh || STATUS=$?
13+
;;
14+
*)
15+
echo postgresql-backup-restore-fs: FATAL: Unknown MODE: ${MODE}
16+
exit 1
17+
esac
18+
19+
if [ $STATUS -ne 0 ]; then
20+
echo postgresql-backup-restore-fs: Non-zero exit: $STATUS
21+
fi
22+
23+
exit $STATUS

application/restore.sh

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env sh
2+
3+
STATUS=0
4+
5+
echo "postgresql-backup-restore-fs: restore: Started"
6+
7+
# Ensure the database user exists.
8+
echo "postgresql-backup-restore-fs: checking for DB user ${DB_USER}"
9+
result=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --command='\du' | grep ${DB_USER})
10+
if [ -z "${result}" ]; then
11+
result=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --command="create role ${DB_USER} with login password '${DB_USERPASSWORD}' inherit;")
12+
if [ "${result}" != "CREATE ROLE" ]; then
13+
message="Create role command failed: ${result}"
14+
echo "postgresql-backup-restore-fs: FATAL: ${message}"
15+
exit 1
16+
fi
17+
fi
18+
19+
# Delete database if it exists.
20+
echo "postgresql-backup-restore-fs: checking for DB ${DB_NAME}"
21+
result=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --list | grep ${DB_NAME})
22+
if [ -z "${result}" ]; then
23+
message="Database "${DB_NAME}" on host "${DB_HOST}" does not exist."
24+
echo "postgresql-backup-restore-fs: INFO: ${message}"
25+
else
26+
echo "postgresql-backup-restore-fs: deleting database ${DB_NAME}"
27+
result=$(psql --host=${DB_HOST} --dbname=postgres --username=${DB_ROOTUSER} --command="DROP DATABASE ${DB_NAME};")
28+
if [ "${result}" != "DROP DATABASE" ]; then
29+
message="Create database command failed: ${result}"
30+
echo "postgresql-backup-restore-fs: FATAL: ${message}"
31+
exit 1
32+
fi
33+
fi
34+
35+
echo "postgresql-backup-restore-fs: copying database ${DB_NAME} backup from ${BACKUP_DIR}"
36+
start=$(date +%s)
37+
cp ${BACKUP_DIR}/${DB_NAME}.sql.gz /tmp/${DB_NAME}.sql.gz || STATUS=$?
38+
end=$(date +%s)
39+
40+
if [ $STATUS -ne 0 ]; then
41+
echo "postgresql-backup-restore-fs: FATAL: Copy backup of ${DB_NAME} from ${BACKUP_DIR} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
42+
exit $STATUS
43+
else
44+
echo "postgresql-backup-restore-fs: Copy backup of ${DB_NAME} from ${BACKUP_DIR} completed in $(expr ${end} - ${start}) seconds."
45+
fi
46+
47+
echo "postgresql-backup-restore-fs: decompressing backup of ${DB_NAME}"
48+
start=$(date +%s)
49+
gunzip -f /tmp/${DB_NAME}.sql.gz || STATUS=$?
50+
end=$(date +%s)
51+
52+
if [ $STATUS -ne 0 ]; then
53+
echo "postgresql-backup-restore-fs: FATAL: Decompressing backup of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
54+
exit $STATUS
55+
else
56+
echo "postgresql-backup-restore-fs: Decompressing backup of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
57+
fi
58+
59+
echo "postgresql-backup-restore-fs: restoring ${DB_NAME}"
60+
start=$(date +%s)
61+
psql --host=${DB_HOST} --username=${DB_ROOTUSER} --dbname=postgres ${DB_OPTIONS} < /tmp/${DB_NAME}.sql || STATUS=$?
62+
end=$(date +%s)
63+
64+
if [ $STATUS -ne 0 ]; then
65+
echo "postgresql-backup-restore-fs: FATAL: Restore of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
66+
exit $STATUS
67+
else
68+
echo "postgresql-backup-restore-fs: Restore of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
69+
fi
70+
71+
echo "postgresql-backup-restore-fs: restore: Completed"
72+
exit $STATUS

codeship-services.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
app:
2+
build:
3+
image: silintl/postgresql-backup-restore-fs
4+
dockerfile: ./Dockerfile
5+
cached: true

codeship-steps.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
- name: push_branch
2+
service: app
3+
type: push
4+
image_name: silintl/postgresql-backup-restore-fs
5+
image_tag: "{{.Branch}}"
6+
exclude: (master|main|snyk*)
7+
registry: https://index.docker.io/v1/
8+
encrypted_dockercfg_path: dockercfg.encrypted
9+
10+
- name: push_latest
11+
service: app
12+
type: push
13+
image_name: silintl/postgresql-backup-restore-fs
14+
image_tag: "latest"
15+
tag: main
16+
registry: https://index.docker.io/v1/
17+
encrypted_dockercfg_path: dockercfg.encrypted
18+
19+
#- name: test
20+
# service: app
21+
# command: echo "Image was tested"
22+

0 commit comments

Comments
 (0)