--- # description: Reclaim disk on swarm nodes but keep every image a swarm service is pinned to, so each node can take over the others' services without pulling. # steward:category: maintenance # steward:confirm: true # Run on the swarm's nodes; each must be a manager (only a manager can list # services). On each node: # 1. docker system prune: stopped containers, unused networks, dangling # images, build cache (+ prune_volumes=true: unused anonymous volumes). # 2. files/swarm_prune.py: removes every other image no container uses and # no swarm service is pinned to, wherever that service's task runs. A # node keeps the images for the services running elsewhere, so it can # start them at once when the other node fails or is drained. # A node that can't list the swarm's services removes no images and the run # fails, rather than pruning blind. Check mode lists what would go. - name: Swarm prune hosts: all gather_facts: false become: true vars: prune_volumes: false tasks: - name: Prune stopped containers, unused networks, dangling images and build cache ansible.builtin.command: argv: >- {{ ['docker', 'system', 'prune', '-f'] + (['--volumes'] if prune_volumes | bool else []) }} register: system_prune changed_when: "'Total reclaimed space: 0B' not in system_prune.stdout" - name: Remove images no container uses and no swarm service is pinned to ansible.builtin.script: cmd: "swarm_prune.py{{ ' --dry-run' if ansible_check_mode else '' }}" executable: python3 check_mode: false register: image_prune changed_when: >- not ansible_check_mode and (image_prune.stdout | from_json).removed | default([]) | length > 0 - name: Report what went ansible.builtin.debug: msg: >- {{ (system_prune.stdout_lines | default([]) | select | list)[-1:] + [image_prune.stdout | from_json] }}