scripts/prune-docker.sh

#!/usr/bin/env bash
# scripts/prune-docker.sh
# A safer docker system prune: only containers exited > 48h, only
# images not referenced by any compose file in /srv/homelab/stacks,
# and never volumes unless --volumes is passed explicitly.

set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
. "${HERE}/lib/log.sh"

INCLUDE_VOLUMES=0
DRY=0
while (( $# )); do
    case "$1" in
        --volumes) INCLUDE_VOLUMES=1 ;;
        --dry-run) DRY=1 ;;
        *) log_err "unknown arg: $1"; exit 2 ;;
    esac
    shift
done

say() { (( DRY )) && printf 'DRY ' || true; log_info "$*"; }

exited=$(docker ps -a --filter 'status=exited' --filter 'until=48h' \
    --format '{{.ID}} {{.Names}}')
if [[ -n "${exited}" ]]; then
    say "removing exited containers"
    while read -r id name _; do
        (( DRY )) || docker rm "${id}" >/dev/null || true
        log_info "rm ${name}"
    done <<<"${exited}"
fi

say "removing dangling images"
(( DRY )) || docker image prune -f >/dev/null

say "removing build cache older than 72h"
(( DRY )) || docker builder prune -af --filter 'until=72h' >/dev/null

if (( INCLUDE_VOLUMES )); then
    log_warn "including dangling volumes (double-check nothing important)"
    (( DRY )) || docker volume prune -f >/dev/null
fi

log_info "disk after prune:"
docker system df