Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a873e89
補排版器檢查
sih4sing5hong5 Jul 3, 2025
90d6f3b
pymarkdown
sih4sing5hong5 Jul 3, 2025
8f9a148
加gherkin規則
sih4sing5hong5 Jul 3, 2025
5a2e5d7
控制before_intall
sih4sing5hong5 Jul 3, 2025
092148c
shellcheck
sih4sing5hong5 Jul 3, 2025
0f84663
修.travis.yml
sih4sing5hong5 Jul 3, 2025
00017a8
修SC1091
sih4sing5hong5 Jul 3, 2025
f707e22
SC2155
sih4sing5hong5 Jul 3, 2025
6460c48
SC2013
sih4sing5hong5 Jul 3, 2025
3d1b016
SC1091攏改做scripts/
sih4sing5hong5 Jul 3, 2025
ec192c5
修SC1091
sih4sing5hong5 Jul 3, 2025
9a270f8
固定awscli版本。
sih4sing5hong5 Jul 3, 2025
9118e6d
Travis CI用pip鬥awscli較khin-khó。
sih4sing5hong5 Jul 3, 2025
bc879d1
docker內ê path,shellcheck無法度檢查。
sih4sing5hong5 Jul 3, 2025
a532215
假設換做docker compose plugin。
sih4sing5hong5 Jul 3, 2025
89681a2
鬥compose plugin
sih4sing5hong5 Jul 4, 2025
498566a
Siu yaml mia
sih4sing5hong5 Jul 4, 2025
6e0cf51
用上新版cli
sih4sing5hong5 Jul 4, 2025
4c3e1f4
用ubuntu24.04
sih4sing5hong5 Jul 4, 2025
70bbcae
修CI pipe
sih4sing5hong5 Jul 4, 2025
c6d4d19
更新awscli版本2.22.35 koh ē-tàng走,2.23.0就無法度--ah。
sih4sing5hong5 Jul 4, 2025
f981112
換新版compose規格
sih4sing5hong5 Jul 4, 2025
66fe207
ubuntu24 kah nonroot
sih4sing5hong5 Jul 4, 2025
2c8f3a6
nonroot
sih4sing5hong5 Jul 4, 2025
8081163
grep -v有問題,改做comm
sih4sing5hong5 Jul 4, 2025
0dab285
grep -v有問題,改做comm
sih4sing5hong5 Jul 4, 2025
d5f5c9b
docker build過程mài印,CI較無負擔。
sih4sing5hong5 Jul 4, 2025
8220414
docker build過程mài印,CI較無負擔。
sih4sing5hong5 Jul 4, 2025
845eab7
處理comm tab
sih4sing5hong5 Jul 4, 2025
352dacb
修pipe
sih4sing5hong5 Jul 4, 2025
503a902
修pipe redirect
sih4sing5hong5 Jul 4, 2025
bb444de
攏愛--rm
sih4sing5hong5 Jul 4, 2025
69353b4
修正cleanup
sih4sing5hong5 Jul 4, 2025
05b3937
修pipe
sih4sing5hong5 Jul 4, 2025
068255f
Merge branch 'linter' into kingsin
sih4sing5hong5 Jul 4, 2025
7a2614f
sonarcloud
sih4sing5hong5 Jul 4, 2025
79f737a
整理dockerfile
sih4sing5hong5 Jul 4, 2025
09384e7
sonarcloud
sih4sing5hong5 Jul 4, 2025
4904543
加sonarcloud建議安全參數。
sih4sing5hong5 Jul 4, 2025
af92831
處理curl ca-certificates問題。
sih4sing5hong5 Jul 4, 2025
1acbafb
繼續試nonroot
sih4sing5hong5 Jul 4, 2025
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
26 changes: 26 additions & 0 deletions .gherkin-lintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"no-unnamed-features": "on",
"no-unnamed-scenarios": "on",
"no-unused-variables": "on",
"no-unused-variables": "on",
"no-dupe-feature-names": "on",
"no-dupe-scenario-names": "on",
"no-empty-background": "on",
"no-empty-file": "on",
"no-examples-in-scenarios": "on",
"no-scenario-outlines-without-examples": "on",
"no-multiple-empty-lines": "on",
"use-and": "on",
"indentation": [
"on", {}
],
"no-trailing-spaces": "on",
"new-line-at-eof": ["on", "yes"],
"one-space-between-tags": "on",

