
Curso Kubernetes 24 — CI/CD: imagens imutáveis e SBOM
O deploy falha menos por Kubernetes e mais por artefato: imagem com tag mutável, build diferente por ambiente, dependência sem rastro. Este capítulo é sobre tornar o artefato confiável e rastreável.
Regra que resolve a maior parte: construa uma vez, promova o mesmo digest.
Selo do curso: testado com GitHub Actions, GHCR e Kubernetes 1.35.
Tag mutável é o problema
portal-backend:latest e até :v5 podem apontar para imagens diferentes amanhã. O pod rodando não é o pod que você testou.
Use:
sha-<commit>como tag principal.- Digest (
@sha256:...) no deploy. - Sem
latestem produção.
docker build -t ghcr.io/example/portal-backend:sha-$GIT_SHA .
docker push ghcr.io/example/portal-backend:sha-$GIT_SHA
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/example/portal-backend:sha-$GIT_SHA | cut -d@ -f2)
echo "$DIGEST"
No manifest:
image: ghcr.io/example/portal-backend@sha256:2f0c...c91
Digest é imutável por construção.
Separe build de deploy
| Etapa | O que roda | Ambiente |
|---|---|---|
| build | teste, lint, imagem, scan | runner |
| publish | push + SBOM + assinatura | runner |
| deploy homolog | atualiza digest no GitOps | ArgoCD |
| promove prod | PR com o mesmo digest | ArgoCD |
O pipeline de prod não compila. Ele só troca o digest no repositório GitOps. Isso elimina "funcionou em homolog" por diferença de build.
Pipeline mínimo
name: build
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:sha-${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
Cache de build reduz minutos e, mais importante, torna o build reprodutível.
Scan de vulnerabilidade
trivy image --severity HIGH,CRITICAL --exit-code 1 \
ghcr.io/example/portal-backend:sha-$GIT_SHA
Estruture o gate:
- CRITICAL com correção disponível: bloqueia.
- CRITICAL sem correção: registra e acompanha.
- HIGH: alerta, não bloqueia no início.
Bloquear tudo no primeiro dia paralisa o time. O objetivo é reduzir, não travar.
SBOM
SBOM é a lista de componentes da imagem. Sem ela, você não responde "estamos afetados por Log4Shell?" em minutos.
syft ghcr.io/example/portal-backend:sha-$GIT_SHA -o spdx-json > sbom.spdx.json
Com Trivy:
trivy image --format spdx-json -o sbom.spdx.json ghcr.io/example/portal-backend:sha-$GIT_SHA
Publique o SBOM como artefato do pipeline e referencie no release. Formatos comuns: SPDX e CycloneDX.
Assinatura e proveniência
- cosign assina a imagem.
- SLSA provenance registra como ela foi construída.
- Admission controller (Kyverno/cosign policy) recusa imagem não assinada.
cosign sign --yes ghcr.io/example/portal-backend@sha256:2f0c...c91
cosign verify ghcr.io/example/portal-backend@sha256:2f0c...c91 \
--certificate-identity-regexp '.*' --certificate-oidc-issuer https://token.actions.githubusercontent.com
Isso fecha a cadeia: commit → build → assinatura → deploy.
O erro de segurança que já vimos
Um build passou porque o MinIO usava minioadmin como credencial padrão. O pipeline não validava configuração — só compilava. Resultado: deploy quebrado no cluster com INF-SEC-01.
Lição: o pipeline precisa de um gate de configuração, não só de teste unitário:
grep -rE 'minioadmin|changeme|password.*=.*(admin|123)' deploy/ && exit 1
Simples, e teria evitado o incidente.
Rastreabilidade: do pod ao commit
Padronize labels:
metadata:
labels:
app.kubernetes.io/name: portal-backend
app.kubernetes.io/version: sha-3f9c1a
org.opencontainers.image.revision: 3f9c1a...
Com isso:
kubectl -n portal get pod -l app.kubernetes.io/version=sha-3f9c1a
Você responde "qual pod roda o commit X" em segundos — e o inverso também.
Laboratório
- Configure um pipeline que gera
sha-<commit>e faz push. - Rode Trivy e veja o relatório.
- Gere o SBOM em SPDX e inspecione dependências.
- Troque o deploy para usar digest e confirme
imageIDno pod:
kubectl -n portal get pod -o jsonpath='{.items[*].status.containerStatuses[*].imageID}'
- Faça um commit que introduz uma credencial falsa e veja o gate falhar.
- Promova o mesmo digest de homolog para prod sem rebuild.
Erros comuns
| Sintoma | Causa |
|---|---|
| Prod diferente de homolog | build separado por ambiente |
ImagePullBackOff |
credencial de registry ou tag inexistente |
| Deploy “funcionou” e quebrou | tag mutável reutilizada |
| SBOM não gerado | etapa falhou silenciosamente |
| Scan bloqueia tudo | severidade sem política de exceção |
| Imagem sem assinatura aceita | falta admission policy |
| Rastreabilidade perdida | imagem sem label de revisão |
Checklist
- [ ] Build único por commit.
- [ ] Tag
sha-<commit>e deploy por digest. - [ ] Nenhum
latestem produção. - [ ] Scan com severidade e política definidas.
- [ ] SBOM gerado e arquivado.
- [ ] Assinatura e verificação (cosign/Kyverno).
- [ ] Gate de configuração (credenciais padrão).
- [ ] Labels de versão/revisão nos pods.
- [ ] Promoção por PR no repo GitOps.
Glossário
- digest: hash imutável da imagem.
- SBOM: inventário de componentes.
- SLSA: framework de integridade de build.
- provenance: registro de como o artefato foi construído.
- cosign: ferramenta de assinatura.
- gate: etapa que bloqueia o pipeline.
Próximo
Artefato confiável e rastreável. Agora endurecer o cluster: RBAC, Pod Security Admission, NetworkPolicy e gestão de segredos.
Próximo: Curso Kubernetes 25 — Segurança: RBAC, PSA, NetworkPolicy e secrets
Continuar a ler
Leia também
KubernetesKubernetes de Verdade — do zero ao cluster em produção
Uma trilha prática para entender, montar e operar um cluster Kubernetes — do primeiro pod ao failover do Postgres.
4 min de leitura
KubernetesCurso Kubernetes 28 — DR e capstone: provar que o cluster volta
RPO, RTO e drills reais: cenários de desastre, runbook, restore medido e o capstone que fecha o curso com um cluster que se recupera.
5 min de leitura
KubernetesCurso Kubernetes 27 — SLO/SLI, on-call e postmortem blameless
O que prometer, como medir e o que fazer quando o erro estoura: SLI, SLO, error budget, alertas que acordam alguém e postmortem sem caça às bruxas.
4 min de leitura
Comentários
Ainda sem comentários
Seja o primeiro a compartilhar sua opinião sobre este artigo.
Deixe um comentário