fix(ci): cache de build com teto em todo job que builda imagem [INFRA-69215] #99

Merged
tmf-ia merged 1 commit from fix/INFRA-69215-cache-buildkit into develop 2026-10-10 11:23:59 -03:00
Owner

O que

Todo job de .forgejo/workflows que builda imagem passa a terminar com o passo Limpar cache de build (teto)
(if: always(), continue-on-error: true, timeout-minutes: 10):

docker buildx prune -f --builder <builder que o job usou> --filter until=24h --max-used-space "$TETO" \
  || echo "::warning::..."

Jobs que ganharam a limpeza:

  • build-ci-images.yml: build-python-ci, build-node-ci, build-docker-ci, build-nginx-base, build-trivy-ci,
    build-php-ci, build-android-ci, build-deploy-ci (docker build → --builder default);
  • reusable-image-cve-os.yml: cve-os (docker buildx build → o builder corrente, capturado antes do build em CVE_OS_BUILDER);
  • install-docker.yml: install (cria o buildkit-builder → --builder buildkit-builder).

O buildkit-builder do install-docker agora nasce com --buildkitd-config com gc ligada e teto.

Por quê

O disco raiz do host tmf-prod (onde roda o runner) lotou; o principal escritor é o cache de build do runner
(buildkit/containerd), INFRA-69105. Nenhum job removia cache: o cve-os só fazia docker rmi da tag, os 8 jobs do
build-ci-images nada, e o buildkit-builder era criado sem gc e nunca removido.

Achados

  • Varredura de docker build, buildx build/bake, compose build, build-push-action, buildx create em
    .forgejo/workflows: só os 10 jobs acima. release.yml não builda imagem no runner (deploy por SSH no host de destino).
  • Os jobs comuns usam o builder default (driver docker): o cache fica no daemon do host. O builder do install-docker
    vale só dentro daquele job container (metadado do buildx), mas o container buildx_buildkit_buildkit-builder0 e o volume
    de estado ficam no host.
  • O driver docker-container usa por padrão moby/buildkit:buildx-stable-1 do Docker Hub (fora do nosso registry). Não
    mexi aqui (fora do escopo); vale issue de soberania para pinar --driver-opt image= num espelho em tmf/mirror.

Flags (versão medida)

docker run --rm --entrypoint docker <registry>/tmf/ci-images/tmf-ci-docker:29.7.1-20261009-2e51884 buildx version
→ github.com/docker/buildx v0.36.0. O buildx prune --help lista --max-used-space, --min-free-space,
--reserved-space; --keep-storage sumiu do help e, usado, imprime
Flag --keep-storage has been deprecated, keep-storage flag has been changed to reserved-space (é piso, não teto).
Por isso o teto é --max-used-space. docker builder prune na CLI 29 é o mesmo comando (--builder padrão default).

Teto escolhido: 10 GB

Padrão 10gb, configurável: input build_cache_max_used_space (reusáveis) e env.BUILD_CACHE_MAX_USED_SPACE
(build-ci-images.yml). Com until=24h, só sai cache sem uso há 24h, e só enquanto o total passar do teto: o cache
quente dos builds do dia fica. 10 GB cabe o cache quente de vários produtos (cada build de produto deixa poucos GB) e é ~1%
do disco de 1 TB; hoje o cache do builder default desta máquina de dev já soma 32 GB, ordem de grandeza do que se acumula
sem limpeza.

gc do buildkit-builder

Config gerado no job (chaves do buildkit ≥ 0.17, sem gckeepstorage/keepBytes depreciadas):

[worker.oci]
  gc = true
  maxUsedSpace = "10gb"
[[worker.oci.gcpolicy]]
  keepDuration = "24h"
  maxUsedSpace = "10gb"
[[worker.oci.gcpolicy]]
  all = true
  maxUsedSpace = "10gb"

O config só vale na criação do container do builder. Um buildkit-builder que já existe no host sem gc segue sem
gc: o job detecta (sem regra Keep Duration: 24h0m0s no buildx inspect) e emite ::warning::, e o prune do último passo
segura o teto. Não recrio à força: buildx rm derruba build concorrente que esteja usando o builder. Para ligar a gc
nele, o operador roda docker buildx rm buildkit-builder fora do horário e o próximo job recria.

