From 012f6392a772d781c8debb1fb4f5f9dc1e085e4c Mon Sep 17 00:00:00 2001 From: Jonas Kaninda Date: Sun, 4 Aug 2024 11:19:11 +0200 Subject: [PATCH 1/3] fix: Fix AWS S3 and SSH backup in scheduled mode on Docker and Docker Swarm --- .github/workflows/build.yml | 32 ++++++++++++++++++++++++++++++++ Makefile | 8 +++++--- docker/Dockerfile | 1 + docker/supervisord.conf | 6 ++---- pkg/backup.go | 22 +++++++++++++--------- pkg/scripts.go | 13 +++---------- pkg/var.go | 11 +++++++++-- utils/logger.go | 1 + utils/s3.go | 5 +---- 9 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..aa2a1bc --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,32 @@ +name: Build +on: + push: + branches: ['develop'] +env: + BUILDKIT_IMAGE: jkaninda/pg-bkup +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v3 + with: + push: true + file: "./docker/Dockerfile" + platforms: linux/amd64,linux/arm64,linux/arm/v7 + tags: | + "${{env.BUILDKIT_IMAGE}}:develop-${{ github.sha }}" + diff --git a/Makefile b/Makefile index 03bd69e..f5f118e 100644 --- a/Makefile +++ b/Makefile @@ -29,10 +29,10 @@ docker-run-scheduled: docker-build docker-run-scheduled-s3: docker-build - docker run --rm --network web --user 1000:1000 --name pg-bkup -v "./backup:/backup" -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "ACCESS_KEY=${ACCESS_KEY}" -e "SECRET_KEY=${SECRET_KEY}" -e "BUCKET_NAME=${BUCKET_NAME}" -e "S3_ENDPOINT=${S3_ENDPOINT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage s3 --mode scheduled --path /custom-path --period "* * * * *" + docker run --rm --network web --name pg-bkup -v "./backup:/backup" -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "ACCESS_KEY=${ACCESS_KEY}" -e "SECRET_KEY=${SECRET_KEY}" -e "BUCKET_NAME=${BUCKET_NAME}" -e "S3_ENDPOINT=${S3_ENDPOINT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage s3 --mode scheduled --path /custom-path --period "* * * * *" docker-run-s3: docker-build - docker run --rm --network web --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "ACCESS_KEY=${ACCESS_KEY}" -e "SECRET_KEY=${SECRET_KEY}" -e "AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME}" -e "AWS_S3_ENDPOINT=${AWS_S3_ENDPOINT}" -e "AWS_REGION=eu2" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage s3 #--path /custom-path + docker run --rm --network web --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "ACCESS_KEY=${ACCESS_KEY}" -e "SECRET_KEY=${SECRET_KEY}" -e "AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME}" -e "S3_ENDPOINT=${AWS_S3_ENDPOINT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage s3 --mode scheduled --path custom-path --period "* * * * *" docker-restore-s3: docker-build @@ -41,8 +41,10 @@ docker-restore-s3: docker-build docker-run-ssh: docker-build docker run --rm --network web --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "SSH_USER=${SSH_USER}" -e "SSH_HOST_NAME=${SSH_HOST_NAME}" -e "SSH_REMOTE_PATH=${SSH_REMOTE_PATH}" -e "SSH_PASSWORD=${SSH_PASSWORD}" -e "SSH_PORT=${SSH_PORT}" -e "SSH_IDENTIFY_FILE=${SSH_IDENTIFY_FILE}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage ssh +docker-run-scheduled-ssh: docker-build + docker run --rm --network web --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "SSH_USER=${SSH_USER}" -e "SSH_HOST_NAME=${SSH_HOST_NAME}" -e "SSH_REMOTE_PATH=${SSH_REMOTE_PATH}" -e "SSH_PASSWORD=${SSH_PASSWORD}" -e "SSH_PORT=${SSH_PORT}" -e "SSH_IDENTIFY_FILE=${SSH_IDENTIFY_FILE}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage ssh --mode scheduled --period "* * * * *" docker-restore-ssh: docker-build - docker run --rm --network web --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "SSH_USER=${SSH_USER}" -e "SSH_HOST_NAME=${SSH_HOST_NAME}" -e "SSH_REMOTE_PATH=${SSH_REMOTE_PATH}" -e "SSH_PASSWORD=${SSH_PASSWORD}" -e "SSH_PORT=${SSH_PORT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" -e "SSH_IDENTIFY_FILE=${SSH_IDENTIFY_FILE}" ${IMAGE_NAME} bkup restore --storage ssh -f data_20240731_200104.sql.gz.gpg + docker run --rm --network web --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "SSH_USER=${SSH_USER}" -e "SSH_HOST_NAME=${SSH_HOST_NAME}" -e "SSH_REMOTE_PATH=${SSH_REMOTE_PATH}" -e "SSH_PASSWORD=${SSH_PASSWORD}" -e "SSH_PORT=${SSH_PORT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" -e "SSH_IDENTIFY_FILE=${SSH_IDENTIFY_FILE}" ${IMAGE_NAME} bkup restore --storage ssh -f ${FILE_NAME} run-docs: cd docs && bundle exec jekyll serve -H 0.0.0.0 -t \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 2bd9779..9b47460 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,6 +20,7 @@ ENV AWS_S3_ENDPOINT="" ENV AWS_S3_BUCKET_NAME="" ENV AWS_ACCESS_KEY="" ENV AWS_SECRET_KEY="" +ENV AWS_S3_PATH="" ENV AWS_REGION="us-west-2" ENV AWS_DISABLE_SSL="false" ENV GPG_PASSPHRASE="" diff --git a/docker/supervisord.conf b/docker/supervisord.conf index 84b35a1..414b337 100644 --- a/docker/supervisord.conf +++ b/docker/supervisord.conf @@ -1,13 +1,11 @@ [supervisord] -nodaemon=true +nodemon=true user=root logfile=/var/log/supervisor/supervisord.log -pidfile=/var/run/supervisord.pid +pipfile=/var/run/supervisord.pid [program:cron] command = /bin/bash -c "declare -p | grep -Ev '^declare -[[:alpha:]]*r' > /run/supervisord.env && /usr/sbin/cron -f -L 15" autostart=true -autorestart=true -user = root stderr_logfile=/var/log/cron.err.log stdout_logfile=/var/log/cron.out.log \ No newline at end of file diff --git a/pkg/backup.go b/pkg/backup.go index 3d2b30c..8248ecb 100644 --- a/pkg/backup.go +++ b/pkg/backup.go @@ -25,7 +25,6 @@ func StartBackup(cmd *cobra.Command) { utils.GetEnv(cmd, "period", "SCHEDULE_PERIOD") //Get flag value and set env - s3Path := utils.GetEnv(cmd, "path", "AWS_S3_PATH") remotePath := utils.GetEnv(cmd, "path", "SSH_REMOTE_PATH") storage = utils.GetEnv(cmd, "storage", "STORAGE") file = utils.GetEnv(cmd, "file", "FILE_NAME") @@ -35,6 +34,8 @@ func StartBackup(cmd *cobra.Command) { executionMode, _ = cmd.Flags().GetString("mode") dbName = os.Getenv("DB_NAME") gpgPassphrase := os.Getenv("GPG_PASSPHRASE") + _ = utils.GetEnv(cmd, "path", "AWS_S3_PATH") + // if gpgPassphrase != "" { encryption = true @@ -49,7 +50,7 @@ func StartBackup(cmd *cobra.Command) { if executionMode == "default" { switch storage { case "s3": - s3Backup(backupFileName, s3Path, disableCompression, prune, backupRetention, encryption) + s3Backup(backupFileName, disableCompression, prune, backupRetention, encryption) case "local": localBackup(backupFileName, disableCompression, prune, backupRetention, encryption) case "ssh", "remote": @@ -61,7 +62,7 @@ func StartBackup(cmd *cobra.Command) { } } else if executionMode == "scheduled" { - scheduledMode() + scheduledMode(storage) } else { utils.Fatal("Error, unknown execution mode!") } @@ -69,7 +70,7 @@ func StartBackup(cmd *cobra.Command) { } // Run in scheduled mode -func scheduledMode() { +func scheduledMode(storage string) { fmt.Println() fmt.Println("**********************************") @@ -77,6 +78,7 @@ func scheduledMode() { fmt.Println("***********************************") utils.Info("Running in Scheduled mode") utils.Info("Execution period %s ", os.Getenv("SCHEDULE_PERIOD")) + utils.Info("Storage type %s ", storage) //Test database connexion utils.TestDatabaseConnection() @@ -101,8 +103,9 @@ func scheduledMode() { utils.Info("Supervisor stopped.") } }() + if _, err := os.Stat(cronLogFile); os.IsNotExist(err) { - utils.Fatal("Log file %s does not exist.", cronLogFile) + utils.Fatal(fmt.Sprintf("Log file %s does not exist.", cronLogFile)) } t, err := tail.TailFile(cronLogFile, tail.Config{Follow: true}) if err != nil { @@ -213,8 +216,9 @@ func localBackup(backupFileName string, disableCompression bool, prune bool, bac } } -func s3Backup(backupFileName string, s3Path string, disableCompression bool, prune bool, backupRetention int, encrypt bool) { +func s3Backup(backupFileName string, disableCompression bool, prune bool, backupRetention int, encrypt bool) { bucket := utils.GetEnvVariable("AWS_S3_BUCKET_NAME", "BUCKET_NAME") + s3Path := utils.GetEnvVariable("AWS_S3_PATH", "S3_PATH") utils.Info("Backup database to s3 storage") //Backup database BackupDatabase(backupFileName, disableCompression) @@ -256,7 +260,7 @@ func sshBackup(backupFileName, remotePath string, disableCompression bool, prune finalFileName = fmt.Sprintf("%s.%s", backupFileName, "gpg") } utils.Info("Uploading backup file to remote server...") - utils.Info("Backup name is ", backupFileName) + utils.Info("Backup name is %s", backupFileName) err := CopyToRemote(finalFileName, remotePath) if err != nil { utils.Fatal("Error uploading file to the remote server: %s ", err) @@ -266,7 +270,7 @@ func sshBackup(backupFileName, remotePath string, disableCompression bool, prune //Delete backup file from tmp folder err = utils.DeleteFile(filepath.Join(tmpPath, finalFileName)) if err != nil { - utils.Error("Error deleting file:", err) + utils.Error("Error deleting file: %v", err) } if prune { @@ -282,7 +286,7 @@ func encryptBackup(backupFileName string) { gpgPassphrase := os.Getenv("GPG_PASSPHRASE") err := Encrypt(filepath.Join(tmpPath, backupFileName), gpgPassphrase) if err != nil { - utils.Fatal("Error during encrypting backup %s", err) + utils.Fatal("Error during encrypting backup %v", err) } } diff --git a/pkg/scripts.go b/pkg/scripts.go index 8370273..4c1e7f6 100644 --- a/pkg/scripts.go +++ b/pkg/scripts.go @@ -24,17 +24,10 @@ func CreateCrontabScript(disableCompression bool, storage string) { var scriptContent string - if storage == "s3" { - scriptContent = fmt.Sprintf(`#!/usr/bin/env bash + scriptContent = fmt.Sprintf(`#!/usr/bin/env bash set -e -bkup backup --dbname %s --port %s --storage s3 --path %s %v -`, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), os.Getenv("S3_PATH"), disableC) - } else { - scriptContent = fmt.Sprintf(`#!/usr/bin/env bash -set -e -bkup backup --dbname %s --port %s %v -`, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), disableC) - } +bkup backup --dbname %s --port %s --storage %s %v +`, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), storage, disableC) if err := utils.WriteToFile(backupCronFile, scriptContent); err != nil { utils.Fatal("Error writing to %s: %v\n", backupCronFile, err) diff --git a/pkg/var.go b/pkg/var.go index fb2619a..f415d89 100644 --- a/pkg/var.go +++ b/pkg/var.go @@ -1,7 +1,5 @@ package pkg -const s3MountPath string = "/s3mnt" -const s3fsPasswdFile string = "/etc/passwd-s3fs" const cronLogFile = "/var/log/pg-bkup.log" const tmpPath = "/tmp/backup" const backupCronFile = "/usr/local/bin/backup_cron.sh" @@ -37,3 +35,12 @@ var sshVars = []string{ "SSH_HOST_NAME", "SSH_PORT", } + +// AwsVars Required environment variables for AWS S3 storage +var awsVars = []string{ + "AWS_S3_ENDPOINT", + "AWS_S3_BUCKET_NAME", + "AWS_ACCESS_KEY", + "AWS_SECRET_KEY", + "AWS_REGION", +} diff --git a/utils/logger.go b/utils/logger.go index 990638a..6adcd2f 100644 --- a/utils/logger.go +++ b/utils/logger.go @@ -55,4 +55,5 @@ func Fatal(msg string, args ...any) { fmt.Printf("%s ERROR: %s\n", currentTime, formattedMessage) } os.Exit(1) + os.Kill.Signal() } diff --git a/utils/s3.go b/utils/s3.go index 5ff27bd..1c4b7ae 100644 --- a/utils/s3.go +++ b/utils/s3.go @@ -24,8 +24,6 @@ func CreateSession() (*session.Session, error) { "AWS_ACCESS_KEY", "AWS_SECRET_KEY", "AWS_REGION", - "AWS_REGION", - "AWS_REGION", } endPoint := GetEnvVariable("AWS_S3_ENDPOINT", "S3_ENDPOINT") @@ -41,8 +39,7 @@ func CreateSession() (*session.Session, error) { err = CheckEnvVars(awsVars) if err != nil { - Error("Error checking environment variables\n: %s", err) - os.Exit(1) + Fatal("Error checking environment variables\n: %s", err) } // Configure to use MinIO Server s3Config := &aws.Config{ From 2f6f9393e956ce72d75fbe16846fab4214e2de26 Mon Sep 17 00:00:00 2001 From: Jonas Kaninda Date: Sun, 4 Aug 2024 12:38:52 +0200 Subject: [PATCH 2/3] fix: fix supervisord, add container entrypoint --- Makefile | 2 +- docker/Dockerfile | 3 ++- docker/supervisord.conf | 6 ++++-- pkg/scripts.go | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index f5f118e..5b8864f 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ docker-run-scheduled: docker-build docker-run-scheduled-s3: docker-build - docker run --rm --network web --name pg-bkup -v "./backup:/backup" -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "ACCESS_KEY=${ACCESS_KEY}" -e "SECRET_KEY=${SECRET_KEY}" -e "BUCKET_NAME=${BUCKET_NAME}" -e "S3_ENDPOINT=${S3_ENDPOINT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage s3 --mode scheduled --path /custom-path --period "* * * * *" + docker run --rm --network web --name pg-bkup -v "./backup:/backup" -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "ACCESS_KEY=${ACCESS_KEY}" -e "SECRET_KEY=${SECRET_KEY}" -e "BUCKET_NAME=${BUCKET_NAME}" -e "S3_ENDPOINT=${AWS_S3_ENDPOINT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} backup --storage s3 --mode scheduled --path /custom-path --period "* * * * *" docker-run-s3: docker-build docker run --rm --network web --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" -e "ACCESS_KEY=${ACCESS_KEY}" -e "SECRET_KEY=${SECRET_KEY}" -e "AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME}" -e "S3_ENDPOINT=${AWS_S3_ENDPOINT}" -e "GPG_PASSPHRASE=${GPG_PASSPHRASE}" ${IMAGE_NAME} bkup backup --storage s3 --mode scheduled --path custom-path --period "* * * * *" diff --git a/docker/Dockerfile b/docker/Dockerfile index 9b47460..85cceef 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -64,4 +64,5 @@ RUN ln -s /usr/local/bin/pg-bkup /usr/local/bin/bkup ADD docker/supervisord.conf /etc/supervisor/supervisord.conf -WORKDIR $WORKDIR \ No newline at end of file +WORKDIR $WORKDIR +ENTRYPOINT ["/usr/local/bin/pg-bkup"] diff --git a/docker/supervisord.conf b/docker/supervisord.conf index 414b337..84b35a1 100644 --- a/docker/supervisord.conf +++ b/docker/supervisord.conf @@ -1,11 +1,13 @@ [supervisord] -nodemon=true +nodaemon=true user=root logfile=/var/log/supervisor/supervisord.log -pipfile=/var/run/supervisord.pid +pidfile=/var/run/supervisord.pid [program:cron] command = /bin/bash -c "declare -p | grep -Ev '^declare -[[:alpha:]]*r' > /run/supervisord.env && /usr/sbin/cron -f -L 15" autostart=true +autorestart=true +user = root stderr_logfile=/var/log/cron.err.log stdout_logfile=/var/log/cron.out.log \ No newline at end of file diff --git a/pkg/scripts.go b/pkg/scripts.go index 4c1e7f6..9e0f637 100644 --- a/pkg/scripts.go +++ b/pkg/scripts.go @@ -26,7 +26,7 @@ func CreateCrontabScript(disableCompression bool, storage string) { scriptContent = fmt.Sprintf(`#!/usr/bin/env bash set -e -bkup backup --dbname %s --port %s --storage %s %v +/usr/local/bin/pg-bkup backup --dbname %s --port %s --storage %s %v `, os.Getenv("DB_NAME"), os.Getenv("DB_PORT"), storage, disableC) if err := utils.WriteToFile(backupCronFile, scriptContent); err != nil { From ac3021033a9316ecf009261ab16b56fc9f3414f6 Mon Sep 17 00:00:00 2001 From: Jonas Kaninda Date: Sun, 4 Aug 2024 12:46:49 +0200 Subject: [PATCH 3/3] Remove entrypoint --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 85cceef..e86f322 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -65,4 +65,4 @@ RUN ln -s /usr/local/bin/pg-bkup /usr/local/bin/bkup ADD docker/supervisord.conf /etc/supervisor/supervisord.conf WORKDIR $WORKDIR -ENTRYPOINT ["/usr/local/bin/pg-bkup"] +#ENTRYPOINT ["/usr/local/bin/pg-bkup"]