2 Commits

Author SHA1 Message Date
3a058825db build step
All checks were successful
Build and Release Docker Image / Build and Push amd64 (push) Successful in 14s
Build and Release Docker Image / Build and Push arm64 (push) Successful in 27s
Build and Release Docker Image / Create and Push Multi-Arch Manifest (push) Successful in 18s
2025-02-04 21:21:36 +01:00
1f0df426be refactor script 2025-02-02 21:27:28 +01:00
6 changed files with 111 additions and 197 deletions

View File

@@ -1,111 +1,86 @@
name: CD
name: Build and Release Docker Image
on:
push:
branches:
- main
env:
DOCKER_REGISTRY: gitea.t000-n.de
- v2
jobs:
check-changes:
name: Check changes
runs-on: ubuntu-latest
outputs:
changes: ${{ steps.filter.outputs.code }}
build_amd64:
name: Build and Push amd64
runs-on: [ubuntu-latest, linux_amd64]
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checkout repository
uses: actions/checkout@v4
- name: Get changed files
id: filter
uses: dorny/paths-filter@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
filters: |
code:
- 'src/**'
- 'Dockerfile'
- 'gitea/workflows/**'
build_and_push:
name: Build and push
needs:
- check-changes
if: ${{ needs.check-changes.outputs.changes != '0' }}
strategy:
matrix:
arch:
- amd64
- arm64
runs-on:
- ubuntu-latest
- linux_${{ matrix.arch }}
steps:
- uses: actions/checkout@v5
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ secrets.REGISTRY_USER }}
registry: gitea.t000-n.de
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- id: meta
run: |
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}' | tr '[:upper:]' '[:lower:]') >> $GITHUB_OUTPUT
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
- uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: linux/${{ matrix.arch }}
push: true
provenance: false
tags: |
${{ env.DOCKER_REGISTRY }}/t.behrendt/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}-${{ matrix.arch }}
create_tag:
name: Create tag
needs:
- check-changes
if: ${{ needs.check-changes.outputs.changes != '0' }}
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.tag.outputs.new-tag }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: https://gitea.t000-n.de/t.behrendt/conventional-semantic-git-tag-increment@0.0.2
id: tag
with:
token: ${{ secrets.GITEA_TOKEN }}
- run: |
git tag ${{ steps.tag.outputs.new-tag }}
git push origin ${{ steps.tag.outputs.new-tag }}
- name: Set output
- name: Build Docker image for amd64
run: |
echo "tag=${{ steps.tag.outputs.new-tag }}" >> $GITHUB_OUTPUT
docker build \
--platform linux/amd64 \
-f Dockerfile \
-t gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-amd64 \
.
create_manifest:
name: Create manifest
needs:
- build_and_push
- create_tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- id: meta
- name: Push Docker image for amd64
run: |
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}' | tr '[:upper:]' '[:lower:]') >> $GITHUB_OUTPUT
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
- uses: docker/login-action@v3
docker push gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-amd64
build_arm64:
name: Build and Push arm64
runs-on: [ubuntu-latest, linux_arm64]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ secrets.REGISTRY_USER }}
registry: gitea.t000-n.de
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- run: |
docker manifest create ${{ env.DOCKER_REGISTRY }}/t.behrendt/${{ steps.meta.outputs.REPO_NAME }}:${{ needs.create_tag.outputs.tag }} \
${{ env.DOCKER_REGISTRY }}/t.behrendt/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}-amd64 \
${{ env.DOCKER_REGISTRY }}/t.behrendt/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}-arm64
docker manifest push ${{ env.DOCKER_REGISTRY }}/t.behrendt/${{ steps.meta.outputs.REPO_NAME }}:${{ needs.create_tag.outputs.tag }}
- name: Build Docker image for arm64
run: |
docker build \
--platform linux/arm64 \
-f Dockerfile \
-t gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-arm64 \
.
- name: Push Docker image for arm64
run: |
docker push gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-arm64
manifest:
name: Create and Push Multi-Arch Manifest
needs: [build_amd64, build_arm64]
runs-on: ubuntu-latest
steps:
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: gitea.t000-n.de
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Create and push manifest with git SHA
run: |
docker manifest create gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }} \
gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-amd64 \
gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-arm64
docker manifest push gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}
- name: Optionally tag manifest as latest
if: ${{ inputs.latest == true }}
run: |
docker manifest create gitea.t000-n.de/t.behrendt/backupsidecar:latest \
gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-amd64 \
gitea.t000-n.de/t.behrendt/backupsidecar:${{ github.sha }}-arm64
docker manifest push gitea.t000-n.de/t.behrendt/backupsidecar:latest

View File

@@ -1,24 +0,0 @@
name: CI
on:
pull_request:
jobs:
build:
name: Build Docker image
runs-on:
- ubuntu-latest
- linux_amd64
steps:
- uses: actions/checkout@v5
- uses: docker/setup-buildx-action@v3
- name: Build image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
push: false
provenance: false
tags: |
backupsidecar:ci-test

View File

