feat: add monthly Docker prune cron Ansible playbook (#29) #45

Open
Claude wants to merge 2 commits from issue/29-docker-image-prune-cron-on-all-docker-hosts into main
Collaborator

Closes #29

Summary

Adds ansible/playbooks/docker-prune.yml — an Ansible playbook that deploys /etc/cron.monthly/docker-prune to all six Docker hosts in the homelab.

Hosts covered

  • VM 106 docker-home
  • VM 110 discord-bots
  • VM 112 databases-bots
  • VM 115 docker-sba
  • VM 116 docker-home-servers
  • manticore (ubuntu-manticore)

Script deployed to each host

#!/bin/bash
set -euo pipefail
docker container prune -f --filter "until=720h"
docker image prune -a -f --filter "until=720h"
docker volume prune -f --filter "label!=keep"

Safety notes

  • docker image prune -a only removes images not referenced by any container (running or stopped) — the until=720h filter adds a 30-day age gate on top of that
  • docker volume prune skips volumes with a keep label — mark critical volumes with docker volume update <vol> --label keep=true to exempt them
  • Follows the same hosts: <group>:... / become: true pattern as mask-avahi.yml

Run instructions

# Dry run from LXC 304
ansible-playbook /opt/ansible/playbooks/docker-prune.yml --check

# Single host test
ansible-playbook /opt/ansible/playbooks/docker-prune.yml --limit docker-sba

# All Docker hosts
ansible-playbook /opt/ansible/playbooks/docker-prune.yml

Files changed

  • ansible/playbooks/docker-prune.yml (new)
Closes #29 ## Summary Adds `ansible/playbooks/docker-prune.yml` — an Ansible playbook that deploys `/etc/cron.monthly/docker-prune` to all six Docker hosts in the homelab. ### Hosts covered - VM 106 `docker-home` - VM 110 `discord-bots` - VM 112 `databases-bots` - VM 115 `docker-sba` - VM 116 `docker-home-servers` - `manticore` (ubuntu-manticore) ### Script deployed to each host ```bash #!/bin/bash set -euo pipefail docker container prune -f --filter "until=720h" docker image prune -a -f --filter "until=720h" docker volume prune -f --filter "label!=keep" ``` ### Safety notes - `docker image prune -a` only removes images **not referenced by any container** (running or stopped) — the `until=720h` filter adds a 30-day age gate on top of that - `docker volume prune` skips volumes with a `keep` label — mark critical volumes with `docker volume update <vol> --label keep=true` to exempt them - Follows the same `hosts: <group>:... / become: true` pattern as `mask-avahi.yml` ## Run instructions ```bash # Dry run from LXC 304 ansible-playbook /opt/ansible/playbooks/docker-prune.yml --check # Single host test ansible-playbook /opt/ansible/playbooks/docker-prune.yml --limit docker-sba # All Docker hosts ansible-playbook /opt/ansible/playbooks/docker-prune.yml ``` ## Files changed - `ansible/playbooks/docker-prune.yml` (new)
Claude added 2 commits 2026-04-03 21:33:41 +00:00
Establishes a first-Sunday-of-the-month maintenance window orchestrated
by Ansible on LXC 304. Split into two playbooks to handle the self-reboot
paradox (the controller is a guest on the host being rebooted):

- monthly-reboot.yml: snapshots, tiered shutdown with per-guest polling,
  fire-and-forget host reboot
- post-reboot-startup.yml: controlled tiered startup with staggered delays,
  Pi-hole UDP DNS fix, validation, and snapshot cleanup

Also fixes onboot:1 on VM 109, LXC 221, LXC 223 and creates a recurring
Google Calendar event for the maintenance window.

Closes #26

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: add monthly Docker prune cron Ansible playbook (#29)
All checks were successful
Auto-merge docs-only PRs / auto-merge-docs (pull_request) Successful in 2s
0e5c3c2b3b
Closes #29

Deploys /etc/cron.monthly/docker-prune to all six Docker hosts via
Ansible. Uses 720h (30-day) age filter on containers and images, with
volume pruning exempt for `keep`-labeled volumes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude added the
ai-reviewing
label 2026-04-03 21:45:26 +00:00
Claude reviewed 2026-04-03 21:47:52 +00:00
Claude left a comment
Author
Collaborator

AI Code Review

Files Reviewed

  • ansible/playbooks/docker-prune.yml (added) — the intended change for issue #29
  • ansible/playbooks/monthly-reboot.yml (in diff, already in main via PR #26)
  • ansible/playbooks/post-reboot-startup.yml (in diff, already in main via PR #26)
  • ansible/systemd/ansible-monthly-reboot.service (in diff, already in main via PR #26)
  • ansible/systemd/ansible-monthly-reboot.timer (in diff, already in main via PR #26)
  • ansible/systemd/ansible-post-reboot.service (in diff, already in main via PR #26)
  • server-configs/proxmox/maintenance-reboot.md (in diff, already in main via PR #26)

Findings

Correctness

  • docker-prune.yml correctly deploys /etc/cron.monthly/docker-prune to all six Docker hosts using ansible.builtin.copy with explicit owner, group, and mode: "0755".
  • The deployed script uses set -euo pipefail — correct defensive shell practice.
  • docker volume prune correctly omits the unsupported until filter (only label!=keep applied). The until=720h filter on container/image prune is correctly supported and applied.
  • label!=keep semantics are correct: volumes without a keep label are pruned; labeled volumes are spared.
  • The verify task (test -x …) with changed_when: false is correct in intent, though redundant since the copy task enforces mode: "0755". Harmless.
  • Follows mask-avahi.yml playbook structure (hosts: <group>:..., become: true, FQCN modules).

Security

  • No hardcoded credentials or secrets.
  • become: true is required — cron.monthly writes need root. No privilege escalation concern beyond what's expected.
  • docker image prune -a only removes images not referenced by any container (running or stopped) — the until=720h filter prevents removing recently-pulled images.
  • docker volume prune with label!=keep is the intended safety mechanism. Note: docker volume update to add labels requires Docker 26+; on older engines, labels must be set at volume creation time. This is a documentation concern in the PR body only — not in the deployed script.

Style & Conventions

  • FQCN modules used throughout (ansible.builtin.copy, ansible.builtin.command) — consistent with existing playbooks.
  • Comment block matches mask-avahi.yml style: usage examples, undo instructions, host list.
  • No issues.

Suggestions

  • Branch divergence (non-blocking): The PR branch was forked from 64f299a (before PR #26 merged the monthly-reboot automation into main). As a result, the diff shows 6 monthly-reboot files that already exist in main with identical content. Gitea confirms mergeable: true — the 3-way merge will succeed without duplicating content. docker-prune.yml is the only net-new file. Consider rebasing issue branches on main before opening PRs to keep diffs focused.

Verdict: APPROVED

docker-prune.yml is correct, follows project conventions, and is safe to deploy. The 6 extra files in the diff are pre-existing in main with identical content and will merge cleanly — no action required.


Automated review by Claude PR Reviewer

## AI Code Review ### Files Reviewed - `ansible/playbooks/docker-prune.yml` (added) — the intended change for issue #29 - `ansible/playbooks/monthly-reboot.yml` (in diff, already in main via PR #26) - `ansible/playbooks/post-reboot-startup.yml` (in diff, already in main via PR #26) - `ansible/systemd/ansible-monthly-reboot.service` (in diff, already in main via PR #26) - `ansible/systemd/ansible-monthly-reboot.timer` (in diff, already in main via PR #26) - `ansible/systemd/ansible-post-reboot.service` (in diff, already in main via PR #26) - `server-configs/proxmox/maintenance-reboot.md` (in diff, already in main via PR #26) ### Findings #### Correctness - `docker-prune.yml` correctly deploys `/etc/cron.monthly/docker-prune` to all six Docker hosts using `ansible.builtin.copy` with explicit `owner`, `group`, and `mode: "0755"`. - The deployed script uses `set -euo pipefail` — correct defensive shell practice. - `docker volume prune` correctly omits the unsupported `until` filter (only `label!=keep` applied). The `until=720h` filter on container/image prune is correctly supported and applied. - `label!=keep` semantics are correct: volumes without a `keep` label are pruned; labeled volumes are spared. - The verify task (`test -x …`) with `changed_when: false` is correct in intent, though redundant since the copy task enforces `mode: "0755"`. Harmless. - Follows `mask-avahi.yml` playbook structure (`hosts: <group>:..., become: true, FQCN modules`). #### Security - No hardcoded credentials or secrets. - `become: true` is required — cron.monthly writes need root. No privilege escalation concern beyond what's expected. - `docker image prune -a` only removes images not referenced by any container (running or stopped) — the `until=720h` filter prevents removing recently-pulled images. - `docker volume prune` with `label!=keep` is the intended safety mechanism. Note: `docker volume update` to add labels requires Docker 26+; on older engines, labels must be set at volume creation time. This is a documentation concern in the PR body only — not in the deployed script. #### Style & Conventions - FQCN modules used throughout (`ansible.builtin.copy`, `ansible.builtin.command`) — consistent with existing playbooks. - Comment block matches `mask-avahi.yml` style: usage examples, undo instructions, host list. - No issues. #### Suggestions - **Branch divergence (non-blocking):** The PR branch was forked from `64f299a` (before PR #26 merged the monthly-reboot automation into main). As a result, the diff shows 6 monthly-reboot files that already exist in main with identical content. Gitea confirms `mergeable: true` — the 3-way merge will succeed without duplicating content. `docker-prune.yml` is the only net-new file. Consider rebasing issue branches on main before opening PRs to keep diffs focused. ### Verdict: APPROVED `docker-prune.yml` is correct, follows project conventions, and is safe to deploy. The 6 extra files in the diff are pre-existing in main with identical content and will merge cleanly — no action required. --- *Automated review by Claude PR Reviewer*
Claude added
ai-reviewed
and removed
ai-reviewing
labels 2026-04-03 21:47:58 +00:00
All checks were successful
Auto-merge docs-only PRs / auto-merge-docs (pull_request) Successful in 2s
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue/29-docker-image-prune-cron-on-all-docker-hosts:issue/29-docker-image-prune-cron-on-all-docker-hosts
git checkout issue/29-docker-image-prune-cron-on-all-docker-hosts
Sign in to join this conversation.
No description provided.