Dockerfile
La receta para construir tu propia imagen. Cada instrucción genera una capa; el orden importa para la caché.
Instrucciones
Van en MAYÚSCULAS y se ejecutan de arriba hacia abajo.
Referencia rápida
| Instrucción | Qué hace | Ejemplo |
|---|---|---|
FROM | Imagen base. Siempre la primera. AS nombre define una etapa. | FROM node:18 |
WORKDIR | Carpeta de trabajo dentro del contenedor. La crea si no existe (reemplaza a RUN mkdir -p + cd). | WORKDIR /home/app |
COPY | Copia [ORIGEN-PC] → [DESTINO-CONTENEDOR]. El origen es relativo al build context. | COPY . /home/app |
ADD | Como COPY pero además descomprime .tar y acepta URLs. Preferí COPY. | ADD app.tar.gz /opt/ |
RUN | Ejecuta un comando al construir la imagen (instalar cosas). | RUN npm i -g nodemon |
ENV | Variable de entorno disponible en build y en ejecución. | ENV NODE_ENV=production |
ARG | Variable solo durante el build (--build-arg). | ARG VERSION=1.0 |
EXPOSE | Documenta el puerto de la app. No publica nada (eso es -p). | EXPOSE 3000 |
CMD | Comando por defecto al iniciar el contenedor. Solo vale el último. | CMD ["node", "app.js"] |
ENTRYPOINT | Ejecutable fijo del contenedor; CMD/args se le agregan. | ENTRYPOINT ["dotnet", "Api.dll"] |
USER | Usuario con el que corre (evitar root en producción). | USER node |
RUN vs CMD: RUN se ejecuta una vez al construir la imagen. CMD se ejecuta cada vez que arranca un contenedor.
Node.js — imagen de producción
El código queda copiado dentro de la imagen.
Dockerfile (pruebas-docker)
# imagen a utilizar
FROM node:latest
# directorio en el contenedor donde va el código
RUN mkdir -p /home/app
# [ORIGEN-PC] [DESTINO-CONTAINER]
COPY . /home/app
# puerto de la app (informativo)
EXPOSE 3000
# comando + argumentos
CMD ["node", "/home/app/app.js"]
No instala dependencias: funciona porque copia tu node_modules local. Si tuvieras dependencias nativas (bcrypt, sharp…) compiladas en Windows, fallarían en Linux.
En docs/Dockerfile-example.md tenés COPY E/Development/pruebas-docker /home/app: no funciona. COPY no acepta rutas absolutas de tu PC, solo rutas dentro del build context → COPY . /home/app.
Dockerfile recomendado
# versión fija: latest puede cambiar y romper el build
FROM node:18
# crea la carpeta y se para en ella
WORKDIR /home/app
# 1º solo las dependencias (capa cacheable)
COPY package*.json ./
RUN npm ci --omit=dev
# 2º el resto del código
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
WORKDIRreemplazaRUN mkdir -py permite rutas relativas- Si solo cambiás código,
npm cino se vuelve a ejecutar (ver caché) - Acompañalo con un .dockerignore que excluya
node_modules
Node.js — imagen de desarrollo
No copia el código: lo recibe por un volumen (bind mount) desde compose y nodemon recarga al guardar.
Dockerfile.dev
FROM node:latest
# nodemon global para recargar al guardar
RUN npm i -g nodemon
RUN mkdir -p /home/app
WORKDIR /home/app
EXPOSE 3000
# -L = legacy watch (polling)
CMD ["nodemon", "-L", "app.js"]
Por qué así
- Sin
COPY: el código entra porvolumes: - .:/home/appendocker-compose-dev.yml - Editás en tu PC → el archivo cambia dentro del contenedor → nodemon reinicia
- No hace falta rebuild por cada cambio de código (solo si cambia el Dockerfile o dependencias globales)
-Les necesario en Windows/WSL: los eventos de cambio de archivo no cruzan el bind mount, así que nodemon tiene que consultar (polling)RUN mkdir -psobra:WORKDIRya crea la carpeta
Levantalo con docker compose -f docker-compose-dev.yml up.
Capas y caché
Si una capa cambia, se reconstruyen esa y todas las de abajo. Lo que cambia poco va arriba.
Multi-stage build (ASP.NET Core / .NET 10)
Una etapa con el SDK para compilar, otra solo con el runtime para ejecutar. La imagen final es mucho más liviana.
Dockerfile
# ---------- Etapa 1: compilar ----------
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# toda la solución: Host depende de Domain, Application…
COPY . .
RUN dotnet restore "src/<Proyecto>.HttpApi.Host/<Proyecto>.HttpApi.Host.csproj"
RUN dotnet publish "src/<Proyecto>.HttpApi.Host/<Proyecto>.HttpApi.Host.csproj" \
-c Release -o /app/publish
# ---------- Etapa 2: ejecutar ----------
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "<Proyecto>.HttpApi.Host.dll"]
Paso a paso (de tus notas)
- Etapa build con la imagen del SDK de .NET 10.
WORKDIR /src: nos paramos en una carpeta nueva del contenedor.COPY . .copia todo el build context (la carpetaaspnet-corecompleta, así se definió en compose) porque HttpApi.Host necesita los otros proyectos para compilar.restore+publish. El resultado va a/app/publish— ruta absoluta, no relativa a/src.- Etapa runtime: solo lo necesario para ejecutar.
WORKDIR /app.COPY --from=buildtrae lo publicado desde la etapa anterior.EXPOSE 8080(informativo; en .NET 8+ el puerto por defecto es 8080).ENTRYPOINTejecuta la DLL compilada.
El restore separado no aprovecha la caché tal como está. Para que sirva, copiá primero solo los .csproj, hacé restore y recién después COPY . . (mismo truco que package.json en Node). publish igual hace restore si hace falta.
CMD vs ENTRYPOINT · forma exec vs shell
Cómo arranca el proceso principal.
CMD
Comando por defecto. Se reemplaza si pasás algo después de la imagen.
CMD ["node", "app.js"]
docker run miapp:1 node otro.js # reemplaza el CMD
ENTRYPOINT
Ejecutable fijo. Lo que pases (o el CMD) se agrega como argumentos.
ENTRYPOINT ["dotnet", "Api.dll"]
docker run api:1 --urls http://+:5000 # dotnet Api.dll --urls ...
Exec form vs shell form
Usá la forma JSON (exec): el proceso recibe las señales y docker stop lo cierra limpio.
# ✓ exec form
CMD ["node", "app.js"]
# ✕ shell form (corre dentro de /bin/sh -c)
CMD node app.js
.dockerignore
Lo que no se manda al build context. Hace los builds más rápidos y evita copiar basura o secretos.
Node.js
node_modules
npm-debug.log
.git
.gitignore
.env
docs
Dockerfile*
docker-compose*.yml
.NET
**/bin
**/obj
**/.vs
**/node_modules
.git
*.user
**/appsettings.Development.json
Tu proyecto pruebas-docker no tiene .dockerignore: el COPY . está copiando node_modules y .git dentro de la imagen.
Construir la imagen
Desde la carpeta donde está el Dockerfile.
Comandos de build
docker build -t miapp:1 .miapp:1 y contexto .docker build -t miapp:dev -f Dockerfile.dev .docker build --no-cache -t miapp:1 .docker build --target build -t api:build .docker build --build-arg VERSION=2.0 -t miapp:2 .ARG.docker build -t api:1 -f src/Api/Dockerfile .