Qué es un multi-stage build
Un multi-stage build es un Dockerfile con varias secciones FROM: cada una arranca una etapa nueva e independiente, con su propia imagen base. Solo la última etapa —normalmente etiquetada runtime— se convierte en la imagen final; el resto solo existe durante el docker build y desaparece después. Con COPY --from=build copiamos exclusivamente lo que necesitamos (el binario compilado) de una etapa a otra, sin arrastrar el compilador, las cabeceras de desarrollo ni el resto del toolchain a producción.
Por qué importa el tamaño de la imagen
Una imagen de producción más pequeña se descarga y despliega más rápido, pero sobre todo reduce la superficie de ataque: menos paquetes instalados significa menos CVE potenciales y menos herramientas (compiladores, shells completos, gestores de paquetes) que un atacante podría aprovechar si compromete el contenedor. Por eso en este laboratorio comparamos con docker images el tamaño real de una imagen de una sola etapa frente a la misma app con multi-stage, y comprobamos que la etapa final ni siquiera tiene el compilador de Go instalado.
.dockerignore y –target
El fichero .dockerignore excluye archivos del contexto de build, igual que .gitignore excluye ficheros de un commit: notas locales, logs o el propio .git nunca llegan a docker build, así que tampoco pueden colarse en la imagen. La flag docker build --target <etapa> permite construir solo una etapa concreta, muy útil para depurar la etapa build por separado sin tener que completar también la etapa runtime.
Cuándo usar Alpine, scratch o distroless
Alpine (basada en musl y BusyBox) suele ser el punto de partida: pesa unos 5 MB y trae un shell mínimo para depurar. Si el binario es completamente estático (como el de este laboratorio, compilado con CGO_ENABLED=0), FROM scratch reduce la imagen aún más al no incluir ni siquiera un sistema base. Las imágenes distroless de Google son un término medio: sin shell ni gestor de paquetes, pero con las librerías del sistema operativo que muchos binarios sí necesitan.
Si además publicas estas imágenes, te interesa nuestro laboratorio para montar un registro privado de imágenes Docker, escanearlas con Trivy y Grype antes de subirlas, gestionarlas desde Portainer con Docker Compose y, si todo esto vive en tu propio servidor, el resto de nuestra serie de home lab autoalojado. La referencia oficial está en la documentación de Docker sobre multi-stage builds, y para elegir la imagen base más ligera consulta las imágenes oficiales de Alpine Linux o la guía de seguridad de contenedores de OWASP.
Preguntas frecuentes
¿Qué es un multi-stage build en Docker?
Es un Dockerfile con varias secciones FROM, donde cada una es una etapa distinta. Solo la última etapa se convierte en la imagen final; las anteriores existen solo durante el build y sirven para compilar o preparar dependencias sin que ese peso llegue a producción.
¿Por qué usar Alpine en la etapa final en vez de la imagen completa?
Porque Alpine pesa unos 5 MB frente a los cientos de MB (o más de 1 GB) de una imagen de desarrollo completa con compilador y librerías. Menos paquetes instalados también significa menos superficie de ataque y menos CVE que vigilar.
¿Cómo construyo solo la etapa de build con –target?
Con docker build –target build -t mi-imagen:build-stage . Docker se detiene justo al terminar esa etapa, la que se llama build en el Dockerfile, sin ejecutar el resto; útil para depurarla o inspeccionar sus artefactos por separado.
¿El multi-stage build hace la imagen más segura, o solo más pequeña?
Ambas cosas, y están relacionadas: al no incluir el compilador, los gestores de paquetes ni las herramientas de desarrollo en la imagen final, hay menos software instalado que un atacante pueda explotar si compromete el contenedor. Por eso en este laboratorio comprobamos con command -v go que la imagen runtime ni siquiera tiene el compilador de Go.