"no-files-without-scenarios": "off",
"allowed-tags": [
"on", {"tags": ["@caho還沒做", "@maherekayto做好了"]}
]
}

1 change: 1 addition & 0 deletions .shellcheckrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
disable=SC1091
226 changes: 133 additions & 93 deletions .travis.yml

Large diffs are not rendered by default.

37 changes: 18 additions & 19 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
FROM ubuntu:latest
FROM ubuntu:24.04
# https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst?plain=1

RUN groupadd --system --gid 138 docker
ARG DEBIAN_FRONTEND=noninteractive

RUN apt update && \
apt install -y \
ca-certificates \
curl \
gnupg \
lsb-release && \
mkdir -m 0755 -p /etc/apt/keyrings && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && \
apt install -y docker-ce-cli cron gnupg jq

RUN apt install -y unzip && \
apt install --no-install-recommends -y \
docker.io cron gnupg jq \
curl ca-certificates unzip && \
apt-get clean && \
mkdir /aws_build/ && \
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/aws_build/awscliv2.zip" && \
update-ca-certificates && \
curl -sSf "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.22.35.zip" -o "/aws_build/awscliv2.zip" && \
unzip -q /aws_build/awscliv2.zip -d /aws_build/ && \
/aws_build/aws/install && \
rm -rf /aws_build/

RUN useradd --uid 1001 nonroot --user-group && \
usermod -aG docker nonroot && \
touch /etc/environment && \
chown nonroot:nonroot /etc/environment && \
chmod u+s /usr/sbin/cron

WORKDIR /app/
COPY scripts/ /app/

CMD bash /app/start.sh
USER nonroot
CMD ["bash", "/app/start.sh"]
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Backup databases from dockerized PostgresSQL to any S3-compatible storage with a

## Quick Start

```
```yaml
version: '3'
services:
postgres:
Expand Down Expand Up @@ -46,7 +46,7 @@ services:

### Backup Multiple Databases Simultaneously

To backup multiple databases simultaneously, you can label the database containers that require backup with the `backup.postgres=true` label. The backup script will then identify all containers with this label and execute the backup command for each of them.
To backup multiple databases simultaneously, you can label the database containers that require backup with the `backup.postgres=true` label. The backup script will then identify all containers with this label and execute the backup command for each of them.

### Easy Configuration

Expand Down Expand Up @@ -75,6 +75,7 @@ The codebase undergoes automatic testing using Travis CI, which covers backup sc
## Configuration

### S3 Storage Configurations

- `S3_ENDPOINT_URL` (required): The S3 endpoint URL in the form of `http://<hostname>/` or `https://<hostname>/
`. Note that the scheme should be included.
- `S3_REGION`: The name of the S3 region (eg. `eu-west-1`). This may be optional depending on your storage vendor.
Expand All @@ -86,7 +87,6 @@ The codebase undergoes automatic testing using Travis CI, which covers backup sc

