Build e push de imagem Docker com GitHub Actions

    Construir imagens Docker no CI e publicar em um registry é o padrão para deploys reproduzíveis — a VPS sempre executa exatamente a imagem que passou pelos testes. GitHub Container Registry (GHCR) é gratuito para repositórios públicos e privados com GitHub Free, eliminando a necessidade de Docker Hub ou registries pagos.

    Workflow completo de build e push

    Build da imagem Docker e push para GitHub Container Registry com cache:

    yaml
    # .github/workflows/docker-build.yml
    name: Build e Push Docker
    
    on:
      push:
        branches: [main, develop]
        tags: ['v*.*.*']
      pull_request:
        branches: [main]
    
    env:
      REGISTRY: ghcr.io
      IMAGE_NAME: ${{ github.repository }}   # ex: usuario/minha-api
    
    jobs:
      build-and-push:
        runs-on: ubuntu-latest
        permissions:
          contents: read
          packages: write              # necessário para push no GHCR
    
        steps:
          - name: Checkout
            uses: actions/checkout@v4
    
          - name: Login no GHCR
            if: github.event_name != 'pull_request'
            uses: docker/login-action@v3
            with:
              registry: ${{ env.REGISTRY }}
              username: ${{ github.actor }}
              password: ${{ secrets.GITHUB_TOKEN }}   # automático, sem config
    
          - name: Extrair metadata (tags e labels)
            id: meta
            uses: docker/metadata-action@v5
            with:
              images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
              tags: |
                type=ref,event=branch
                type=semver,pattern={{version}}
                type=semver,pattern={{major}}.{{minor}}
                type=sha,prefix=sha-
    
          - name: Configurar Docker Buildx
            uses: docker/setup-buildx-action@v3
    
          - name: Build e Push
            uses: docker/build-push-action@v6
            with:
              context: .
              push: ${{ github.event_name != 'pull_request' }}
              tags: ${{ steps.meta.outputs.tags }}
              labels: ${{ steps.meta.outputs.labels }}
              cache-from: type=gha        # cache do GitHub Actions
              cache-to: type=gha,mode=max
    Dica
    GITHUB_TOKEN é gerado automaticamente pelo GitHub Actions — não precisa criar ou configurar. permissions: packages: write autoriza o token a fazer push no GHCR.

    Estratégia de tags automáticas

    O metadata-action gera tags automaticamente baseadas em branch, tag e commit:

    bash
    # Tags geradas automaticamente pelo metadata-action:
    
    # Push no branch main:
    # ghcr.io/usuario/app:main
    # ghcr.io/usuario/app:sha-abc1234
    
    # Push de tag v1.2.3:
    # ghcr.io/usuario/app:1.2.3
    # ghcr.io/usuario/app:1.2
    # ghcr.io/usuario/app:latest (tag semver com latest=true)
    
    # Pull Request:
    # Imagem buildada mas não publicada (push: false)
    # Útil para verificar que o build não quebra
    
    # Usar a imagem na VPS:
    # docker compose pull
    # docker compose up -d
    
    # docker-compose.yml na VPS:
    # services:
    #   app:
    #     image: ghcr.io/usuario/minha-api:main
    #     # ou: image: ghcr.io/usuario/minha-api:1.2.3

    Pull de imagem privada na VPS

    Para fazer pull de imagem privada do GHCR na VPS, autentique o Docker:

    bash
    # Na VPS — autenticar no GHCR:
    # 1. Criar Personal Access Token no GitHub:
    #    Settings → Developer Settings → Personal access tokens (classic)
    #    Scopes: read:packages
    
    # 2. Login na VPS:
    echo "SEU_GITHUB_TOKEN" | docker login ghcr.io -u SEU_USUARIO --password-stdin
    
    # 3. Verificar autenticação:
    cat ~/.docker/config.json | grep ghcr.io
    
    # 4. Docker Compose puxa automaticamente no deploy:
    docker compose pull app
    docker compose up -d --no-deps app
    
    # Alternativa via GitHub Actions secret (mais seguro):
    # No workflow, injete o token via SSH:
    # ssh deploy@VPS "echo '${{ secrets.GITHUB_TOKEN }}' | docker login ghcr.io -u ${{ github.actor }} --password-stdin"

    Multi-platform: build para ARM e AMD64

    Para VPS ARM (Ampere, Graviton) ou Raspberry Pi, faça build multi-platform:

    yaml
          # Habilitar QEMU para emulação
          - name: Configurar QEMU
            uses: docker/setup-qemu-action@v3
    
          - name: Configurar Buildx
            uses: docker/setup-buildx-action@v3
    
          - name: Build multi-platform
            uses: docker/build-push-action@v6
            with:
              context: .
              platforms: linux/amd64,linux/arm64
              push: true
              tags: ${{ steps.meta.outputs.tags }}
              cache-from: type=gha
              cache-to: type=gha,mode=max
    
    # O Docker seleciona automaticamente a imagem correta
    # para a arquitetura da máquina que faz o pull:
    # VPS AMD64 → pega a camada linux/amd64
    # VPS ARM64 → pega a camada linux/arm64
    Dica
    Build multi-platform com QEMU é lento (emulação de ARM em x86). Para projetos com muitos deploys: use runners ARM nativos (GitHub hosted arm64 runners, disponíveis em 2024) ou self-hosted runners na VPS ARM.

    Verificar vulnerabilidades na imagem com Trivy

    Escaneie a imagem por CVEs no próprio CI antes de fazer push:

    yaml
          - name: Scan de vulnerabilidades com Trivy
            uses: aquasecurity/trivy-action@master
            with:
              image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }}
              format: 'table'
              exit-code: '1'            # falhar o CI se encontrar CVE crítica
              ignore-unfixed: true
              severity: 'CRITICAL,HIGH'
    
          # Alternativa: gerar SBOM (Software Bill of Materials)
          - name: Gerar SBOM
            uses: aquasecurity/trivy-action@master
            with:
              image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }}
              format: 'cyclonedx'
              output: 'sbom.json'
    
          - name: Upload SBOM como artefato
            uses: actions/upload-artifact@v4
            with:
              name: sbom
              path: sbom.json

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Perguntas frequentes