Files
platform-templates/dockerfiles/node-api.Dockerfile
T

95 lines
3.5 KiB
Docker

# Basado en el Dockerfile real de commerce-backend (Medusa v2 / Express).
# Multi-stage: build con devDependencies, runtime solo con lo necesario
# para correr -- sin compilador, sin devDependencies, sin npm/npx.
#
# ARGs a completar por tu app (todos tienen un default razonable):
# NODE_IMAGE -- versión exacta de Node. Fijala a una versión concreta
# (no "node:22-slim"), así un rebuild no te cambia la
# versión de Node por sorpresa un día cualquiera.
# APP_PORT -- puerto en el que tu app escucha.
# START_CMD -- cómo arrancar tu app en runtime. Por default invoca
# "node dist/index.js" -- CAMBIALO al entrypoint real de
# tu build. No uses "npm start"/"npx algo": el runtime
# de esta imagen NO tiene npm (ver más abajo, por qué).
# syntax=docker/dockerfile:1.7
ARG NODE_IMAGE=node:22.18.0-bookworm-slim
ARG APP_PORT=3000
#############################################################
# Builder
#############################################################
FROM ${NODE_IMAGE} AS builder
WORKDIR /app
ENV CI=true \
NODE_ENV=development \
NPM_CONFIG_UPDATE_NOTIFIER=false
COPY package.json package-lock.json* .npmrc* ./
# --legacy-peer-deps: sacalo si tu proyecto no lo necesita. Medusa v2 sí
# lo necesita hoy (conflictos de peer deps conocidos del ecosistema).
RUN --mount=type=cache,id=node-api-npm-cache,target=/root/.npm \
npm ci \
--legacy-peer-deps \
--prefer-offline \
--no-audit \
--no-fund
# CAMBIAR: copiá acá los archivos/carpetas fuente reales de tu app
# (tsconfig, src/, config específico). Estos son solo un ejemplo.
COPY tsconfig.json ./
COPY src ./src
RUN npm run build
RUN npm prune --omit=dev \
&& npm cache clean --force
#############################################################
# Runtime
#############################################################
FROM ${NODE_IMAGE}
ARG APP_PORT
ENV NODE_ENV=production \
PORT=${APP_PORT} \
NPM_CONFIG_UPDATE_NOTIFIER=false
# El CLI global de npm que trae la imagen base node:*-slim arrastra su
# propia copia de "tar" con historial de CVEs — no hace falta en
# runtime (nunca corrés npm/npx acá, solo "node algo.js"). Borrarlo
# reduce lo que Trivy tiene que escanear al set real que corre en
# producción.
#
# OJO si tu app usa un init container que corre "npx <algo>" contra
# esta misma imagen (ej. migraciones): eso se rompe si borrás npm acá.
# Cambiá ese comando a invocar el binario directo con "node", como el
# CMD de abajo — no vuelvas a agregar npm solo para eso.
RUN rm -rf /usr/local/lib/node_modules/npm
WORKDIR /app
# CAMBIAR: qué carpetas copiar del builder depende de tu build real
# (dist/, .output/, node_modules). Este ejemplo asume un build típico
# de tsc/esbuild a dist/ + node_modules de producción.
COPY --from=builder --chown=node:node /app/node_modules ./node_modules
COPY --from=builder --chown=node:node /app/dist ./dist
# La imagen base node:*-bookworm-slim ya trae un usuario "node" (uid
# 1000) sin privilegios -- no hace falta crear uno nuevo, a diferencia
# de nextjs.Dockerfile.
USER node
EXPOSE ${APP_PORT}
HEALTHCHECK --interval=30s --timeout=8s --start-period=20s --retries=3 \
CMD ["node", "-e", "fetch('http://127.0.0.1:' + (process.env.PORT || 3000) + '/health').then((r) => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"]
# CAMBIAR: el entrypoint real. Nunca "npm start"/"npx algo" -- ver nota
# de arriba sobre por qué npm no existe en esta imagen.
CMD ["node", "dist/index.js"]