Configurar BuildKit garbage collection e systemd timers para limpeza automática de imagens e volumes Docker em VPS: tutorial prático
Docker & Containers · Por Kevin Marcondes · Publicado em · 9 min de leitura
Este tutorial mostra como configurar BuildKit garbage collection e systemd timers para limpeza automática de imagens e volumes Docker em VPS. Você vai aplicar políticas seguras, usar labels para exceções e criar services/timers do systemd para controlar cache de build, imagens antigas e volumes temporários, evitando surpresas em produção.
Pré‑requisitos e o que será automatizado
A rotina combina o GC do BuildKit (cache de build) e a remoção controlada de artefatos do Docker (containers parados, imagens antigas e volumes rotulados). O objetivo é reduzir uso de disco sem afetar serviços em execução.
Antes de seguir, confirme que você tem acesso sudo, Docker e systemd ativos. Faça um snapshot/backup se houver dados críticos. Alguns passos removem dados antigos ou temporários.
Para segurança, imagens ativas não são removidas, e volumes só são excluídos quando marcados com uma label de autoclean e sem uso. Se você ainda vai preparar o host, veja como instalar Docker e Compose em Linux em este guia.
- Docker Engine e buildx instalados
- Acesso sudo para criar services/timers
- Espaço livre temporário para rodar a limpeza
- Backups ou snapshot do host
| Alvo | Comando principal | Critérios | Observações |
|---|---|---|---|
| Cache de build (BuildKit) | docker buildx prune -af --keep-storage 20GB | Manter N GB de cache | Não toca imagens/volumes; só cache de build |
| Imagens | docker image prune -a -f --filter 'until=240h' | Idade > 10 dias e não usadas | Pode excluir versões antigas não referenciadas |
| Containers parados | docker container prune -f --filter 'until=240h' | Idade > 10 dias e parados | Libera camadas e logs antigos |
| Volumes | docker volume rm $(docker volume ls -q --filter 'label=autoclean=true' --filter 'dangling=true') | Apenas com label autoclean e sem uso | Evita apagar dados importantes por engano |
O que o BuildKit realmente limpa com GC?
O GC do BuildKit remove apenas cache de build (camadas e artefatos temporários gerados em builds). Ele não remove imagens publicadas, containers, volumes ou networks. Usaremos docker buildx prune com limite de armazenamento para manter um cache útil e estável.
Para imagens e volumes, criaremos rotinas separadas com filtros de idade e labels. Assim, cada alvo tem regras claras e independentes.
Como ver o consumo de cache, imagens e volumes agora?
Antes de automatizar, meça onde está o consumo. O buildx du mostra o uso do cache de build por repositório/estágio. O docker system df detalha imagens, containers e volumes. Liste volumes dangling para identificar candidatos à limpeza sem risco.
# Uso do cache de build (BuildKit)
docker buildx du --verbose
# Uso geral de disco (imagens, containers, volumes)
docker system df -v
# Volumes sem uso (dangling)
docker volume ls --filter dangling=true
Configurar BuildKit GC com systemd timers (política por armazenamento)
Vamos agendar docker buildx prune para manter o cache de build dentro de um teto (keep-storage). A execução via systemd garante logs e retomada se o host estiver desligado no horário.
Se você usa um builder dedicado (driver docker-container), ajuste o alvo do builder com a flag apropriada ao seu ambiente. Boas práticas de timers estão em migrar cron para systemd timers. Para acelerar builds com cache remoto, veja o guia de cache remoto com BuildKit.
# Service e timer para GC do BuildKit (cache de build)
# Crie os arquivos abaixo
sudo tee /etc/systemd/system/buildkit-prune.service >/dev/null <<'EOF'
[Unit]
Description=BuildKit cache prune (docker buildx)
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
# Ajuste o limite conforme seu disco (ex.: 10GB, 20GB, 50GB)
ExecStart=/usr/bin/docker buildx prune -af --keep-storage 20GB
Nice=10
IOSchedulingClass=idle
EOF
sudo tee /etc/systemd/system/buildkit-prune.timer >/dev/null <<'EOF'
[Unit]
Description=Run BuildKit cache prune weekly
[Timer]
OnCalendar=Sun *-*-* 03:15:00
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now buildkit-prune.timer
Script seguro para limpar imagens e volumes por idade e labels
O script abaixo remove containers parados antigos, limpa imagens não usadas e apaga apenas volumes sem uso marcados com label autoclean=true. Revise os filtros antes de ativar em produção. Para proteger imagens críticas, use uma label keep=true e o filtro do prune irá preservá-las.
# Dica: rotule recursos para controle fino (exemplos):
# docker volume create --label autoclean=true tmp_cache
# docker build -t minhaimg:latest --label keep=true .
sudo tee /usr/local/sbin/docker-gc-safe.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
log() { echo "[$(date -Is)] $*"; }
if ! docker info >/dev/null 2>&1; then
log "Docker não está acessível; saindo."
exit 0
fi
# 1) Containers parados antigos (ex.: >10 dias)
log "Pruning containers parados (>10d)"
docker container prune -f --filter "until=240h" || true
# 2) Imagens não usadas antigas, preservando as rotuladas com keep
log "Pruning imagens antigas não usadas (>10d), exceto label keep"
docker image prune -a -f \
--filter "until=240h" \
--filter "label!=keep" || true
# 3) Volumes sem uso e rotulados para autoclean
log "Removendo volumes sem uso com label autoclean=true"
mapfile -t VOLS < <(docker volume ls -q \
--filter "label=autoclean=true" \
--filter "dangling=true") || true
if ((${#VOLS[@]} > 0)); then
docker volume rm "${VOLS[@]}" || true
else
log "Nenhum volume elegível encontrado"
fi
log "Limpeza concluída"
EOF
sudo chmod +x /usr/local/sbin/docker-gc-safe.sh
Como agendar o script de limpeza com um systemd timer?
Crie um service oneshot e um timer diário com atraso aleatório para evitar colisões com janelas de backup. O Persistent=true executa a tarefa atrasada se o host ficou desligado.
Se você usa Docker rootless, crie units no systemd de usuário (systemctl --user) e armazene o script no seu $HOME/bin. Para integrar com sua estratégia de proteção, considere agendar snapshots e uploads para object storage usando timers, como neste guia de LVM+Restic em S3 passo a passo.
sudo tee /etc/systemd/system/docker-gc.service >/dev/null <<'EOF'
[Unit]
Description=Rotina de limpeza segura de Docker (containers, imagens e volumes com label)
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/docker-gc-safe.sh
Nice=10
IOSchedulingClass=idle
EOF
sudo tee /etc/systemd/system/docker-gc.timer >/dev/null <<'EOF'
[Unit]
Description=Agendar limpeza segura de Docker diariamente
[Timer]
OnCalendar=daily
RandomizedDelaySec=45m
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now docker-gc.timer
Como confirmar que funcionou e onde ver logs?
Confirme timers ativos, leia os logs e meça a redução de espaço com docker system df e buildx du. Se uma execução foi perdida, o Persistent=true reexecuta na volta do host. Isso ajuda a manter BuildKit garbage collection e systemd timers confiáveis na sua VPS.
# Timers ativos
systemctl list-timers '*buildkit*' '*docker-gc*'
# Logs da última execução
journalctl -u buildkit-prune.service -u docker-gc.service --since "-2d" -e
# Medir economia de espaço
docker system df -v
docker buildx du --verbose
Problemas comuns e ajustes finos
Alguns cenários pedem ajustes nos filtros. Priorize rótulos para exceções e revise janelas de idade em ambientes com baixa taxa de deploy. Em registros privados extensos, rode imagens semanalmente e cache diariamente.
- Imagens críticas sumindo: adicione label keep=true ao build e preserve com --filter label!=keep.
- Cache de build insuficiente: aumente --keep-storage (ex.: 30GB).
- Volumes removidos cedo: rotule autoclean=true somente em volumes temporários; nunca em volumes de banco de dados.
- Docker rootless: crie timers com systemctl --user e garanta o serviço do Docker de usuário ativo.
- Concorrência com backups: ajuste OnCalendar para fora da janela de snapshot/backup.
- Sem espaço para rodar prune: limpe primeiro apenas dangling (docker image prune -f) e, se preciso, mova volumes grandes para outro disco seguindo este tutorial de migração de volumes Docker passo a passo.
Perguntas frequentes
É seguro rodar prune automaticamente no Docker?
Sim, quando você define filtros conservadores e usa labels para exceções. Aplique idade (until=...) para containers e imagens e remova apenas volumes sem uso com label autoclean=true. Tenha snapshots ou backups recentes antes da primeira execução.
Qual a diferença entre docker system prune e buildx prune?
docker system prune remove recursos do Docker (containers parados, imagens não usadas, redes e volumes anônimos). Já docker buildx prune remove somente o cache de build do BuildKit. Combine ambos com critérios distintos e agendamentos separados.
Com que frequência devo executar o GC e os timers?
Diariamente para cache de build e containers parados, e semanalmente para imagens antigas costuma equilibrar espaço e desempenho. Ajuste a janela de idade e o keep-storage conforme sua taxa de deploy e o tamanho do disco.
Como impedir que imagens críticas sejam removidas?
Rotule-as com keep=true no build e adicione o filtro --filter label!=keep ao docker image prune. Versões marcadas ficam preservadas mesmo se forem antigas e não referenciadas por containers.
Posso usar isso em Docker rootless?
Sim. Crie o service e o timer no systemd de usuário (systemctl --user) e garanta que a sessão de usuário esteja habilitada no login. O restante do fluxo (buildx prune, image prune, volume rm) funciona da mesma forma.
O timer executa se a VPS estiver desligada no horário?
Sim. Quando o timer tem Persistent=true, o systemd dispara a próxima execução pendente assim que o sistema volta. Os logs ficam acessíveis no journalctl para auditoria e troubleshooting.
Quer padronizar a limpeza sem riscos?
Precisa revisar filtros, labels e horários para seu ambiente? Descreva seu cenário e validamos juntos as políticas, com dry‑run e rollback seguro.
Falar sobre políticas de GCVeja também
- tutorial: configurar mTLS entre Traefik e serviços em Docker Compose usando smallstep CA e certificados automáticos — passo a passo
- Tutorial: integrar Sentry ao pipeline de deploy com GitHub Actions para upload automático de source maps e criação de issues (PHP e JavaScript) — passo a passo
- Configurar retenção e compactação de logs de containers Docker com journald + logrotate + rsyslog em VPS com pouco disco
- tutorial: configurar GitHub Actions para testes de integração com PostgreSQL em containers efêmeros e rollback automático de migrações — guia prático