From 936805a8c7bdbf33ada1caee439efdbc1c6af97e Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Wed, 27 Aug 2025 15:22:41 +0700 Subject: [PATCH] init --- .dockerignore | 2 + .env.example | 9 +++++ .gitea/workflows/docker-build.yml | 61 +++++++++++++++++++++++++++++++ .gitignore | 2 + Dockerfile | 29 +++++++++++++++ README.md | 39 ++++++++++++++++++++ docker-build.sh | 6 +++ docker-compose.yml | 17 +++++++++ scripts/backup.sh | 15 ++++++++ scripts/deleteold.sh | 24 ++++++++++++ scripts/entrypoint.sh | 6 +++ scripts/minio_uploader.sh | 18 +++++++++ 12 files changed, 228 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .gitea/workflows/docker-build.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100755 docker-build.sh create mode 100644 docker-compose.yml create mode 100644 scripts/backup.sh create mode 100644 scripts/deleteold.sh create mode 100644 scripts/entrypoint.sh create mode 100644 scripts/minio_uploader.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..781dc31 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +docker-compose.yml +README.md diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dd1919c --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +DB_FILE=/data/db.sqlite +CRONTAB="00 06 * * *" +DELETE_AFTER=10 +TZ=Asia/Novosibirsk +MINIO_PATH=myminio://sqlite/master/ +MINIO_ACCOUNT_ID=account +MINIO_APPLICATION_KEY=key +MINIO_ENDPOINT=https://s3.domain.ru +MINIO_LOCATION=ru-nsk diff --git a/.gitea/workflows/docker-build.yml b/.gitea/workflows/docker-build.yml new file mode 100644 index 0000000..9b887f2 --- /dev/null +++ b/.gitea/workflows/docker-build.yml @@ -0,0 +1,61 @@ +name: docker-build + +on: + push: + tags: + - "*" + +permissions: + contents: read + packages: write + +jobs: + build: + runs-on: docker + env: + REGISTRY: hub.realmanual.ru + IMAGE_NAME: pub/sqlite-backup/backup + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Ensure tag commit is reachable from main + shell: bash + run: | + set -euo pipefail + git fetch --no-tags --depth=0 origin main + if git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "Commit is on main history. Proceeding." + else + echo "Tag commit is not from main. Skipping build." >&2 + exit 0 + fi + + - name: Extract tag + id: vars + shell: bash + run: | + TAG_REF="${GITHUB_REF#refs/tags/}" + echo "tag=$TAG_REF" >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITEA_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: true + platforms: linux/amd64 + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.tag }} + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de03f38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..53f0de7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +FROM alpine:latest + +ENV TZ=UTC +LABEL maintainer="Vassiliy Yegorov " + +RUN apk add --no-cache \ + sqlite \ + curl \ + bash \ + tzdata \ + openssl + +RUN curl -O https://downloads.rclone.org/rclone-current-linux-amd64.zip && \ + unzip rclone-current-linux-amd64.zip && \ + cd rclone-*-linux-amd64 && \ + cp rclone /usr/bin/ && \ + chown root:root /usr/bin/rclone && \ + chmod 755 /usr/bin/rclone + +RUN export TZ=/usr/share/zoneinfo/${TZ} + +RUN mkdir -p scripts +COPY scripts/ /scripts + +WORKDIR /scripts + +RUN chmod +x /scripts/* + +ENTRYPOINT ["/scripts/entrypoint.sh"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..1819c10 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# бекапирование sqlite в minio + +```yaml +services: + sqlite_backup: + image: hub.realmanual.ru/pub/sqlite-backup/backup:latest + container_name: sqlite_backup + restart: always + volumes: + - ./var/lib/data/:/data + environment: + - DB_FILE + - CRONTAB + - DELETE_AFTER + - TZ + - MINIO_PATH + - MINIO_ACCOUNT_ID + - MINIO_APPLICATION_KEY + - MINIO_ENDPOINT + - MINIO_LOCATION +``` + +пример .env + +```bash +DB_FILE=/data/db.sqlite +CRONTAB="00 06 * * *" +DELETE_AFTER=10 +TZ=Asia/Novosibirsk +MINIO_PATH=myminio://sqlite/master/ +MINIO_ACCOUNT_ID=account +MINIO_APPLICATION_KEY=key +MINIO_ENDPOINT=https://s3.domain.ru +MINIO_LOCATION=ru-nsk +``` + +1. myminio - системно! не менять +2. проверьте настройки локации, не должно быть пусто +3. DELETE_AFTER - в днях diff --git a/docker-build.sh b/docker-build.sh new file mode 100755 index 0000000..31363cd --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +DOCKER_BASEIMAGE=alpine:latest + +docker buildx build --platform linux/amd64,linux/arm64 --push -t hub.realmanual.ru/pub/sqlite-backup \ + --build-arg DOCKER_BASEIMAGE=${DOCKER_BASEIMAGE} . diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d53933b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +services: + sqlite_backup: + image: hub.realmanual.ru/pub/sqlite-backup/backup:latest + container_name: sqlite_backup + restart: always + volumes: + - ./var/lib/sqlite/:/data + environment: + - DB_FILE + - CRONTAB + - DELETE_AFTER + - TZ + - MINIO_PATH + - MINIO_ACCOUNT_ID + - MINIO_APPLICATION_KEY + - MINIO_ENDPOINT + - MINIO_LOCATION diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100644 index 0000000..0e6db19 --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +BACKUP_FILE="sqlite_$(date "+%F-%H%M%S")" + +sqlite3 ${DB_FILE} ".backup '/tmp/db.sqlite'" +tar -zcvf /tmp/${BACKUP_FILE}.tar.gz /tmp/db.sqlite + +/scripts/minio_uploader.sh copy /tmp/${BACKUP_FILE}.tar.gz ${MINIO_PATH} + +rm /tmp/${BACKUP_FILE}.tar.gz + +if [ ! -z $DELETE_AFTER ] && [ $DELETE_AFTER -gt 0 ] +then + /scripts/deleteold.sh ${MINIO_PATH} +fi diff --git a/scripts/deleteold.sh b/scripts/deleteold.sh new file mode 100644 index 0000000..ad6998c --- /dev/null +++ b/scripts/deleteold.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Seconds since epoch for current time +DATE_NOW=$(date +%s) + +/scripts/minio_uploader.sh list $MINIO_PATH | grep "sqlite_" | while read LINE +do + BACKUP_FILENAME=$(echo $LINE | awk '{ print $3 }') + + BACKUP_DATE=$(echo $BACKUP_FILENAME | awk 'BEGIN { FS = "[_-]" } ; { printf "%s-%s-%s",$2,$3,$4 }') + + if [[ $BACKUP_DATE =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] + then + BACKUP_DATE_SECS=$(date -d $BACKUP_DATE +%s) + + DAYS_DIFF=$(( ($DATE_NOW - $BACKUP_DATE_SECS) / (60*60*24) )) + + if [ "$DAYS_DIFF" -gt "$DELETE_AFTER" ] + then + echo "File $BACKUP_FILENAME is $DAYS_DIFF days old (greater than $DELETE_AFTER days). Deleting it." + /scripts/minio_uploader.sh delete /$BACKUP_FILENAME + fi + fi +done diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh new file mode 100644 index 0000000..a4aef8a --- /dev/null +++ b/scripts/entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "${CRONTAB} /scripts/backup.sh" > /etc/crontabs/root + +/scripts/backup.sh +exec crond -f diff --git a/scripts/minio_uploader.sh b/scripts/minio_uploader.sh new file mode 100644 index 0000000..501a425 --- /dev/null +++ b/scripts/minio_uploader.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +rclone config create myminio s3 provider Minio access_key_id $MINIO_ACCOUNT_ID secret_access_key $MINIO_APPLICATION_KEY endpoint $MINIO_ENDPOINT region $MINIO_LOCATION acl private + +case $1 in + copy) + echo "copy from $2 to $3" + rclone copy --progress $2 $3 + ;; + list) + echo "list $2" + rclone ls $2 + ;; + delete) + echo "delete $2" + rclone delete $2 + ;; +esac