diff --git a/ansible/roles/registry/tasks/main.yml b/ansible/roles/registry/tasks/main.yml index 3862b29..4297c48 100644 --- a/ansible/roles/registry/tasks/main.yml +++ b/ansible/roles/registry/tasks/main.yml @@ -38,3 +38,23 @@ state: present pull: missing tags: registry + +- name: Deploy registry GC script + ansible.builtin.template: + src: registry-gc.sh.j2 + dest: /usr/local/bin/registry-gc + owner: root + group: root + mode: "0750" + tags: registry + +- name: Schedule weekly registry GC cron job + ansible.builtin.cron: + name: registry-gc + user: root + weekday: "0" + hour: "3" + minute: "0" + job: /usr/local/bin/registry-gc >> /var/log/registry-gc.log 2>&1 + state: present + tags: registry diff --git a/ansible/roles/registry/templates/registry-gc.sh.j2 b/ansible/roles/registry/templates/registry-gc.sh.j2 new file mode 100644 index 0000000..d0f40fa --- /dev/null +++ b/ansible/roles/registry/templates/registry-gc.sh.j2 @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Managed by Ansible — do not edit manually +# Weekly registry maintenance: remove stale uploads, run GC, prune dangling host images. +set -euo pipefail + +LOG_TAG="registry-gc" +REGISTRY_COMPOSE_DIR="{{ registry_data_dir }}" +REGISTRY_DATA_DIR="{{ registry_data_dir }}/data" + +log() { logger -t "$LOG_TAG" -- "$*"; echo "$(date -Iseconds) $*"; } + +log "=== Registry cleanup started ===" + +# 1. Remove stale upload sessions (failed or abandoned pushes) +find "{{ registry_data_dir }}/docker/registry/v2/repositories" \ + -type d -name '_uploads' -exec rm -rf {} + 2>/dev/null || true +log "Stale _uploads removed" + +# 2. Garbage-collect unreferenced blobs (stop → collect → start) +cd "$REGISTRY_COMPOSE_DIR" +docker compose stop registry +docker run --rm \ + -v "${REGISTRY_DATA_DIR}:/var/lib/registry" \ + registry:2 garbage-collect /etc/docker/registry/config.yml +docker compose start registry +log "Registry GC complete, registry restarted" + +# 3. Remove dangling Docker images from the host +PRUNED=$(docker image prune -f) +RECLAIMED=$(echo "$PRUNED" | awk '/Total reclaimed/{print $NF}') +log "Docker image prune complete: ${RECLAIMED:-0B} reclaimed" + +log "=== Registry cleanup done ===" diff --git a/docs/runbook-configuration.md b/docs/runbook-configuration.md index adff9fa..242b6c0 100644 --- a/docs/runbook-configuration.md +++ b/docs/runbook-configuration.md @@ -434,7 +434,32 @@ ansible-vault edit ansible/group_vars/all/vault.yml ansible-playbook -i ansible/inventory.ini ansible/site.yml --tags registry --ask-vault-pass ``` -### 8.2 Registry web UI +### 8.2 Automated garbage collection + +A cleanup script runs every **Sunday at 03:00** via cron (deployed by the +`registry` Ansible role). Each run: + +1. Deletes stale `_uploads/` sessions (failed or abandoned pushes) +2. Stops the registry, runs `garbage-collect` to remove unreferenced blobs, + then restarts it +3. Prunes dangling Docker images from the host + +Output is appended to `/var/log/registry-gc.log` and tagged `registry-gc` in +syslog. To check recent runs: + +```bash +tail -50 /var/log/registry-gc.log +# or +grep registry-gc /var/log/syslog +``` + +To run manually at any time: + +```bash +sudo /usr/local/bin/registry-gc +``` + +### 8.3 Registry web UI A web dashboard is available at `https://cr.ladkau.de/`. Sign in with any `registry_users` credential from the vault. The UI allows browsing repositories