- `SCHEDULE`: The backup schedule specified in a string following [crontab syntax](https://www.man7.org/linux/man-pages/man5/crontab.5.html) where the five fields are minute, hour, day of month, month and day of week. If set to a blank string, the script will perform a instant backup and exit. The default value is a blank string.


### GPG Key

- `GPG_PUBLIC_KEY`: Base64-encoded GPG public key used in the encryption process. If not set, backup files will be uploaded and saved un-encrypted.
Expand All @@ -95,22 +95,28 @@ The codebase undergoes automatic testing using Travis CI, which covers backup sc

1. [Generate a new GPG key](https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key) if there is not any existing GPG key.
2. Encode GPG public key in base64 format and write it into the `.env` file.

```bash
GPG_PUBLIC_KEY=`gpg --armor --export <GPG key ID> | base64 --wrap 0`
echo "GPG_PUBLIC_KEY=${GPG_PUBLIC_KEY}" > .env
```

3. Export the private key and store it securely. The private key is needed when decrypting a backup file.

```bash
gpg --export-secret-keys --armor <GPG key ID> > <gpg-private-key.asc>
```

#### Decrypt a Backup File

1. Import the gpg private key if it hasn't been imported yet.

```bash
gpg --import <gpg-private-key.asc>
```

2. Decrypt the backup file to get the original SQL.

```bash
gpg --decrypt <postgres15.sql.gz.gpg> | zcat
```
Expand Down
4 changes: 4 additions & 0 deletions requirements_travisci.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
awscli
boto3~=1.35.0

awscli-local
45 changes: 45 additions & 0 deletions requirements_travisci.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile requirements_travisci.in
#
awscli==1.36.40
# via -r requirements_travisci.in
awscli-local==0.22.0
# via -r requirements_travisci.in
boto3==1.35.99
# via
# -r requirements_travisci.in
# localstack-client
botocore==1.35.99
# via
# awscli
# boto3
# s3transfer
colorama==0.4.6
# via awscli
docutils==0.16
# via awscli
jmespath==1.0.1
# via
# boto3
# botocore
localstack-client==2.10
# via awscli-local
pyasn1==0.6.1
# via rsa
python-dateutil==2.9.0.post0
# via botocore
pyyaml==6.0.2
# via awscli
rsa==4.7.2
# via awscli
s3transfer==0.10.4
# via
# awscli
# boto3
six==1.17.0
# via python-dateutil
urllib3==2.5.0
# via botocore
2 changes: 1 addition & 1 deletion scripts/backup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ all_containers=`docker container list \
for postgres_container_name in $all_containers
do
>&2 echo "Backuping ${postgres_container_name} is starting."
FILE_PATH=$(filepath ${postgres_container_name} 'now')
FILE_PATH=$(filepath "${postgres_container_name}" 'now')
docker exec "${postgres_container_name}" pg_dump -U postgres \
| gzip \
| ${ENCRYPT_COMMAND} \
Expand Down
18 changes: 11 additions & 7 deletions scripts/cleanup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ source /app/filepath.sh

CONTAINER_NAME=$1

FILE_PATH=$(filepath ${CONTAINER_NAME} "${MAX_PERIOD_IN_HOURS_TO_KEEP_EVERY_BACKUPS} hours ago")
FILE_PATH=$(filepath "${CONTAINER_NAME}" "${MAX_PERIOD_IN_HOURS_TO_KEEP_EVERY_BACKUPS} hours ago")

temp_dir=$(mktemp -d)
ALL_FILES="${temp_dir}/all.list"
Expand All @@ -29,7 +29,7 @@ aws s3api list-objects-v2 \
for day in $(seq 1 "${MAX_PERIOD_IN_DAYS_TO_KEEP_DAILY_BACKUPS}")
do
TARGET_DAY=`date "+%Y-%m-%d" --date "${day} days ago"`
FILE_PATH=$(filepath ${CONTAINER_NAME} "${TARGET_DAY}")
FILE_PATH=$(filepath "${CONTAINER_NAME}" "${TARGET_DAY}")
aws s3api list-objects-v2 \
--endpoint-url "${S3_ENDPOINT_URL}" \
--bucket "${S3_BUCKET}" \
Expand All @@ -43,7 +43,7 @@ done
for month in $(seq 1 "${MAX_PERIOD_IN_MONTHS_TO_KEEP_MONTHLY_BACKUPS}")
do
TARGET_DAY=`date "+%Y-%m-01" --date "${month} months ago"`
FILE_PATH=$(filepath ${CONTAINER_NAME} "${TARGET_DAY}")
FILE_PATH=$(filepath "${CONTAINER_NAME}" "${TARGET_DAY}")
aws s3api list-objects-v2 \
--endpoint-url "${S3_ENDPOINT_URL}" \
--bucket "${S3_BUCKET}" \
Expand All @@ -54,14 +54,18 @@ do
>> "${PRESERVE_FILES}"
done

for filename in `cat "${ALL_FILES}" \
| grep --invert-match --line-regexp --file "${PRESERVE_FILES}" \
| sed 's/^"\(.*\)"$/\1/g'`
sort -u "${ALL_FILES}" > "${temp_dir}/tmp.list"
mv "${temp_dir}/tmp.list" "${ALL_FILES}"
sort -u "${PRESERVE_FILES}" > "${temp_dir}/tmp.list"
mv "${temp_dir}/tmp.list" "${PRESERVE_FILES}"
comm -23 "${ALL_FILES}" "${PRESERVE_FILES}" \
| sed 's/^[[:space:]]*"\(.*\)"$/\1/g' \
| while IFS= read -r filename
do
aws s3api delete-object \
--endpoint-url "${S3_ENDPOINT_URL}" \
--bucket "${S3_BUCKET}" \
--key ${filename}
--key "${filename}"
done

rm -rf "${temp_dir}"
2 changes: 1 addition & 1 deletion scripts/crontab.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -euo pipefail

echo "PATH=${PATH}
${SCHEDULE} bash /app/backup.sh >> /var/log/cron.log 2>> /var/log/cron.error.log" \
${SCHEDULE} bash /app/backup.sh" \
| crontab -

cron -f -L 15
12 changes: 8 additions & 4 deletions scripts/filepath.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ set -euo pipefail

function filepath()
{
local container_name="$1"
local target_time="$2"
local DATE=`date "+%Y-%m-%d" --date "${target_time}"`
local TIME=`date "+%Y%m%dT%H%M" --date "${target_time}"`
local container_name
local target_time
local DATE
local TIME
container_name="$1"
target_time="$2"
DATE=`date "+%Y-%m-%d" --date "${target_time}"`
TIME=`date "+%Y%m%dT%H%M" --date "${target_time}"`
echo "${container_name}/${DATE}/${container_name}_${TIME}"
}
2 changes: 1 addition & 1 deletion scripts/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ if [ -z "${GPG_PUBLIC_KEY}" ]; then
>&2 echo 'There is not a GPG_PUBLIC_KEY, all backup files will not be encrypted.'
else
>&2 echo 'There is the GPG_PUBLIC_KEY, all backup files will be encrypted.'
echo ${GPG_PUBLIC_KEY} | base64 -d > ${GPG_PUBLIC_KEY_PATH}
echo "${GPG_PUBLIC_KEY}" | base64 -d > ${GPG_PUBLIC_KEY_PATH}
fi
if [ -z "${SCHEDULE}" ]; then
>&2 echo "multiple-databases-backup is starting."
Expand Down
12 changes: 12 additions & 0 deletions shellcheck.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
exit_code=0
shellcheck --severity=info scripts/*;
tsitkai="$?"
exit_code=$(( tsitkai != 0 ? tsitkai : exit_code))
while IFS= read -r -d '' file
do
shellcheck --severity=info "$file";
tsitkai="$?"
exit_code=$(( tsitkai != 0 ? tsitkai : exit_code))
done < <(find . -type f -name '*.sh' -not -path './venv/*' -not -path './scripts/*' -print0)
exit $(( exit_code == 0 ? 0 : 1))
1 change: 0 additions & 1 deletion tests/docker-compose-backup-encrypt.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
version: '3'
services:
backup:
build: ../
Expand Down
1 change: 0 additions & 1 deletion tests/docker-compose-backup-minute.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
version: '3'
services:
backup:
build: ../
Expand Down
1 change: 0 additions & 1 deletion tests/docker-compose-backup-strategy.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
version: '3'
services:
backup:
build: ../
Expand Down
1 change: 0 additions & 1 deletion tests/docker-compose-backup.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
version: '3'
services:
backup:
build: ../
Expand Down
1 change: 0 additions & 1 deletion tests/postgres15/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
version: '3'
services:
postgres:
image: postgres:15
Expand Down
1 change: 0 additions & 1 deletion tests/s3/docker-compose-localstack.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
version: '3'
services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
Expand Down
36 changes: 36 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[tox]
skipsdist = True

[flake8]
max-line-length = 79
exclude =
.git
.tox
venv

[testenv:yamllint]
deps =
yamllint
commands =
yamllint .

[testenv:flake8]
deps =
flake8
commands =
flake8 . --show-source --count

[testenv:pymarkdown]
deps =
pymarkdownlnt
commands =
pymarkdown \
--strict-config \
--disable-rules md013,md029 \
scan .

[testenv:shellcheck]
allowlist_externals =
bash
commands =
bash shellcheck.sh