Docker y Go: contenedorización de aplicaciones en Golang
En el desarrollo moderno, la contenedorización se ha convertido en el estándar de facto para el despliegue y escalado de aplicaciones. Docker y Go son la pareja ideal para crear microservicios ligeros, rápidos y seguros. Go se compila en un binario estático, lo que lo hace especialmente atractivo para la contenedorización: la imagen final puede pesar solo unos pocos megabytes. En este artículo, analizaremos cómo contenedorizar correctamente aplicaciones Go, optimizar el Dockerfile y evitar errores típicos.
¿Por qué Docker y Go son la combinación ideal?
Go (Golang) fue creado pensando en las arquitecturas cloud modernas. Sus características clave son la compilación estática, el soporte integrado para concurrencia y la ausencia de dependencias externas en runtime. Docker, por su parte, proporciona un entorno aislado para ejecutar aplicaciones. Juntos permiten crear imágenes que:
- Ocupan mínimo espacio — la imagen de una aplicación Go puede ser menor a 10 MB.
- Se inician rápidamente — el binario estático no requiere intérprete ni máquina virtual.
- Se escalan fácilmente — ideales para orquestación en Kubernetes.
- Son más seguras — la imagen mínima reduce la superficie de ataque.
Creación de una aplicación Go simple para contenedorizar
Para empezar, escribamos una aplicación web simple en Go que contenedorizaremos. Cree el archivo main.go:
package main
import ( "fmt" "log" "net/http" "os")
func main() { port := os.Getenv("PORT") if port == "" { port = "8080" }
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from Go in Docker! 🐳") })
log.Printf("Server starting on port %s", port) log.Fatal(http.ListenAndServe(":"+port, nil))}Esta aplicación escucha peticiones HTTP y devuelve un mensaje de bienvenida. El puerto se puede configurar mediante la variable de entorno PORT.
Escritura del Dockerfile para la aplicación Go
Ahora crearemos el Dockerfile. Comenzaremos con un enfoque básico y luego lo optimizaremos.
Dockerfile básico (sin optimización)
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./RUN go mod download
COPY . .RUN go build -o main .
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]Este Dockerfile utiliza multi-stage build — uno de los mejores patrones para Go. La primera etapa (builder) compila la aplicación, la segunda (imagen final) contiene solo el binario compilado. Este enfoque evita incluir el compilador y las herramientas de Go en la imagen final.
Dockerfile optimizado (best practices)
Para hacer la imagen aún más pequeña y segura, usamos scratch — una imagen vacía sin shell ni utilidades:
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./RUN go mod download
COPY . .
# Deshabilitamos CGO, activamos optimizacionesRUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o main .
FROM scratch
WORKDIR /root/
COPY --from=builder /app/main .
# Añadimos certificados raíz para HTTPSCOPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
CMD ["./main"]Optimizaciones clave:
CGO_ENABLED=0— deshabilita CGO, lo que reduce el tamaño del binario.-ldflags="-s -w"— elimina la tabla de símbolos y la información de depuración.scratch— imagen mínima sin capas innecesarias.- Copia de
ca-certificates.crt— necesaria para trabajar con HTTPS.