
Você escreveu seu microsserviço em Go. Ele é rápido, concorrente e confiável. Agora vem a parte que separa os projetos amadores dos profissionais: colocar isso em produção, em escala, com tolerância a falhas, atualizações sem downtime e monitoramento.
É aí que o Kubernetes entra. O orquestrador de contêineres se tornou o padrão para rodar microsserviços. Mas Go e Kubernetes juntos exigem algumas boas práticas específicas: health checks que realmente funcionam, graceful shutdown para não perder requisições, gerenciamento de configuração com ConfigMaps, e sidecars para observabilidade.
Neste post, vamos construir o caminho do zero até a produção de um microsserviço Go no Kubernetes, com exemplos práticos e as armadilhas que a Jacobus Software aprendeu na prática.
1. O microsserviço Go pronto para Kubernetes
Antes de containerizar, seu código Go precisa estar preparado para o ambiente orquestrado. Os requisitos mínimos:
Graceful shutdown (indispensável)
Quando o Kubernetes vai matar um pod (por escala, atualização ou falha), ele envia um sinal SIGTERM. Seu serviço precisa capturar esse sinal, parar de aceitar novas conexões, finalizar as requisições em andamento e então se encerrar.
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", healthHandler)
mux.HandleFunc("/ready", readyHandler)
mux.HandleFunc("/api", apiHandler)
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
// Goroutine para rodar o servidor
go func() {
log.Println("Servidor iniciado na porta 8080")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("erro no servidor: %v", err)
}
}()
// Aguarda sinal de término (SIGTERM do Kubernetes)
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit
log.Println("SIGTERM recebido, desligando graciosamente...")
// Tempo máximo para finalizar conexões existentes
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("erro no shutdown: %v", err)
}
log.Println("Servidor finalizado")
}
Health probes: readiness e liveness
O Kubernetes usa duas sondas:
- livenessProbe: verifica se o pod está vivo. Se falhar, o pod é reiniciado.
- readinessProbe: verifica se o pod está pronto para receber tráfego. Se falhar, o pod é removido do balanceamento.
// Endpoint de liveness (apenas se o processo está rodando)
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
// Endpoint de readiness (verifica dependências: banco, cache, etc.)
func readyHandler(w http.ResponseWriter, r *http.Request) {
// Verifica conexão com banco, Redis, etc.
if err := checkDatabase(); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte(err.Error()))
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("READY"))
}
2. Containerizando a aplicação Go
O Dockerfile para Go deve ser multi-stage para gerar binários pequenos e seguros.
# Estágio 1: builder
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/service ./cmd/api
# Estágio 2: imagem final (distroless ou alpine mínimo)
FROM alpine:3.19
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/service /service
# Usuário não-root para segurança
RUN adduser -D appuser
USER appuser
EXPOSE 8080
ENTRYPOINT ["/service"]
Dicas:
CGO_ENABLED=0gera binário estático, sem dependências C.-ldflags="-s -w"remove símbolos de debug, reduzindo tamanho.- Use imagens
scratchoudistrolesspara segurança máxima (sem shell).
3. Manifestos Kubernetes
Agora, os arquivos YAML que definem seu microsserviço.
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-api
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: go-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # quantos pods extras durante atualização
maxUnavailable: 0 # garante zero downtime (mantém pelo menos réplicas ativas)
template:
metadata:
labels:
app: go-api
spec:
containers:
- name: api
image: jacobus/go-api:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
- name: REDIS_ADDR
valueFrom:
configMapKeyRef:
name: api-config
key: redis_addr
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
# Probes essenciais
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# Lifecycle para garantir shutdown gracioso
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 15"]
restartPolicy: Always
Explicações importantes:
maxUnavailable: 0garante que nunca fique com menos pods que o desejado.preStop sleep 15dá tempo para o Service remover o pod do balanceamento antes de enviar SIGTERM.- Recursos (requests/limits) são obrigatórios para o escalonador funcionar bem.
Service (expor o microsserviço)
apiVersion: v1
kind: Service
metadata:
name: go-api-service
namespace: production
spec:
selector:
app: go-api
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP # interno ao cluster
ConfigMap e Secret
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
namespace: production
data:
redis_addr: "redis-service.default:6379"
log_level: "info"
# secret.yaml (valores em base64)
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
url: cG9zdGdyZXM6Ly91c2VyOnBhc3NAaG9zdDo1NDMyL2Ri
4. Escalabilidade horizontal em Go
Kubernetes escala facilmente:
kubectl scale deployment go-api --replicas=10
Mas seu código Go precisa ser stateless (não armazenar estado local que deveria ser compartilhado). Se precisar de estado, use Redis, banco de dados ou cache distribuído.
HPA (Horizontal Pod Autoscaler)
Para escalar automaticamente baseado em métricas (CPU, memória ou custom):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: go-api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: go-api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Em Go, monitore também a latência e o número de goroutines – são métricas melhores que CPU para muitos workloads.
5. Sidecars: o parceiro do microsserviço
O padrão sidecar é um contêiner auxiliar que roda no mesmo pod. Muito usado para:
- Observabilidade: Envoy, Linkerd (service mesh) ou um agente de logs.
- Proxy de banco de dados: Cloud SQL Auth Proxy.
- Rate limiting / autorização: Sidecar que verifica tokens antes de encaminhar.
Exemplo: adicionar um sidecar que envia métricas para o Prometheus (já que o app pode não ter suporte nativo).
containers:
- name: api
image: jacobus/go-api:latest
# ...
- name: metrics-sidecar
image: prometheus/statsd-exporter
args: ["--statsd.listen-udp=:8125"]
6. Configuração avançada: Init containers
Às vezes você precisa executar tarefas antes do app principal iniciar: migrações de banco, download de arquivos, etc. Use init containers:
initContainers:
- name: migrations
image: jacobus/go-migrate:latest
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
O init container roda até completar com sucesso antes dos contêineres principais iniciarem.
7. Observabilidade no Kubernetes (essencial)
Nunca coloque microsserviços em produção sem:
- Logs estruturados (JSON) enviados para stdout/stderr – o Kubernetes coleta automaticamente.
- Métricas Prometheus exportadas no endpoint
/metrics. - Tracing distribuído (Jaeger) com headers propagados.
Go + Prometheus é trivial:
import "github.com/prometheus/client_golang/prometheus/promhttp"
http.Handle("/metrics", promhttp.Handler())
8. Boas práticas para Go no Kubernetes
| Prática | Por quê |
|---|---|
Use GOMAXPROCS automático | Go 1.19+ detecta limites de CPU do container. Antes, use automaxprocs library. |
Configure GOMEMLIMIT | Evita que Go consuma memória além do limit do container e seja morto pelo OOMKiller. |
Evite os.Exit(1) | Deixe o K8s reiniciar o container – não aborte o processo sem cleanup. |
Use context com timeout | Em calls HTTP, banco, etc. Para não vazar goroutines. |
| Graceful shutdown para conexões externas | Feche pools de conexões no SIGTERM. |
| Não escreva arquivos locais | Pods são efêmeros. Use volumes ou buckets. |
| Teste localmente com Kind ou Minikube | Reproduza o ambiente antes de deployar. |
9. Pipeline CI/CD (GitHub Actions exemplo)
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- run: go test ./...
- run: go build -o app ./cmd/api
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
push: true
tags: jacobus/go-api:${{ github.sha }}
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/go-api api=jacobus/go-api:${{ github.sha }}
kubectl rollout status deployment/go-api
Caso real: deploy de fintech em Go na Jacobus
Uma plataforma de pagamentos precisava de zero downtime absoluto e escalabilidade instantânea para black friday.
Implementação:
- Microsserviços Go com graceful shutdown e health probes.
- Deploy no Kubernetes com
maxUnavailable: 0e preStop sleep. - HPA baseado em CPU e requisições por segundo (custom metric).
- Sidecar do Cloud SQL Proxy para conexão segura com banco.
- Istio como service mesh para controle de tráfego e mTLS.
Resultado: 200k requisições por minuto em pico, zero incidentes de deploy, rollback de 30 segundos quando necessário.
Conclusão: Go e Kubernetes – uma parceria poderosa
Kubernetes oferece a plataforma; Go oferece eficiência e concorrência. Juntos, eles formam a espinha dorsal de sistemas modernos e escaláveis. Mas é preciso mais do que kubectl run – as boas práticas de health checks, graceful shutdown, recursos, sidecars e autoscaling fazem a diferença entre um sistema frágil e um que realmente aguenta produção.
Na Jacobus Software, usamos essa stack diariamente para clientes que exigem alta disponibilidade e escala. Com os exemplos deste post, você tem um roteiro sólido para levar seu microsserviço Go do zero à produção com confiança.
☸️ Quer colocar seus microsserviços Go no Kubernetes com segurança?
Nossos especialistas projetam pipelines, manifestos e autoscaling sob medida – garantindo zero downtime e operação tranquila.
