Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 101 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
name: CI
name: CI/CD

on:
push:
pull_request:

jobs:
build-and-test:
name: CI - build e testes
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout do código
Expand Down Expand Up @@ -54,3 +57,100 @@ jobs:
- name: Derrubar a stack
if: always()
run: docker compose down -v

publish:
name: CD - publicar imagem no GHCR
runs-on: ubuntu-latest
needs: build-and-test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write

steps:
- name: Checkout do código
uses: actions/checkout@v4

- name: Definir o nome da imagem em minúsculas
id: img
run: echo "name=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT"

- name: Configurar o Buildx
uses: docker/setup-buildx-action@v3

- name: Login no GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Montar as tags e labels da imagem
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.img.outputs.name }}
tags: |
type=raw,value=latest
type=sha,format=short

- name: Build e push da imagem
id: build
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Smoke test da imagem que acabou de ser publicada
env:
IMAGE: ${{ steps.img.outputs.name }}
DIGEST: ${{ steps.build.outputs.digest }}
run: |
echo "Baixando $IMAGE@$DIGEST do registry..."
docker run -d --name deploy-check -p 3000:3000 "$IMAGE@$DIGEST"
for i in $(seq 1 20); do
if curl -sf http://localhost:3000/items > /dev/null; then
echo "A imagem publicada subiu e respondeu OK"
docker rm -f deploy-check
exit 0
fi
echo "tentativa $i..."
sleep 3
done
echo "A imagem publicada nao respondeu a tempo"
docker logs deploy-check
docker rm -f deploy-check
exit 1

- name: Resumo da entrega
if: success()
env:
IMAGE: ${{ steps.img.outputs.name }}
DIGEST: ${{ steps.build.outputs.digest }}
TAGS: ${{ steps.meta.outputs.tags }}
run: |
{
echo "### Imagem publicada no GHCR"
echo ""
echo "| campo | valor |"
echo "| --- | --- |"
echo "| imagem | \`$IMAGE\` |"
echo "| digest | \`$DIGEST\` |"
echo "| commit | \`$GITHUB_SHA\` |"
echo ""
echo "Tags publicadas:"
echo ""
echo '```'
echo "$TAGS"
echo '```'
echo ""
echo "Para rodar localmente:"
echo ""
echo '```bash'
echo "docker run -d -p 3000:3000 $IMAGE:latest"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,38 @@ Porque o Docker tem um DNS interno na rede todo-net que resolve o nome do servi
![ci log](docs/imagens/10.1-ci-log.png)


## 7.1 Entrega Contínua (CD) — extra

**Arquivo do workflow:** `.github/workflows/ci.yml`, job `publish` **Gatilho:** push na branch `main`, e somente se o job de CI (`build-and-test`) tiver passado — `needs: build-and-test` **Destino:** GitHub Container Registry (`ghcr.io/tomd4vs/project-docker`)

**O que o pipeline de CD faz:**

1. Autentica no `ghcr.io` usando o `GITHUB_TOKEN` do próprio repositório (nenhum secret manual)
2. Gera as tags da imagem: `latest` e `sha-<commit>`, para rastrear qual commit gerou qual imagem
3. Builda e faz push da imagem para o registry, com cache de layers entre execuções
4. Baixa de volta do registry a imagem recém-publicada e sobe ela — se não responder no `/items`, o deploy falha
5. Publica um resumo da entrega com o digest da imagem

**Por que o CD só roda na main e depois do CI?** O `needs: build-and-test` transforma o CI em portão: enquanto os testes não passam, o job de publicação nem começa, então imagem quebrada nunca chega ao registry. O `if: github.ref == 'refs/heads/main'` garante que branches de trabalho e Pull Requests rodem só a validação, sem publicar nada — foi exatamente o caso do PR da seção 7.

**Diferença entre CI e CD aqui:** o CI valida o código num ambiente descartável e joga tudo fora no final (`docker compose down -v`). O CD pega o mesmo código já aprovado, empacota num artefato versionado e imutável (imagem identificada por digest) e entrega esse artefato num registry, de onde qualquer ambiente pode consumir.

**Print 11 — pipeline completo: CI verde seguido do CD**

<!-- ![pipeline cd](docs/imagens/11-cd-pipeline.png) -->

**Print 11.1 — log do job de publicação + resumo com o digest**

<!-- ![cd log](docs/imagens/11.1-cd-log.png) -->

**Print 11.2 — imagem publicada no GHCR com as tags**

<!-- ![ghcr package](docs/imagens/11.2-ghcr-package.png) -->

**Print 11.3 — `docker pull` + `docker run` da imagem publicada, rodando na máquina local**

<!-- ![pull da imagem](docs/imagens/11.3-pull-imagem.png) -->

## 8. Dificuldades e aprendizados

Minha principal dificuldade foi na primeira configuração do ambiente, pois não tinha trabalhado com a ferramenta. Repeti o processo em outros dois computadores, ganhei prática e, na terceira vez, consegui instalar as ferramentas de forma simples e prática. O aprendizado foi ótimo: já apliquei parte do que vi em projetos em que estou trabalhando e ainda aproveitei as dicas do professor sobre instalação e configurações para Ubuntu Server.
Expand All @@ -140,3 +172,4 @@ Minha principal dificuldade foi na primeira configuração do ambiente, pois nã
- [x] CI verde
- [x] PR com CI vermelho documentado
- [x] Todos os 9 prints no README
- [ ] CD publicando a imagem no registry (extra)
Loading