Skip to content

Commit 9dece75

Browse files
committed
feat: initial commit
1 parent e98ef8a commit 9dece75

9 files changed

Lines changed: 782 additions & 0 deletions

File tree

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
B2_APPLICATION_KEY=
2+
B2_APPLICATION_KEY_ID=
3+
B2_BUCKET=
4+
RESTIC_PASSWORD=

.github/workflows/on-push.yml

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
name: On Push
2+
on:
3+
push:
4+
env:
5+
IMAGE: ghcr.io/rogueoneecho/backup
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: true
9+
jobs:
10+
11+
release:
12+
runs-on: ubuntu-latest
13+
outputs:
14+
version: ${{ steps.release.outputs.version }}
15+
steps:
16+
17+
- uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
fetch-tags: true
21+
22+
- id: release
23+
env:
24+
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
25+
run: ${{ secrets.RELEASE_SCRIPT }}
26+
27+
- run: echo "# ${{ steps.release.outputs.version}}" >> $GITHUB_STEP_SUMMARY
28+
29+
- run: cat /tmp/release-notes.md >> $GITHUB_STEP_SUMMARY
30+
31+
- uses: actions/upload-artifact@v4
32+
with:
33+
name: release-notes.md
34+
path: /tmp/release-notes.md
35+
36+
build:
37+
if: needs.release.outputs.version != ''
38+
strategy:
39+
matrix:
40+
include:
41+
- runner: ubuntu-24.04
42+
arch: amd
43+
- runner: ubuntu-24.04-arm
44+
arch: arm
45+
runs-on: ${{ matrix.runner }}
46+
needs:
47+
- release
48+
steps:
49+
50+
- uses: actions/checkout@v4
51+
52+
- uses: actions/cache@v4
53+
with:
54+
path: /tmp/.buildx-cache
55+
key: buildx-${{ matrix.arch }}-${{ github.sha }}
56+
restore-keys: |
57+
buildx-${{ matrix.arch }}-
58+
59+
- run: echo $GH_TOKEN | docker login ghcr.io -u ${{ github.actor }} --password-stdin
60+
env:
61+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
62+
63+
- run: docker buildx create --use
64+
65+
- run: >
66+
docker buildx build src
67+
--platform "linux/${{ matrix.arch }}64"
68+
--build-arg VERSION=${{ needs.release.outputs.version }}
69+
--tag ${{ env.IMAGE }}:${{ needs.release.outputs.version }}-${{ matrix.arch }}
70+
--cache-from=type=local,src=/tmp/.buildx-cache
71+
--cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max
72+
--provenance false
73+
--push
74+
75+
# Temp fix
76+
# https://github.com/docker/build-push-action/issues/252
77+
# https://github.com/moby/buildkit/issues/1896
78+
- run: rm -rf /tmp/.buildx-cache
79+
- run: mv /tmp/.buildx-cache-new /tmp/.buildx-cache
80+
81+
82+
git-tag:
83+
runs-on: ubuntu-24.04
84+
if: needs.release.outputs.version != '' && contains(needs.release.outputs.version, '-')
85+
needs:
86+
- release
87+
- build
88+
steps:
89+
90+
- uses: actions/checkout@v4
91+
with:
92+
fetch-depth: 0
93+
fetch-tags: true
94+
95+
- name: git config
96+
run: ${{ secrets.GIT_CONFIG }}
97+
98+
- name: git tag
99+
run: git tag "v${{ needs.release.outputs.version }}"
100+
101+
- name: git push
102+
run: git push origin "v${{ needs.release.outputs.version }}"
103+
104+
105+
github-release:
106+
runs-on: ubuntu-24.04
107+
if: needs.release.outputs.version != '' && contains(needs.release.outputs.version, '-') == false
108+
needs:
109+
- release
110+
- build
111+
steps:
112+
113+
- uses: actions/checkout@v4
114+
115+
- uses: actions/download-artifact@v4
116+
with:
117+
name: release-notes.md
118+
119+
- name: gh release create
120+
if: contains(needs.release.outputs.version, '-') == false
121+
env:
122+
GH_TOKEN: ${{ github.token }}
123+
run: >
124+
gh release create
125+
"v${{ needs.release.outputs.version }}"
126+
--title "v${{ needs.release.outputs.version }}"
127+
--notes-file release-notes.md
128+
--target ${{ github.ref_name }}
129+
130+
- name: gh release create --prerelease
131+
if: contains(needs.release.outputs.version, '-')
132+
env:
133+
GH_TOKEN: ${{ github.token }}
134+
run: >
135+
gh release create
136+
"v${{ needs.release.outputs.version }}"
137+
--title "v${{ needs.release.outputs.version }}"
138+
--notes-file release-notes.md
139+
--target ${{ github.ref_name }}
140+
--prerelease
141+
142+
143+
push:
144+
runs-on: ubuntu-24.04
145+
needs:
146+
- release
147+
- build
148+
steps:
149+
150+
- run: echo $GH_TOKEN | docker login ghcr.io -u ${{ github.actor }} --password-stdin
151+
env:
152+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
153+
154+
- run: >
155+
docker manifest create ${{ env.IMAGE }}:${{ needs.release.outputs.version }}
156+
${{ env.IMAGE }}:${{ needs.release.outputs.version }}-amd
157+
${{ env.IMAGE }}:${{ needs.release.outputs.version }}-arm
158+
159+
- run: docker manifest push ${{ env.IMAGE }}:${{ needs.release.outputs.version }}
160+
161+
- if: contains(needs.release.outputs.version, '-')
162+
run: >
163+
docker manifest create ${{ env.IMAGE }}:alpha
164+
${{ env.IMAGE }}:${{ needs.release.outputs.version }}-amd
165+
${{ env.IMAGE }}:${{ needs.release.outputs.version }}-arm
166+
167+
- if: contains(needs.release.outputs.version, '-')
168+
run: docker manifest push ${{ env.IMAGE }}:alpha
169+
170+
- if: contains(needs.release.outputs.version, '-') == false
171+
run: >
172+
docker manifest create ${{ env.IMAGE }}:latest
173+
${{ env.IMAGE }}:${{ needs.release.outputs.version }}-amd
174+
${{ env.IMAGE }}:${{ needs.release.outputs.version }}-arm
175+
176+
- if: contains(needs.release.outputs.version, '-') == false
177+
run: docker manifest push ${{ env.IMAGE }}:latest

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.env
2+
.envrc
23
.idea

