Aprenda / Infraestrutura — Docker

IntermediárioAula 15 de 1617 min0% da trilha

CI/CD com Docker: build, push e deploy automatizado

Fazer build, push e deploy na mão funciona uma vez — um pipeline garante que funciona todas as vezes, do mesmo jeito.

Na lição de deploy da trilha de fundamentos, os comandos docker build, docker push e docker pull foram digitados na mão. Isso ensina o que cada passo faz, mas não escala: alguém esquece um passo, roda numa ordem errada, ou builda com o código errado. Um pipeline de CI/CD automatiza exatamente essa sequência, sempre do mesmo jeito, disparado por um evento (um push, um merge de PR).

O pipeline: build → teste → push → deploy

.github/workflows/deploy.yml (GitHub Actions)
name: Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build da imagem
        run: docker build -t minha-api:${{ github.sha }} .

      - name: Rodar testes dentro do container
        run: docker run --rm minha-api:${{ github.sha }} npm test

      - name: Login no registry
        run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login registry.exemplo.com -u ci --password-stdin

      - name: Push da imagem
        run: |
          docker tag minha-api:${{ github.sha }} registry.exemplo.com/minha-api:${{ github.sha }}
          docker tag minha-api:${{ github.sha }} registry.exemplo.com/minha-api:latest
          docker push registry.exemplo.com/minha-api:${{ github.sha }}
          docker push registry.exemplo.com/minha-api:latest

      - name: Deploy no servidor
        run: ssh deploy@servidor "docker compose pull && docker compose up -d"

Rodar teste DENTRO do container, não fora dele

Repare que o passo de teste roda docker run --rm minha-api:sha npm test — dentro da própria imagem que acabou de ser buildada, não numa instalação separada de Node no runner do CI. Isso garante que o ambiente testado é exatamente o mesmo que vai pra produção: mesma versão de sistema operacional, mesmas bibliotecas nativas, mesma versão de runtime. Testar fora do container e depois buildar a imagem separadamente reabre a porta pro clássico "passou no CI, quebrou em produção".

Tag baseada no commit, não só 'latest'

Tagear com github.sha (o hash do commit) além de latest dá rastreabilidade: dá pra saber exatamente qual código gerou aquela imagem, e — se algo quebrar depois do deploy — fazer rollback pra uma tag anterior específica, em vez de "latest", que muda de significado a cada push.

terminal — rollback manual usando a tag do commit
# volta pra imagem do commit anterior, sem precisar rebuildar nada
docker pull registry.exemplo.com/minha-api:a1b2c3d
docker compose up -d

Redeploy automatizado no servidor

O último passo do pipeline conecta no servidor (via SSH, ou um webhook que dispara um script equivalente) e roda docker compose pull (baixa a imagem nova do registry) seguido de docker compose up -d (recria os containers que mudaram, mantendo os que não mudaram intactos). O servidor nunca precisa ter o código-fonte nem as ferramentas de build — só o Docker instalado e acesso ao registry.

Exercício

O pipeline acima builda, testa, publica e faz deploy sempre que há um push na branch main. O time quer que pull requests também rodem o build e os testes (pra pegar erro antes do merge), mas sem nunca publicar imagem nem fazer deploy a partir de um PR. O que muda no on: e nos jobs desse workflow?

Quiz rápido

Por que rodar os testes dentro do mesmo container/imagem que vai pra produção, em vez de rodar só na máquina do CI?
Por que tagear a imagem com o hash do commit, além de 'latest', no push pro registry?