// Engineering Log

Desarrollo seguro: Parte 5 — El Dockerfile correcto

Publicado el 22.09.2026

// Ruta rapida

Este articulo pertenece al tema Despliegue y estabilidad.

Dockerfile de tres líneas — FROM node, COPY . ., CMD npm start — funciona, pero en el pipeline esa imagen se construye lentamente, cada vez resulta un poco diferente y se detiene mal. Esta parte está dedicada a la construcción correcta: reproducibilidad, caché, secretos y el proceso dentro del contenedor. Las imágenes base mínimas, el escaneo y las restricciones al ejecutar se tratan en la sección del ciclo sobre seguridad de contenedores.

Imagen base: versión y digest

La etiqueta latest y las etiquetas sin versión cambian sin aviso: la compilación de hoy y la de mañana pueden obtener versiones diferentes del lenguaje. Como mínimo — indicar la versión. Más fiable es fijar la imagen por digest, como recomienda la documentación de Docker: así la compilación usará exactamente esa imagen, incluso si el editor actualiza la etiqueta.

dockerfile
FROM python:3.13-slim@sha256:<digest>

Puedes obtener el digest con el comando docker buildx imagetools inspect python:3.13-slim. Para que las imágenes fijadas no queden obsoletas, se actualizan vía Dependabot (package-ecosystem: "docker") — crea pull requests con nuevas etiquetas y digest según programación.

A septiembre de 2026:

  • Node.js 18 no recibe actualizaciones de seguridad desde el 30 de abril de 2025, Node.js 20 — desde el 30 de abril de 2026; para nuevas imágenes convienen las ramas LTS 22 (correcciones de seguridad hasta el 30 de abril de 2027) y 24.
  • Python 3.9 no es compatible desde el 31 de octubre de 2025; Python 3.10 pierde soporte el 31 de octubre de 2026; para nuevas imágenes — 3.12 o 3.13.

Contexto de compilación y .dockerignore

Todo el contenido del directorio de construcción se envía al motor de compilación, salvo que se excluya. El archivo .dockerignore acelera la compilación y evita que cosas innecesarias —incluyendo archivos con contraseñas— entren en la imagen:

.git
node_modules
.env
*.log
dist

Orden de las instrucciones y caché

Cada instrucción crea una capa. Si una capa cambia, todas las siguientes se reconstruyen. Por eso primero se copian los archivos de dependencias y se instalan, y el código va después:

dockerfile
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

Ahora modificar el código no dispara de nuevo la instalación de dependencias. npm ci instala exactamente lo que está en el lock-file, — eso es una compilación reproducible.

Los paquetes del sistema se instalan en una sola instrucción junto con la actualización de la lista y la limpieza, como recomienda la documentación de Docker:

dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq5 \
 && rm -rf /var/lib/apt/lists/*

Construcción multi-etapa

Compiladores, dependencias de desarrollo y fuentes se necesitan para construir, pero no para ejecutar. La construcción multi-etapa deja en la imagen final solo lo necesario:

dockerfile
# syntax=docker/dockerfile:1
FROM node:24-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:24-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]

La primera etapa compila la aplicación; la segunda sólo recibe el resultado listo y las dependencias para ejecutarla. La instrucción USER node ejecuta la aplicación con un usuario no privilegiado, que ya existe en las imágenes oficiales de Node.js.

Secretos durante la compilación

El token para un registro privado no debe pasarse vía ARG o ENV: los valores quedan en la imagen y son visibles en su historial. Para esto existen los secretos de BuildKit — se montan en una única instrucción y no aparecen en las capas:

dockerfile
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
bash
docker build --secret id=npmrc,src=$HOME/.npmrc .

Por defecto, el secreto está disponible como archivo /run/secrets/<id>; el parámetro env= permite pasarlo a una variable de entorno sólo para ese comando.

Proceso en el contenedor: PID 1 y señales

El comando de parada del contenedor envía al proceso principal la señal SIGTERM. Si CMD está en forma shell (CMD node server.js), el proceso principal será la shell y la aplicación puede no recibir la señal — tras un timeout el contenedor se termina forzosamente y se pierden peticiones incompletas.

  • Usa la forma exec: CMD ["node", "dist/server.js"].
  • Si necesitas un script de arranque, debe terminar con exec "$@", para que la aplicación pase a ser PID 1 y reciba las señales — este patrón aparece en la documentación de Docker.
  • Si la aplicación genera procesos hijos, ejecuta el contenedor con docker run --init (en Compose — init: true): Docker añadirá un pequeño proceso init basado en tini, que reenvía señales y recolecta procesos terminados.

Verificación del Dockerfile

El analizador estático hadolint encuentra errores típicos en Dockerfile — versiones no fijadas, forma shell en comandos, capas innecesarias — y se integra fácilmente en el pipeline:

bash
docker run --rm -i hadolint/hadolint < Dockerfile

Errores típicos

  • COPY . . al inicio del archivo. El caché de dependencias se invalida con cualquier cambio en el código.
  • No tener .dockerignore. En la imagen entran .git, node_modules locales y .env.
  • npm install en lugar de npm ci. La build puede obtener versiones de paquetes distintas a las del lock-file.
  • Tokens en ARG y ENV. Se pueden extraer del historial de la imagen.
  • Forma shell de CMD. La aplicación no recibe SIGTERM y no tiene tiempo para terminar correctamente.
  • Imágenes base obsoletas. Node.js 18 y Python 3.9 ya no reciben correcciones de seguridad.

// Tarea parecida

Si estas resolviendo algo parecido

Este articulo pertenece a uno de los temas principales de trabajo. Puedes seguir leyendo sobre el tema, ir a la pagina principal para entender a que me dedico o abrir directamente los servicios.

Tema del articulo

Despliegue y estabilidad

Docker, CI/CD, despliegues, monitoreo, observabilidad y respuesta a incidentes.

Tareas frecuentes de esta tema

  • Configurar despliegues sin trabajo manual ni caos
  • Añadir monitoreo, alertas y observabilidad base
  • Investigar incidentes y estabilizar produccion

// Siguiente paso

Si necesitas ayuda con este tema y no solo otro articulo, es mejor ir directo a la pagina del servicio. La pagina principal y la seleccion de materiales quedan como rutas secundarias.

Abrir servicios

// Reviews

Reseñas relacionadas

Llegué con una solicitud costosa para la configuración de un servidor VPS, pero durante la consulta Mikhail propuso una solución mucho más sencilla y económica. Al final ahorré dinero y tiempo. Mikhail — un verdadero experto que trabaja por el resultado del cliente, no por la factura. ¡Lo recomiendo!

Llegué con una solicitud costosa para la configuración de un servidor VPS, pero durante la consulta Mikhail propuso una solución mucho más simple y económica. Al final ahorré presupuesto y tiempo. Mikhail es un …

kfhzasorin

Configuración de VPS, configuración del servidor

12.05.2026 · ★ 5/5

Hubo varios problemas, tanto en la parte técnica como en la comprensión general. Mijaíl respondió rápido a la solicitud, ayudó a aclarar las cosas y resolvió los problemas técnicos; por ello, muchas gracias. Estoy satisfecho con el resultado.

Hubo varios problemas relacionados tanto con la parte técnica como con la comprensión en general. Mijaíl respondió rápidamente a la solicitud, ayudó a aclarar las cosas y resolvió los problemas técnicos, por lo que le …

abazawolf

Configuración de VPS, configuración del servidor

18.02.2026 · ★ 5/5

// Contact

¿Necesitas ayuda?

Escríbeme y te ayudaré a resolver el problema

Respondo en un día laborable (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirme que no es un bot.

Escribir y recibir una respuesta rápida