Validação

  • Prune real, sem efeito (tmf-ci-docker com o socket local, filtro until=876000h + teto 100tb, nada elegível):
    --max-used-space rc=0 Total: 0B; sem --builder rc=0; --keep-storage rc=0 com o aviso de depreciação;
    --builder nao-existe rc=1 (por isso o || ::warning::). docker buildx du igual antes e depois (32.54GB).
  • Config de gc: buildkitd moby/buildkit:v0.33.1 descartável com o toml → GC Policy rule#0: Keep duration 24h0m0s, Maximum used space 10.73GB; rule#1: All true, 10.73GB, sem aviso de chave depreciada.
  • Create real (builder descartável infra69215-teste, imagem buildkit local, removido no fim): buildx create --driver docker-container --buildkitd-config + inspect --bootstrap mostra as 2 regras; o prune do passo nele rc=0;
    nenhum container sobrou.
  • tests/cache-build/ (17 testes): todo job com build tem a limpeza como último passo, no builder certo; nenhum
    system prune -a/volume prune/image prune -a/--keep-storage; install-docker cria com gc; controle negativo
    (job sintético sem limpeza, limpeza no meio, builder errado) reprova; o run: real do passo, com docker falso que
    falha, sai 0 com ::warning::.
  • Todas as suítes de tests/* verdes (generate-docs precisa de python no PATH; aqui rodou com um link para python3).

Não verificado

  • Efeito no disco do host tmf-prod (nenhum job rodou com o passo ainda).
  • Comportamento do daemon do runner (versão do engine do host) com --max-used-space; medido no engine 29.8.1 local (API 1.56).

🤖 Generated with Claude Code

https://claude.ai/code/session_01ES1xwVdpQV69zEsuLLKzx2

## O que Todo job de `.forgejo/workflows` que builda imagem passa a terminar com o passo **`Limpar cache de build (teto)`** (`if: always()`, `continue-on-error: true`, `timeout-minutes: 10`): ```bash docker buildx prune -f --builder <builder que o job usou> --filter until=24h --max-used-space "$TETO" \ || echo "::warning::..." ``` Jobs que ganharam a limpeza: - `build-ci-images.yml`: `build-python-ci`, `build-node-ci`, `build-docker-ci`, `build-nginx-base`, `build-trivy-ci`, `build-php-ci`, `build-android-ci`, `build-deploy-ci` (`docker build` → `--builder default`); - `reusable-image-cve-os.yml`: `cve-os` (`docker buildx build` → o builder corrente, capturado antes do build em `CVE_OS_BUILDER`); - `install-docker.yml`: `install` (cria o `buildkit-builder` → `--builder buildkit-builder`). O `buildkit-builder` do `install-docker` agora nasce com `--buildkitd-config` com gc ligada e teto. ## Por quê O disco raiz do host tmf-prod (onde roda o runner) lotou; o principal escritor é o cache de build do runner (buildkit/containerd), INFRA-69105. Nenhum job removia cache: o `cve-os` só fazia `docker rmi` da tag, os 8 jobs do `build-ci-images` nada, e o `buildkit-builder` era criado sem gc e nunca removido. ## Achados - Varredura de `docker build`, `buildx build/bake`, `compose build`, `build-push-action`, `buildx create` em `.forgejo/workflows`: só os 10 jobs acima. `release.yml` não builda imagem no runner (deploy por SSH no host de destino). - Os jobs comuns usam o builder `default` (driver docker): o cache fica no daemon do host. O builder do `install-docker` vale só dentro daquele job container (metadado do buildx), mas o container `buildx_buildkit_buildkit-builder0` e o volume de estado ficam no host. - O driver docker-container usa por padrão `moby/buildkit:buildx-stable-1` do Docker Hub (fora do nosso registry). Não mexi aqui (fora do escopo); vale issue de soberania para pinar `--driver-opt image=` num espelho em `tmf/mirror`. ## Flags (versão medida) `docker run --rm --entrypoint docker <registry>/tmf/ci-images/tmf-ci-docker:29.7.1-20261009-2e51884 buildx version` → **`github.com/docker/buildx v0.36.0`**. O `buildx prune --help` lista `--max-used-space`, `--min-free-space`, `--reserved-space`; `--keep-storage` sumiu do help e, usado, imprime `Flag --keep-storage has been deprecated, keep-storage flag has been changed to reserved-space` (é piso, não teto). Por isso o teto é `--max-used-space`. `docker builder prune` na CLI 29 é o mesmo comando (`--builder` padrão `default`). ## Teto escolhido: 10 GB Padrão `10gb`, configurável: input `build_cache_max_used_space` (reusáveis) e `env.BUILD_CACHE_MAX_USED_SPACE` (`build-ci-images.yml`). Com `until=24h`, só sai cache **sem uso há 24h**, e só enquanto o total passar do teto: o cache quente dos builds do dia fica. 10 GB cabe o cache quente de vários produtos (cada build de produto deixa poucos GB) e é ~1% do disco de 1 TB; hoje o cache do builder default desta máquina de dev já soma 32 GB, ordem de grandeza do que se acumula sem limpeza. ## gc do `buildkit-builder` Config gerado no job (chaves do buildkit ≥ 0.17, sem `gckeepstorage`/`keepBytes` depreciadas): ```toml [worker.oci] gc = true maxUsedSpace = "10gb" [[worker.oci.gcpolicy]] keepDuration = "24h" maxUsedSpace = "10gb" [[worker.oci.gcpolicy]] all = true maxUsedSpace = "10gb" ``` O config só vale na **criação** do container do builder. Um `buildkit-builder` que já existe no host sem gc segue sem gc: o job detecta (sem regra `Keep Duration: 24h0m0s` no `buildx inspect`) e emite `::warning::`, e o prune do último passo segura o teto. **Não recrio à força**: `buildx rm` derruba build concorrente que esteja usando o builder. Para ligar a gc nele, o operador roda `docker buildx rm buildkit-builder` fora do horário e o próximo job recria. ## Validação - **Prune real, sem efeito** (tmf-ci-docker com o socket local, filtro `until=876000h` + teto `100tb`, nada elegível): `--max-used-space` rc=0 `Total: 0B`; sem `--builder` rc=0; `--keep-storage` rc=0 com o aviso de depreciação; `--builder nao-existe` rc=1 (por isso o `|| ::warning::`). `docker buildx du` igual antes e depois (32.54GB). - **Config de gc**: buildkitd `moby/buildkit:v0.33.1` descartável com o toml → `GC Policy rule#0: Keep duration 24h0m0s, Maximum used space 10.73GB; rule#1: All true, 10.73GB`, sem aviso de chave depreciada. - **Create real** (builder descartável `infra69215-teste`, imagem buildkit local, removido no fim): `buildx create --driver docker-container --buildkitd-config` + `inspect --bootstrap` mostra as 2 regras; o prune do passo nele rc=0; nenhum container sobrou. - `tests/cache-build/` (17 testes): todo job com build tem a limpeza como **último** passo, no builder certo; nenhum `system prune -a`/`volume prune`/`image prune -a`/`--keep-storage`; install-docker cria com gc; controle negativo (job sintético sem limpeza, limpeza no meio, builder errado) reprova; o `run:` real do passo, com `docker` falso que falha, sai 0 com `::warning::`. - Todas as suítes de `tests/*` verdes (`generate-docs` precisa de `python` no PATH; aqui rodou com um link para python3). ## Não verificado - **Efeito no disco do host tmf-prod** (nenhum job rodou com o passo ainda). - Comportamento do daemon do runner (versão do engine do host) com `--max-used-space`; medido no engine 29.8.1 local (API 1.56). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01ES1xwVdpQV69zEsuLLKzx2
fix(ci): cache de build com teto em todo job que builda imagem [INFRA-69215]
All checks were successful
PR checks (ci-shared) / testes (pull_request) Successful in 4m30s
557ab18158
O disco raiz do host do runner (tmf-prod) lotou; o maior escritor era o cache
do buildkit que os jobs de build deixavam e ninguém removia (INFRA-69105).

- build-ci-images.yml (8 jobs), reusable-image-cve-os.yml (cve-os) e
  install-docker.yml (install) terminam com "Limpar cache de build (teto)":
  if: always(), continue-on-error, `docker buildx prune -f --builder <o que o
  job usou> --filter until=24h --max-used-space <teto>`; falha vira :⚠️:.
- Teto padrão 10gb: input build_cache_max_used_space nos reusáveis,
  env.BUILD_CACHE_MAX_USED_SPACE no build-ci-images.
- Flags medidas no buildx v0.36.0 da tmf-ci-docker:29.7.1-20261009-2e51884
  (--keep-storage depreciado -> reserved-space; o teto é --max-used-space).
- buildkit-builder nasce com --buildkitd-config (gc = true, gcpolicy com
  keepDuration 24h + maxUsedSpace); builder antigo sem gc gera :⚠️: e
  não é recriado à força.
- tests/cache-build: reprova job de build sem a limpeza como último passo,
  builder errado, system prune -a / volume prune / --keep-storage.
- CHANGELOG e docs/workflows-reusaveis.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ES1xwVdpQV69zEsuLLKzx2
tmf-ia merged commit eaa7695aa1 into develop 2026-10-10 11:23:59 -03:00
Sign in to join this conversation.
No reviewers
No labels
seguranca
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
TMF/ci-shared!99
No description provided.