Cada línea, una capa
Un Dockerfile describe paso a paso cómo construir una imagen, y Docker reutiliza todo paso que no cambió. Al terminar sabrás ordenar un Dockerfile para que construya rápido y salga pequeño.
Qué es un Dockerfile
Un Dockerfile es un archivo de texto con los pasos para construir una imagen, de arriba hacia abajo. docker build -t miapp . lo lee y produce la imagen miapp. El punto final es el contexto: la carpeta cuyos archivos puede usar el Dockerfile.
FROM node:18-alpine # imagen base: de aquí se parte WORKDIR /app # carpeta de trabajo (la crea si no existe) COPY package.json . # copia archivos del contexto a la imagen RUN npm install # ejecuta una orden al construir COPY . . ENV NODE_ENV=production # variable de entorno EXPOSE 3000 # documenta en qué puerto escucha CMD ["node", "src/app.js"] # la orden con que arranca cada contenedor
Ojo con la diferencia entre RUN y CMD: RUN se ejecuta una vez, al construir, y su resultado queda guardado en la imagen; CMD no se ejecuta al construir, sino cada vez que arranca un contenedor. Y EXPOSE no publica nada: solo documenta el puerto; el que publica es -p al correr.
El orden importa
Cada RUN, COPY y ADD crea una capa: el conjunto de archivos que ese paso agregó o cambió. Al reconstruir, Docker revisa los pasos en orden y reutiliza la capa guardada (CACHED) mientras el paso y sus archivos de entrada no hayan cambiado. En cuanto un paso cambia, ese y todos los siguientes se vuelven a ejecutar.
Por eso los pasos que cambian poco van arriba y los que cambian mucho, abajo. Instalar dependencias tarda minutos y solo hace falta repetirlo cuando cambia package.json; tu código, en cambio, cambia a cada rato. Si copias todo el código antes de instalar, cualquier cambio en una línea vuelve a instalar todas las dependencias.
Elige el orden del Dockerfile y qué archivo cambiaste desde la última construcción. Mira qué pasos se reutilizan.
.dockerignore
Antes de construir, Docker empaqueta el contexto completo y se lo envía al motor. Si en la carpeta está node_modules (cientos de megas que de todas formas se van a reinstalar), la construcción se vuelve lenta y COPY . . mete en la imagen cosas que no deberían estar. Peor aún si hay un .env con contraseñas: quedaría dentro de la imagen, al alcance de cualquiera que la descargue.
Un archivo .dockerignore en la raíz del contexto, con la misma idea que .gitignore, lista lo que se excluye:
node_modules .git .env *.log
Marca qué excluye tu .dockerignore y mira qué viaja al construir y qué termina dentro de la imagen.
Multi-stage
Para compilar un sitio web hacen falta Node, las dependencias de desarrollo y el código fuente; para servirlo solo hacen falta los archivos generados y un servidor web. Una construcción multi-stage tiene varios FROM: cada uno empieza una etapa nueva, y con COPY --from=etapa te llevas únicamente lo que necesitas. La imagen final es la última etapa; lo demás se descarta.
FROM node:18-alpine AS build WORKDIR /app COPY package.json . RUN npm install COPY . . RUN npm run build # genera /app/build FROM nginx:alpine COPY --from=build /app/build /usr/share/nginx/html
Para compartir tu imagen, la etiquetas con tu usuario del registro y la subes: docker tag miapp ana/miapp:1.0, docker login y docker push ana/miapp:1.0. Antes de publicarla conviene revisar sus vulnerabilidades conocidas con docker scout quickview; una base más pequeña, como alpine, trae menos paquetes y por lo tanto menos de qué preocuparse.
Compara la imagen de una sola etapa con la de dos etapas: tamaño y contenido.
Antes de leer la respuesta
Tu turno: empaqueta una aplicación
En la carpeta proyecto hay una aplicación de Node (src/app.js responde un saludo en el puerto 3000), su package.json, una carpeta node_modules y un Dockerfile que funciona pero está mal ordenado. También hay un sitio estático en public/. Construye la imagen, haz que reconstruir sea rápido, que el contexto no cargue lo que no hace falta, y empaqueta el sitio en una imagen pequeña.
Comprueba lo que entendiste
Cada respuesta incorrecta explica por qué parece correcta y en qué falla.