Docker y Go: contenerización de aplicaciones de nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción

\n

La contenerización de aplicaciones Go con Docker es el estándar del desarrollo moderno. Sin embargo, los Dockerfile básicos a menudo distan de ser ideales: las imágenes resultan pesadas, la compilación es lenta y en producción surgen problemas con el registro, las señales y los healthchecks. En este artículo, analizaremos técnicas avanzadas: desde compilaciones multi-stage hasta el ajuste fino de redes y volúmenes. Aprenderá cómo hacer que la imagen de una aplicación Go sea mínima, segura y lista para producción.

\n\n

1. Compilaciones multi-stage: imagen mínima en segundos

\n

Go se compila en un binario estático, lo que es ideal para la contenerización. Sin embargo, si utiliza la imagen completa golang:1.22 para ejecutar, arrastra el compilador, el gestor de paquetes y las utilidades del sistema. La solución es multi-stage build.

\n\n

Dockerfile básico con multi-stage

\n
# Stage 1: compilación\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: imagen 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 qué funciona esto?

\n
    \n
  • Alpine — 5 MB, conjunto mínimo de utilidades.
  • \n
  • CGO_ENABLED=0 — desactiva las dependencias de C, el binario se vuelve estático.
  • \n
  • -ldflags="-s -w" — elimina la información de depuración, reduciendo el tamaño del binario en un 30-40%.
  • \n
  • ca-certificates y tzdata — para solicitudes HTTPS y la hora correcta.
  • \n
\n\n

Resultado: imagen de 10-15 MB en lugar de 800+ MB. Compilación: 15-20 segundos (con almacenamiento en caché de dependencias).

\n\n

2. Optimización del almacenamiento en caché y las capas

\n

Docker almacena en caché las capas. Si copia todo el código antes de go mod download, cualquier cambio en los archivos .go invalida la caché de dependencias. El orden correcto:

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

También utilice .dockerignore:

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

Esto excluye archivos innecesarios del contexto de compilación, acelerando la transferencia al demonio de Docker.

\n\n

Truco avanzado: almacenamiento en caché de módulos

\n

Si utiliza Go modules, puede montar la caché:

\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

Esto conserva los módulos descargados y los artefactos de compilación entre ejecuciones de docker build.

\n\n

3. Healthchecks, señales y graceful shutdown

\n

Docker puede verificar el estado del contenedor. Añada en el Dockerfile:

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

En el código Go, implemente el 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: la aplicación Go debe manejar correctamente SIGTERM (que Docker envía al detener el contenedor). Sin un graceful shutdown, corre el riesgo de perder datos o dejar conexiones abiertas.

\n\n

4. Docker Compose para producción: redes, volúmenes y limitaciones de recursos

Blogs

Book Recommendations