@@ -1,4 +1,4 @@
FROM alpine:3.22
FROM alpine:3.18
RUN apk update && apk add --no-cache \
bash \

View File

@@ -1,6 +1,6 @@
# BackupSidecar
BackupSidecar is a lightweight backup solution designed to run as a cron job in Kubernetes. It automates backups using Restic and supports both directory and PostgreSQL database backups. Optional notifications can be sent via Gotify to keep you informed of backup results.
BackupSidecar is a lightweight backup solution designed to run as a cron job in Kubernetes. It automates backups using Restic and supports both directory and PostgreSQL database backups. Notifications are sent via Gotify to keep you informed of backup results.
## Configuration
@@ -10,32 +10,31 @@ BackupSidecar is configured through environment variables. Below is a breakdown
These variables apply to both directory and PostgreSQL backups.
- **`BACKUP_MODE`** _(optional)_ - Defines the backup type (`directory` or `postgres`). Defaults to `directory`.
- **`RESTIC_PASSWORD`** _(required)_ - The encryption password for Restic.
- **`RESTIC_REPOSITORY`** _(required)_ - The URI of the Restic repository (e.g., `rest:http://your-rest-server:8000/backup`).
- **`RESTIC_REST_USERNAME`** _(optional)_ - The username for REST server authentication.
- **`RESTIC_REST_PASSWORD`** _(optional)_ - The password for REST server authentication.
- **`ENABLE_GOTIFY`** _(optional)_ - Enable Gotify notifications. Set to `true` to enable, any other value or unset disables notifications. Defaults to `true`.
- **`GOTIFYHOST`** _(required when ENABLE_GOTIFY=true)_ - The Gotify server URL.
- **`GOTIFYTOKEN`** _(required when ENABLE_GOTIFY=true)_ - The API token for Gotify.
- **`GOTIFYTOPIC`** _(required when ENABLE_GOTIFY=true)_ - The topic under which backup notifications will be sent.
- **`BACKUP_MODE`** _(optional)_ Defines the backup type (`directory` or `postgres`). Defaults to `directory`.
- **`RESTIC_PASSWORD`** _(required)_ The encryption password for Restic.
- **`RESTIC_REPOSITORY`** _(required)_ The URI of the Restic repository (e.g., `rest:http://your-rest-server:8000/backup`).
- **`RESTIC_REST_USERNAME`** _(optional)_ The username for REST server authentication.
- **`RESTIC_REST_PASSWORD`** _(optional)_ The password for REST server authentication.
- **`GOTIFYHOST`** _(required)_ The Gotify server URL.
- **`GOTIFYTOKEN`** _(required)_ The API token for Gotify.
- **`GOTIFYTOPIC`** _(required)_ The topic under which backup notifications will be sent.
### Directory Backup
When running in `directory` mode, the following variable must be set:
- **`SOURCEDIR`** _(required)_ - The path of the directory to be backed up.
- **`SOURCEDIR`** _(required)_ The path of the directory to be backed up.
### PostgreSQL Backup
For `postgres` mode, the following database-related variables are required:
- **`PGHOST`** _(required)_ - The hostname of the PostgreSQL server.
- **`PGDATABASE`** _(required)_ - The name of the database to back up.
- **`PGUSER`** _(required)_ - The PostgreSQL username.
- **`PGPORT`** _(optional)_ - The port for PostgreSQL (defaults to `5432`).
- **`PGPASSWORD`** _(optional)_ - The password for authentication. Setting this prevents interactive prompts.
- **`PG_DUMP_ARGS`** _(optional)_ - Additional flags for `pg_dump`.
- **`PGHOST`** _(required)_ The hostname of the PostgreSQL server.
- **`PGDATABASE`** _(required)_ The name of the database to back up.
- **`PGUSER`** _(required)_ The PostgreSQL username.
- **`PGPORT`** _(optional)_ The port for PostgreSQL (defaults to `5432`).
- **`PGPASSWORD`** _(optional)_ The password for authentication. Setting this prevents interactive prompts.
- **`PG_DUMP_ARGS`** _(optional)_ Additional flags for `pg_dump`.
## Dependencies
@@ -51,23 +50,16 @@ Ensure the following commands are available in the container:
Example Kubernetes CronJob manifest for running BackupSidecar as a cron job for directory backups in minimal configuration:
```yaml
apiVersion: batch/v1
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: backupsidecar-cron
namespace: authentik
spec:
schedule: "0 7 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 3
schedule: "0 2 * * *" # Run daily at 2:00 AM
jobTemplate:
spec:
backoffLimit: 3
activeDeadlineSeconds: 300
template:
spec:
restartPolicy: OnFailure
containers:
- name: backupsidecar
image: backupsidecar:latest
@@ -83,8 +75,6 @@ spec:
value: "directory" # or "postgres"
- name: SOURCEDIR
value: "/data/source"
- name: ENABLE_GOTIFY
value: "true"
- name: GOTIFYHOST
value: "http://gotify.example.com"
- name: GOTIFYTOKEN
@@ -107,17 +97,10 @@ spec:
## Notifications
The script can send success or failure notifications via Gotify when enabled. To enable notifications, set `ENABLE_GOTIFY=true` and provide the required Gotify configuration variables (`GOTIFYHOST`, `GOTIFYTOKEN`, `GOTIFYTOPIC`). When notifications are disabled, backup status messages are still logged to the console.
The script sends success or failure notifications via Gotify.
Example success notification:
```
Backup successful. Snapshot 56ff6a909a44e01f67d2d88f9a76aa713d437809d7ed14a2361e28893f38befb: files new: 1, files changed: 0, data added: 1019 bytes in 0.277535184 sec
```
When Gotify is disabled, you'll see a single message at startup indicating notifications are disabled, followed by normal backup status messages:
```
2024-01-15T10:30:00 - Gotify notifications disabled. Backup status will be logged to console only.
2024-01-15T10:30:05 - Backup successful. Snapshot 56ff6a909a44e01f67d2d88f9a76aa713d437809d7ed14a2361e28893f38befb: files new: 1, files changed: 0, data added: 1019 bytes in 0.277535184 sec
```

View File

@@ -1,3 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

View File

@@ -1,20 +1,6 @@
#!/bin/bash
set -euo pipefail
#######################################
# Date format for logging.
#######################################
LOG_DATE_FORMAT="%Y-%m-%dT%T"
#######################################
# Log a message with a timestamp.
# Arguments:
# Message to log.
#######################################
log() {
echo "$(date +"$LOG_DATE_FORMAT") - $*"
}
#######################################
# Determine backup mode from the environment only.
# Valid values: "directory" or "postgres".
@@ -32,7 +18,7 @@ fi
for cmd in "${REQUIRED_CMDS[@]}"; do
if ! command -v "$cmd" &>/dev/null; then
log "Error: Required command '$cmd' is not installed."
echo "Error: Required command '$cmd' is not installed." >&2
exit 1
fi
done
@@ -40,17 +26,10 @@ done
#######################################
# Validate common required environment variables.
#######################################
# Gotify notification settings (optional).
# Set ENABLE_GOTIFY to "true" to enable notifications, any other value or unset disables them.
ENABLE_GOTIFY="${ENABLE_GOTIFY:-true}"
if [ "$ENABLE_GOTIFY" = "true" ]; then
: "${GOTIFYHOST:?Environment variable GOTIFYHOST is not set (required when ENABLE_GOTIFY=true)}"
: "${GOTIFYTOKEN:?Environment variable GOTIFYTOKEN is not set (required when ENABLE_GOTIFY=true)}"
: "${GOTIFYTOPIC:?Environment variable GOTIFYTOPIC is not set (required when ENABLE_GOTIFY=true)}"
else
log "Gotify notifications disabled. Backup status will be logged to console only."
fi
# Gotify notification settings.
: "${GOTIFYHOST:?Environment variable GOTIFYHOST is not set}"
: "${GOTIFYTOKEN:?Environment variable GOTIFYTOKEN is not set}"
: "${GOTIFYTOPIC:?Environment variable GOTIFYTOPIC is not set}"
# Restic encryption password.
: "${RESTIC_PASSWORD:?Environment variable RESTIC_PASSWORD is not set}"
@@ -83,11 +62,23 @@ case "$BACKUP_MODE" in
esac
#######################################
# Build the Gotify URL (only if Gotify is enabled).
# Build the Gotify URL.
#######################################
if [ "$ENABLE_GOTIFY" = "true" ]; then
GOTIFYURL="${GOTIFYHOST}/message?token=${GOTIFYTOKEN}"
fi
#######################################
# Date format for logging.
#######################################
LOG_DATE_FORMAT="%Y-%m-%dT%T"
#######################################
# Log a message with a timestamp.
# Arguments:
# Message to log.
#######################################
log() {
echo "$(date +"$LOG_DATE_FORMAT") - $*"
}
#######################################
# Send a notification via Gotify.
@@ -96,13 +87,6 @@ fi
#######################################
send_notification() {
local message="$1"
# Only send notification if Gotify is enabled
if [ "$ENABLE_GOTIFY" != "true" ]; then
log "$message"
return 0
fi
if ! curl -s -X POST "$GOTIFYURL" -F "title=${GOTIFYTOPIC}" -F "message=${message}" >/dev/null; then
log "Warning: Failed to send notification with message: ${message}"
fi
@@ -116,10 +100,9 @@ send_notification() {
#######################################
run_restic_backup() {
local source_dir="$1"
cd "${source_dir}"
log "Starting backup of '${source_dir}' to repository ${RESTIC_REPOSITORY}"
# Capture both stdout and stderr in a variable
backup_output=$(restic -r "${RESTIC_REPOSITORY}" backup --no-cache --json --verbose . 2>&1)
backup_output=$(restic -r "${RESTIC_REPOSITORY}" backup --no-cache --json --verbose "${source_dir}" 2>&1)
# Optionally, also print the output to the console:
echo "$backup_output"
# Parse the JSON lines output for the summary message