Compare commits

..

5 Commits

Author SHA1 Message Date
root
0086878d57 added more .env stuff 2024-06-28 20:15:14 -05:00
root
2ed9f3345d added some dotenv stuff 2024-06-28 20:10:47 -05:00
root
50dd0df84f some error tolerance 2024-06-28 20:10:04 -05:00
John Lancaster
e17894e49c added docker sdk to dependencies 2024-06-15 15:49:34 -05:00
John Lancaster
326d2c0910 added to gitignore 2024-06-15 15:08:05 -05:00
10 changed files with 34 additions and 113 deletions

View File

@@ -2,52 +2,23 @@
Purpose: Purpose:
> [!WARNING]
> This behvior does not work on the `resticprofile` branch
- Wrap `restic` with the ability to start/stop Docker containers - Wrap `restic` with the ability to start/stop Docker containers
- Send updates to Loki server - Send updates to Loki server
## Installation ## Environment Variables
### Include in Repo Put these in a `.env` file in the directory that the backup will be run from.
From a parent repo, add this one as a submodule: | Env Variable | Description |
|---------------------|--------------------------------------------------------------------------------------------|
```shell | `HOSTNAME` | Network hostname of where the backup is running. Used to tag the backups in restic |
git submodule add https://gitea.john-stream.com/john/restic-scripts | `BACKUP_DIR` | Directory to back up |
``` | `RESTIC_REPOSITORY` | Directory for the restic repository. This is usually on a mount point made from Proxmox |
| `RESTIC_PASSWORD` | Password for the restic repository |
Then add this to the `docker-compose.yml` file of the parent. | `LOKI_URL` | Push URL for Loki. Should include the port and end with something like `/loki/api/v1/push` |
```yaml
include:
- restic-scripts/docker-compose.yml
```
### Environment Variables
Put these in `./restic-scripts/.env`, which is on the `.gitignore` list.
| Env Variable | Description |
| ------------------- | --------------------------------------------------------------------------------------- |
| `BACKUP_DIR` | Directory to back up |
| `RESTIC_REPOSITORY` | Directory for the restic repository. This is usually on a mount point made from Proxmox |
| `TZ` | Set to modify the timezone shown in the scheduler |
### Key file
The password needs to be stored in `./restic-scripts/key`. Make sure it has the right (secure) permissions.
```shell
sudo chown root:root ./restic-scripts/key && sudo chmod 600 ./restic-scripts/key
```
## Loki Updates ## Loki Updates
> [!WARNING]
> This doesn't currently work on the `resticprofile` branch
Updates sent to Loki will have the following labels: Updates sent to Loki will have the following labels:
| Label | Description | | Label | Description |
@@ -57,28 +28,16 @@ Updates sent to Loki will have the following labels:
## Usage ## Usage
Check snapshots
```shell ```shell
docker compose exec backup resticprofile snapshots python -m restic.snapshots
``` ```
Dry-run a backup To stop docker containers before the backup and start them again afterwards, use the `--project` and `--services` flags.
```shell ```shell
docker compose exec backup resticprofile --dry-run backup python -m restic.backup --tag manual --project joplin --services app,db
``` ```
Check crontab entry in container
```shell ```shell
docker compose exec backup cat /var/spool/cron/crontabs/root python -m restic.prune
```
### Crond
Crond command when scheduled using `resticprofile schedule --all`
```shell
cd /resticprofile && /usr/bin/resticprofile --no-ansi --config /etc/resticprofile/profiles.yaml --name default backup
``` ```

View File

@@ -1,16 +0,0 @@
services:
backup:
image: creativeprojects/resticprofile
entrypoint: '/bin/sh'
command:
- -c
- 'resticprofile-schedule.sh && crond -f'
env_file:
- .env
hostname: ${HOSTNAME}
volumes:
- ./restic-profile.yaml:/etc/resticprofile/profiles.yaml:ro
- ./resticprofile-schedule.sh:/usr/local/bin/resticprofile-schedule.sh:ro
- ./key:/etc/resticprofile/key:ro
- ${BACKUP_DIR}:${BACKUP_DIR}:ro
- ${RESTIC_REPOSITORY}:${RESTIC_REPOSITORY}:rw

View File

@@ -12,4 +12,4 @@ authors = [
license = { file = "LICENSE" } license = { file = "LICENSE" }
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = ["rich", "requests", "click"] dependencies = ["rich", "requests", "click", "docker", "python-dotenv"]

View File

@@ -2,4 +2,6 @@ uv
ruff ruff
rich rich
requests requests
click click
docker
python-dotenv

View File

@@ -1,29 +0,0 @@
global:
scheduler: crond
default:
base-dir: ${BACKUP_DIR}
repository: local:${RESTIC_REPOSITORY}
password-file: key
initialize: true
backup:
source: ./
exclude-caches: true
one-file-system: true
schedule: "*:00"
schedule-permission: system
check-after: true
tag:
- resticprofile
retention:
after-backup: true
before-backup: false
prune: true
tag:
- resticprofile
keep-within: 3h
keep-hourly: 72
keep-daily: 14
keep-weekly: 8
keep-monthly: 6

View File

@@ -1,9 +0,0 @@
#!/bin/sh
set -e
resticprofile unschedule > /dev/null
resticprofile schedule --all
echo "Scheduled all restic profiles"

View File

@@ -81,6 +81,7 @@ def main(
logging.getLogger('urllib3.connectionpool').setLevel('WARNING') logging.getLogger('urllib3.connectionpool').setLevel('WARNING')
if project is not None and services is not None: if project is not None and services is not None:
logger.debug(f'Using project {project} and stopping services: {services}')
decorator = manage_containers(project=project, services=services.split(',')) decorator = manage_containers(project=project, services=services.split(','))
func = decorator(run) func = decorator(run)
else: else:
@@ -96,4 +97,10 @@ def main(
if __name__ == '__main__': if __name__ == '__main__':
from dotenv import load_dotenv
from pathlib import Path
dotenv_file = Path.cwd() / '.env'
print(dotenv_file)
load_dotenv(dotenv_path=dotenv_file)
main() main()

View File

@@ -15,11 +15,12 @@ def manage_containers(project: str, services: list[str]):
try: try:
project_containers = ( project_containers = (
c c
for c in client.containers.list() for c in client.containers.list(all=True)
if c.labels['com.docker.compose.project'] == project if c.labels.get('com.docker.compose.project', False)
) )
service_dict: dict[str, Container] = { service_dict: dict[str, Container] = {
c.labels['com.docker.compose.service']: c for c in project_containers service: c for c in project_containers
if (service := c.labels.get('com.docker.compose.service', False))
} }
containers: list[Container] = [service_dict[s] for s in services] containers: list[Container] = [service_dict[s] for s in services]
except Exception as e: except Exception as e:

View File

@@ -95,4 +95,7 @@ def main(loki_url: str, dry_run: bool, **kwargs):
if __name__ == '__main__': if __name__ == '__main__':
from dotenv import load_dotenv
load_dotenv()
main() main()

View File

@@ -35,4 +35,7 @@ def main(loki_url: str = None):
if __name__ == '__main__': if __name__ == '__main__':
from dotenv import load_dotenv
load_dotenv()
main() main()