Files
homelab-configs/lubelogger/deploy-lubelogger.yml
T
tommy 6de37c8712 LubeLogger: back up data+keys volumes to PBS via the playbook
Close the volume-backup gap: the pg_dump covered Postgres only; the ASP.NET
DataProtection keyring (root-user credential) and uploaded docs live in the
lubelogger-{data,keys} volumes. The docker-volume-backup sidecar can't target PBS
natively, so both volumes now ride the same proxmox-backup-client job as the SQL
dump — one host/lubelogger snapshot, three .pxar archives, keep-daily 14. Backup
script+units are now installed by the Ansible playbook (idempotent, changed=0);
PBS token from ansible-vault. Restore verified: keyring XML + sentinel doc
byte-identical (sha256). Removes the now-playbook-managed standalone script/units.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:28:31 -05:00

207 lines
7.2 KiB
YAML

---
- name: Deploy LubeLogger on docker-node01
hosts: docker-node01
become: true
vars:
app_dir: /home/tommy/lubelogger
app_port: 8099
handlers:
- name: reload systemd
ansible.builtin.systemd_service:
daemon_reload: true
tasks:
- name: Create lubelogger directory
ansible.builtin.file:
path: "{{ app_dir }}"
state: directory
owner: tommy
group: tommy
mode: "0755"
- name: Write docker-compose.yml
ansible.builtin.copy:
dest: "{{ app_dir }}/docker-compose.yml"
owner: tommy
group: tommy
mode: "0644"
content: |
# lubelogger - Vehicle & small-engine maintenance tracker
# Host: docker-node01 (.186), Port: {{ app_port }}
# Traefik: lubelogger.goattw.net (Authelia protected, @file router -> :{{ app_port }})
# Backend: PostgreSQL 18 (tables live in the `app` schema).
# In-app auth is ENABLED (root user) - the published host port is safe.
# Do NOT lose the lubelogger-keys volume (ASP.NET DataProtection keyring).
services:
lubelogger:
image: ghcr.io/hargata/lubelogger:v1.6.8
container_name: lubelogger
restart: unless-stopped
depends_on:
- lubelogger-db
ports:
- "{{ app_port }}:8080"
environment:
TZ: America/Chicago
LUBELOGGER_LOCALE_OVERRIDE: "en_US"
POSTGRES_CONNECTION: "Host=lubelogger-db:5432;Username=lubelogger;Password={{ vault_lubelogger_db_password }};Database=lubelogger;"
volumes:
- lubelogger-data:/App/data
- lubelogger-keys:/root/.aspnet/DataProtection-Keys
networks:
- lubelogger-int
labels:
- "docker-volume-backup.stop-during-backup=true"
# Diun watches by default (digest); watch_repo + semver filter
# so a NEW release tag (e.g. v1.6.9) pings the existing Diun->HA pipeline.
- "diun.enable=true"
- "diun.watch_repo=true"
- 'diun.include_tags=^v[0-9]+\.[0-9]+\.[0-9]+$'
lubelogger-db:
image: postgres:18
container_name: lubelogger-db
restart: unless-stopped
environment:
POSTGRES_USER: lubelogger
POSTGRES_PASSWORD: "{{ vault_lubelogger_db_password }}"
POSTGRES_DB: lubelogger
TZ: America/Chicago
volumes:
- lubelogger-db:/var/lib/postgresql
- /etc/localtime:/etc/localtime:ro
networks:
- lubelogger-int
healthcheck:
test: ["CMD-SHELL", "pg_isready -U lubelogger -d lubelogger"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
labels:
- "docker-volume-backup.stop-during-backup=true"
networks:
lubelogger-int:
driver: bridge
volumes:
lubelogger-data:
lubelogger-keys:
lubelogger-db:
- name: Remove stale .env (secret now sourced from ansible-vault)
ansible.builtin.file:
path: "{{ app_dir }}/.env"
state: absent
- name: Deploy lubelogger with docker compose
community.docker.docker_compose_v2:
project_src: "{{ app_dir }}"
state: present
pull: missing
register: app_result
- name: Show deployment result
ansible.builtin.debug:
msg: "lubelogger is {{ 'running (changed)' if app_result.changed else 'already up (no-op)' }} on port {{ app_port }}"
# ---- Backup: pg_dump + data/keys volumes -> PBS (host/lubelogger, keep-daily 14) ----
# docker-volume-backup sidecar cannot target a PBS datastore natively, so the two
# volumes ride the same proxmox-backup-client job as the SQL dump: one snapshot,
# three archives, one retention. Secrets come from ansible-vault, never committed.
- name: Install PBS backup credentials (from vault)
ansible.builtin.copy:
dest: /etc/lubelogger-backup.env
owner: root
group: root
mode: "0600"
content: |
# Managed by deploy-lubelogger.yml. PBS push creds — NOT in git.
PBS_PASSWORD={{ vault_lubelogger_pbs_token }}
PBS_FINGERPRINT=90:6B:3E:85:C4:E7:77:F0:24:25:1D:B0:2C:F9:6D:08:AA:CE:08:CE:7B:04:4C:C7:C9:E0:CF:DD:99:44:DB:21
PBS_REPOSITORY='root@pam!vaultwarden-backup@192.168.99.153:rust-usb'
no_log: true
- name: Install lubelogger backup script
ansible.builtin.copy:
dest: /usr/local/bin/lubelogger-backup.sh
owner: root
group: root
mode: "0700"
content: |
#!/bin/bash
# LubeLogger backup -> Proxmox Backup Server.
# One snapshot (host/lubelogger), three archives: Postgres logical dump +
# the data and keys volumes (uploads, config, ASP.NET DataProtection keyring).
# Managed by deploy-lubelogger.yml; driven by lubelogger-backup.timer.
set -euo pipefail
source /etc/lubelogger-backup.env
export PBS_PASSWORD PBS_FINGERPRINT
DATA_VOL=/var/lib/docker/volumes/lubelogger_lubelogger-data/_data
KEYS_VOL=/var/lib/docker/volumes/lubelogger_lubelogger-keys/_data
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
# Logical DB dump (app schema + data); app stays online.
docker exec lubelogger-db pg_dump -U lubelogger lubelogger > "$TMPDIR/lubelogger.sql"
proxmox-backup-client backup \
"lubelogger-db.pxar:$TMPDIR" \
"lubelogger-data.pxar:$DATA_VOL" \
"lubelogger-keys.pxar:$KEYS_VOL" \
--repository "$PBS_REPOSITORY" \
--backup-type host \
--backup-id lubelogger
proxmox-backup-client prune "host/lubelogger" \
--repository "$PBS_REPOSITORY" \
--keep-daily 14
notify: reload systemd
- name: Install backup systemd service unit
ansible.builtin.copy:
dest: /etc/systemd/system/lubelogger-backup.service
owner: root
group: root
mode: "0644"
content: |
[Unit]
Description=LubeLogger backup (pg_dump + volumes) -> PBS
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/lubelogger-backup.sh
notify: reload systemd
- name: Install backup systemd timer unit
ansible.builtin.copy:
dest: /etc/systemd/system/lubelogger-backup.timer
owner: root
group: root
mode: "0644"
content: |
[Unit]
Description=Daily LubeLogger backup to PBS
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
[Install]
WantedBy=timers.target
notify: reload systemd
- name: Enable lubelogger backup timer
ansible.builtin.systemd_service:
name: lubelogger-backup.timer
enabled: true
state: started