Docker e Go: conteinerização de aplicações de nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução

\n

A conteinerização de aplicações Go com Docker é o padrão do desenvolvimento moderno. No entanto, Dockerfiles básicos muitas vezes estão longe do ideal: as imagens ficam pesadas, o build é lento e, em produção, surgem problemas com logging, sinais e healthcheck. Neste artigo, abordaremos técnicas avançadas: desde builds multi-stage até a configuração refinada de rede e volumes. Você aprenderá como tornar a imagem de uma aplicação Go mínima, segura e pronta para produção.

\n\n

1. Builds multi-stage: imagem mínima em segundos

\n

Go compila para um binário estático, o que é ideal para conteinerização. No entanto, se você usar a imagem completa golang:1.22 para execução, estará carregando o compilador, o gerenciador de pacotes e utilitários do sistema. A solução é o multi-stage build.

\n\n

Dockerfile básico com multi-stage

\n
# Stage 1: build\nFROM golang:1.22-alpine AS builder\nWORKDIR /app\nCOPY go.mod go.sum ./\nRUN go mod download\nCOPY . .\nRUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/main ./cmd/\n\n# Stage 2: imagem mínima\nFROM alpine:3.19\nRUN apk add --no-cache ca-certificates tzdata\nCOPY --from=builder /app/main /usr/local/bin/main\nEXPOSE 8080\nENTRYPOINT ["/usr/local/bin/main"]
\n\n

Por que isso funciona?

\n
    \n
  • Alpine — 5 MB, conjunto mínimo de utilitários.
  • \n
  • CGO_ENABLED=0 — desativa dependências C, o binário torna-se estático.
  • \n
  • -ldflags="-s -w" — remove informações de depuração, reduzindo o tamanho do binário em 30-40%.
  • \n
  • ca-certificates e tzdata — para requisições HTTPS e horário correto.
  • \n
\n\n

Resultado: imagem de 10-15 MB em vez de 800+ MB. Build — 15-20 segundos (com cache de dependências).

\n\n

2. Otimização de cache e camadas

\n

O Docker armazena em cache as camadas. Se você copiar todo o código antes de go mod download, qualquer alteração nos arquivos .go invalida o cache de dependências. A ordem correta é:

\n\n
COPY go.mod go.sum ./\nRUN go mod download\nCOPY . .
\n\n

Use também .dockerignore:

\n
.git\n*.md\ntest/\ncoverage/\n.env\nDockerfile
\n\n

Isso exclui arquivos desnecessários do contexto do build, acelerando a transferência para o daemon Docker.

\n\n

Truque avançado: cache de módulos

\n

Se você usa Go modules, pode montar o cache:

\n
FROM golang:1.22-alpine AS builder\nWORKDIR /app\nRUN --mount=type=cache,target=/go/pkg/mod \\\n    --mount=type=cache,target=/root/.cache/go-build \\\n    go build -ldflags="-s -w" -o /app/main ./cmd/
\n\n

Isso preserva os módulos baixados e artefatos de build entre execuções de docker build.

\n\n

3. Healthchecks, sinais e graceful shutdown

\n

O Docker pode verificar a integridade do contêiner. Adicione no Dockerfile:

\n\n
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\\n    CMD ["/usr/local/bin/main", "health"]
\n\n

No código Go, implemente o endpoint /healthz:

\n
package main\n\nimport (\n    "net/http"\n    "os"\n    "os/signal"\n    "syscall"\n)\n\nfunc main() {\n    http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {\n        w.WriteHeader(http.StatusOK)\n        w.Write([]byte("ok"))\n    })\n\n    srv := &http.Server{Addr: ":8080"}\n\n    // Graceful shutdown\n    go func() {\n        sigint := make(chan os.Signal, 1)\n        signal.Notify(sigint, syscall.SIGTERM, syscall.SIGINT)\n        <-sigint\n        srv.Shutdown(nil)\n    }()\n\n    srv.ListenAndServe()\n}
\n\n

Importante: a aplicação Go deve tratar corretamente o SIGTERM (que o Docker envia ao parar o contêiner). Sem graceful shutdown, você corre o risco de perder dados ou deixar conexões abertas.

\n\n

4. Docker Compose para produção: redes, volumes e limites de recursos

Blogs

Book Recommendations