README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Backup
2+
3+
Docker container for backing up service data to Backblaze B2 using rsync and restic.
4+
5+
## Features
6+
7+
- Syncs files using rsync with configurable exclusions
8+
- Exports SQLite databases safely with integrity checks
9+
- Uploads to Backblaze B2 using restic (encrypted, deduplicated)
10+
- Automatic retention policy (7 daily, 4 weekly, 12 monthly)
11+
- Verifies backup integrity after each run
12+
13+
## Environment Variables
14+
15+
| Variable | Description |
16+
|----------|-------------|
17+
| `NAME` | Backup name (used for restic host and repo path) |
18+
| `SOURCE` | Source directory to backup (default: `/srv/${NAME}/`) |
19+
| `B2_APPLICATION_KEY` | Backblaze B2 application key |
20+
| `B2_APPLICATION_KEY_ID` | Backblaze B2 application key ID |
21+
| `B2_BUCKET` | Backblaze B2 bucket name |
22+
| `RESTIC_PASSWORD` | Restic repository encryption password |
23+
24+
## Usage
25+
26+
### With Docker Compose
27+
28+
```yaml
29+
services:
30+
backup-myservice:
31+
image: ghcr.io/rogueoneecho/backup:latest
32+
userns_mode: host
33+
environment:
34+
NAME: myservice
35+
env_file:
36+
- .env
37+
configs:
38+
- source: myservice_backup_exclude
39+
target: /app/exclude
40+
volumes:
41+
- /srv/myservice:/srv/myservice:ro
42+
- /srv/shared/backups/myservice:/srv/shared/backups/myservice
43+
- /srv/shared/backups/.restic-cache:/root/.cache/restic
44+
45+
configs:
46+
myservice_backup_exclude:
47+
content: |
48+
cache
49+
logs
50+
```
51+
52+
### Running
53+
54+
```bash
55+
docker compose run --rm backup-myservice
56+
```
57+
58+
## Testing
59+
60+
```bash
61+
docker compose run --rm backup-test
62+
```
63+
64+
## Exclusions
65+
66+
Create an exclusion file mounted at `/app/exclude`. Patterns match path components (not substrings).
67+
68+
Example:
69+
```
70+
cache
71+
logs
72+
temp
73+
```

docker-compose.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
services:
2+
3+
backup-test:
4+
container_name: backup-test
5+
build: ./src
6+
userns_mode: host
7+
environment:
8+
NAME: test
9+
SOURCE: /srv/shared/tests/
10+
env_file:
11+
- .env
12+
configs:
13+
- source: backup_exclude
14+
target: /app/exclude
15+
volumes:
16+
- /srv/shared/tests:/srv/shared/tests:ro
17+
- /srv/shared/backups/test:/srv/shared/backups/test
18+
- /srv/shared/backups/.restic-cache:/root/.cache/restic
19+
20+
configs:
21+
backup_exclude:
22+
content: |
23+
example-1
24+
example-2.torrent

src/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*
2+
!backup
3+
!logging

src/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM alpine
2+
RUN echo "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
3+
RUN apk update
4+
RUN apk add --no-cache bash rsync sqlite b2-tools restic
5+
WORKDIR /app
6+
COPY logging /app/logging
7+
COPY backup /app/backup
8+
RUN chmod a+x /app/logging && chmod a+x /app/backup
9+
ENTRYPOINT ["/app/backup"]

0 commit comments

Comments
 (0)