Compensaciones de Distroless y Alpine
Elige una imagen base de contenedor basándote en la compatibilidad con libc, el tamaño de la imagen y la capacidad de depuración, no en la costumbre.
Receta
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
# Predeterminado: Debian slim (glibc) - mejor compatibilidad con npm
FROM node:24-bookworm-slim AS prod
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY dist ./dist
USER node
CMD ["node", "dist/main.js"]Cuándo usarlo: APIs de Node nuevas sin módulos nativos que requieran compilaciones específicas de musl. Este es el valor predeterminado del equipo.
Ejemplo de trabajo
Tres opciones de etapa final para la misma API de Express:
# syntax=docker/dockerfile:1
FROM node:24-bookworm-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY tsconfig.json src ./
RUN npm run build
# Opción A: bookworm-slim (predeterminado recomendado)
FROM node:24-bookworm-slim AS slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/main.js"]
# Opción B: Alpine (más pequeña, musl)
FROM node:24-alpine AS alpine
WORKDIR /app
RUN apk add --no-cache libc6-compat
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/main.js"]
# Opción C: Distroless (mínima, sin shell)
FROM gcr.io/distroless/nodejs24-debian12 AS distroless
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=slim /app/node_modules ./node_modules
USER nonroot
CMD ["dist/main.js"]docker build --target slim -t api:slim .
docker build --target alpine -t api:alpine .
docker build --target distroless -t api:distroless .Lo que esto demuestra:
- El mismo
dist/compilado en los tres tiempos de ejecución - Alpine puede necesitar
libc6-compatpara algunos binarios precompilados - Distroless copia
node_modulesde una etapa de compilación de glibc (nunca compilar dentro de distroless)
Análisis profundo
libc: glibc vs musl
| Base | libc | Tamaño típico | Módulos nativos de npm |
|---|---|---|---|
bookworm-slim | glibc | ~180 MB | Mejor compatibilidad |
alpine | musl | ~120 MB | Problemas frecuentes de reconstrucción (sharp, bcrypt, prisma) |
distroless/nodejs24 | glibc | ~130 MB | Bueno si se construye en la etapa glibc |
Node mismo envía binarios precompilados para glibc Linux. Alpine a menudo fuerza npm rebuild o compilaciones desde el código fuente.
Cuándo funciona Alpine
- Solo dependencias de JavaScript puro
- Controlas las dependencias nativas y pruebas
npm cien Alpine en CI - El tamaño de la imagen en el registro importa (muchas extracciones de borde)
Cuándo funciona Distroless
- API de producción sin depuración en el contenedor
- La política de seguridad prohíbe shells y gestores de paquetes en tiempo de ejecución
- Depuras a través de registros, métricas y pods de depuración efímeros (K8s)
Compensación de depuración
# bookworm-slim: shell disponible
docker run -it --entrypoint bash api:slim
# distroless: sin shell - usa un pod de depuración o copia los volcados de memoria fuera del sistema
kubectl debug pod/api-xyz -it --image=busyboxErrores comunes
sharpen Alpine: fallo común. Solución: usa bookworm-slim o la documentación oficial de instalación desharpen Alpine con versiones fijadas.- Compilar en Mac, ejecutar Alpine: incompatibilidad de arquitectura y libc. Solución: siempre
docker builden el destino de CI de Linux. prisma generateen la etapa incorrecta: enlaces OpenSSL incorrectos. Solución: genera en la etapa de compilación de glibc; copia los artefactos.- Distroless sin
USER nonroot: se ejecuta como root por defecto en algunas etiquetas. Solución:USER nonrootexplícito. - Asumir que más pequeño siempre significa más rápido: el asignador de musl difiere; compara el rendimiento de tu carga de trabajo. Solución: prueba de carga antes de cambiar.
apkde Alpine en un Dockerfile de producción: aumenta las capas. Solución: multi-etapa; el tiempo de ejecución no tiene gestor de paquetes.
Alternativas
| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| bookworm-slim | Predeterminado para APIs de Node | Necesitas la imagen más pequeña posible y has probado Alpine |
| Alpine | Despliegues de borde sensibles al tamaño, pila de JS puro | Uso intensivo de módulos nativos |
| Distroless | Producción endurecida, K8s con herramientas de depuración en otro lugar | El equipo depende de docker exec bash |
| Imágenes de Node de Chainguard | Bases endurecidas de la cadena de suministro | No puedes adoptar la nueva cadencia de imágenes base |
Preguntas frecuentes
¿Cuál es el valor predeterminado de nuestro equipo?
node:24-bookworm-slim a menos que una necesidad medida (tamaño, mandato del escáner de seguridad) justifique Alpine o distroless.
¿Cómo pruebo la compatibilidad con Alpine en CI?
Agrega un trabajo de matriz: docker build --target alpine y ejecuta pruebas de humo. Haz que la PR falle si los módulos nativos se rompen.
¿Puedo usar distroless con Fastify o NestJS?
Sí. Compila en bookworm-slim, copia dist/ y node_modules en distroless. No se requieren cambios de código.
¿Distroless incluye npm?
No. Todas las instalaciones ocurren en una etapa anterior. El tiempo de ejecución solo ejecuta node.
¿Diferencia de tamaño entre Alpine y slim?
A menudo se ahorran 40-80 MB, dependiendo de node_modules. Mide con docker images después de npm ci de producción.
¿Qué pasa con la fijación de `node:24-alpine3.20`?
Fija las versiones menores de Alpine en entornos regulados. Sigue las notas de lanzamiento de Node Docker para actualizaciones de imágenes base.
Relacionado
- Compilaciones Multi-Etapa - compila en una imagen completa, ejecuta en una mínima
- Reducción de Imagen - tamaño sin riesgo de musl
- Contenedores No-Root -
USER node/nonroot - Conceptos Básicos de Docker - tu primer Dockerfile
- Mejores Prácticas de Docker - lista de verificación de la sección
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS Activo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.