Lección 4 de 15 · Lectura y práctica
Variables de Entorno y Argumentos en Build
CONCEPTO CLAVE: En Docker, los ARG son variables disponibles únicamente durante el proceso de construcción de la imagen, mientras que ENV son variables persistentes disponibles tanto en build como en runtime. Comprender esta.
Esta es una lección del contenido anterior de Cursalo. Si ya estudiaste o compraste este curso, entra con tu cuenta para guardar tu progreso y abrir el resto de las clases. No necesitas comprar nada de nuevo.
¿Por qué importan las variables?
En el desarrollo moderno, las aplicaciones necesitan adaptarse a diferentes entornos, configuraciones y contextos. Docker proporciona dos mecanismos principales para manejar configuraciones: los argumentos de construcción (ARG) y las variables de entorno (ENV). Aunque a simple vista pueden parecer similares, tienen propósitos y comportamientos muy distintos que exploraremos en detalle.
ARG: Argumentos de Construcción
Los argumentos ARG son instrucciones del Dockerfile que permiten pasar valores durante el proceso de docker build. Su alcance está limitado exclusivamente a la construcción de la imagen, lo que significa que no persisten en la imagen final ni están disponibles cuando el contenedor se ejecuta.
Sintaxis básica de ARG
ARG NOMBRE_VARIABLE
ARG NOMBRE_VARIABLE=valor_por_defecto
Ejemplo práctico
# Dockerfile
ARG NODE_VERSION
ARG NPM_TOKEN
RUN echo "Installing dependencies..."
RUN npm install --registry=https://registry.npmjs.org/ --token=$NPM_TOKEN
FROM node:${NODE_VERSION:-18}
Para construir con estos argumentos:
docker build --build-arg NODE_VERSION=20 --build-arg NPM_TOKEN=mi_token_secreto -t mi-app:latest .
ARG son ideales para valores que cambian entre builds pero no necesitan estar disponibles en runtime, como versiones de dependencias, tokens de construcción o flags de compilación.ENV: Variables de Entorno
Las variables ENV persisten tanto durante el build como en el contenedor ejecutándose. Son el mecanismo principal para configurar el comportamiento de la aplicación en runtime y pueden ser sobrescritas al iniciar el contenedor.
Sintaxis básica de ENV
ENV NOMBRE_VARIABLE=valor
ENV NOMBRE_VARIABLE=valor
Ejemplo práctico
# Dockerfile
FROM node:18-alpine
ENV NODE_ENV=production
ENV APP_PORT=3000
ENV DATABASE_HOST=localhost
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE ${APP_PORT}
CMD ["node", "server.js"]
docker run -e APP_PORT=8080 -e DATABASE_HOST=db-server mi-appComparación directa: ARG vs ENV
| Característica | ARG | ENV |
|---|---|---|
| Disponibilidad en build | ✅ Sí | ✅ Sí |
| Disponibilidad en runtime | ❌ No | ✅ Sí |
| Persiste en imagen | ❌ No | ✅ Sí |
| Sobrescribible en run | ❌ No aplica | ✅ Sí (-e flag) |
| Uso típico | Versiones, tokens de build | Configuración de aplicación |
Uso combinado: El patrón ARG + ENV
Una práctica muy común es combinar ambos mecanismos. Usamos ARG para recibir valores durante el build y luego los asignamos a ENV para que estén disponibles en runtime:
# Dockerfile multi-stage
ARG VERSION=1.0.0
ARG BUILD_DATE
# Stage de construcción
FROM node:18 AS builder
ARG VERSION
ARG BUILD_DATE
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage de producción
FROM node:18-alpine
ARG VERSION
ARG BUILD_DATE
# Convertimos ARG en ENV para runtime
ENV APP_VERSION=${VERSION}
ENV BUILD_DATE=${BUILD_DATE}
ENV NODE_ENV=production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]
Variables predefinidas de Docker
Docker proporciona varios ARG predefinidos que puedes usar sin declararlos:
| Variable | Descripción |
|---|---|
HTTP_PROXY |
Proxy HTTP configurado en el daemon |
HTTPS_PROXY |
Proxy HTTPS configurado en el daemon |
FTP_PROXY |
Proxy FTP configurado en el daemon |
NO_PROXY |
Hosts excluidos del proxy |
Scope de ARG: Limitando su alcance
Los ARG tienen un concepto de scope o alcance. Un ARG definido antes del primer FROM en un Dockerfile con múltiples stages solo está disponible en stages posteriores si se redefine:
# ARG global disponible desde el inicio
ARG BASE_VERSION=1.0
FROM node:18 AS builder
# BASE_VERSION está disponible aquí
FROM python:3.11 AS api
# BASE_VERSION NO está disponible aquí automáticamente
ARG BASE_VERSION
# Ahora BASE_VERSION está disponible
FROM en un Dockerfile multi-stage.Ejemplo completo: Aplicación Node.js con configuración
- Crear la estructura del proyecto:
mi-proyecto/
├── Dockerfile
├── package.json
├── src/
│ └── index.js
└── .dockerignore
- Definir el Dockerfile completo:
# ============================================
# ARG para construcción
# ============================================
ARG NODE_VERSION=18
ARG NPM_REGISTRY=https://registry.npmjs.org/
# ============================================
# Imagen base con versión configurable
# ============================================
FROM node:${NODE_VERSION}-alpine AS builder
# Argumentos de build del stage
ARG NPM_REGISTRY
ARG BUILD_ENV=production
# Configurar npm registry
RUN npm config set registry ${NPM_REGISTRY}
WORKDIR /app
# Copiar archivos de dependencias primero (optimización de caché)
COPY package*.json ./
# Instalar dependencias
RUN npm ci --only=${BUILD_ENV}
# Copiar código fuente
COPY src/ ./src/
# ============================================
# Imagen de producción
# ============================================
FROM node:${NODE_VERSION}-alpine AS production
# ============================================
# ENV para runtime (algunos desde ARG)
# ============================================
ARG NODE_VERSION
ARG BUILD_ENV
ENV NODE_ENV=${BUILD_ENV}
ENV APP_ENV=production
ENV LOG_LEVEL=info
ENV API_TIMEOUT=5000
ENV MAX_CONNECTIONS=100
WORKDIR /app
# Copiar solo lo necesario del stage de build
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/src ./src
# Crear usuario no-root para seguridad
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodeuser -u 1001
USER nodeuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "src/index.js"]
- Construir la imagen:
# Construcción default
docker build -t mi-app:default .
# Construcción con argumentos personalizados
docker build \
--build-arg NODE_VERSION=20 \
--build-arg BUILD_ENV=staging \
--build-arg NPM_REGISTRY=https://registry.npmmirror.com \
-t mi-app:staging \
.
- Ejecutar con sobrescritura de ENV:
# Ejecutar en producción
docker run -d \
-p 3000:3000 \
-e LOG_LEVEL=debug \
-e MAX_CONNECTIONS=200 \
--name mi-app-prod \
mi-app:default
# Ejecutar en desarrollo
docker run -d \
-p 3000:3000 \
-e NODE_ENV=development \
-e LOG_LEVEL=debug \
--name mi-app-dev \
mi-app:default
Mejores prácticas
docker history o inspeccionando la configuración del contenedor. Para secretos, usa mecanismos como Docker Secrets o montajes de volúmenes.Ver más: Ejemplo de manejo de secretos
Para manejar secretos de forma segura, evita ponerlos directamente en ENV:
# INCORRECTO - Expone el secreto
ENV API_KEY=mi_clave_secreta
# CORRECTO - Usar montajes de volumen o Docker Secrets
# Al ejecutar el contenedor:
docker run -v /ruta/local/secrets.json:/secrets/api.json:ro \
-e API_KEY=$(cat /ruta/local/api_key.txt) \
mi-app
En Swarm, usa Docker Secrets para gestión segura de credenciales sensibles.
Inspección de variables
Para verificar qué variables ENV están configuradas en una imagen:
# Ver todas las variables ENV
docker image inspect mi-app:latest --format='{{range .Config.Env}}{{println .}}{{end}}'
# Ver solo las variables personalizadas
docker image inspect mi-app:latest --format='{{range .Config.Env}}{{if not (hasPrefix . "PATH=")}}{{println .}}{{end}}{{end}}'
# Ver la configuración completa
docker inspect mi-app:latest | grep -A 50 '"Env"'
Las variables de entorno son la forma más flexible de configurar contenedores. Aprende a combinarlas con ARG para builds reproducibles y despliegues versátiles.
Resumen práctico
Recuerda esta regla simple:
- ¿Necesitas el valor SOLO durante el build? → Usa
ARG - ¿Necesitas el valor en runtime? → Usa
ENV - ¿Necesitas el valor en ambos? → Combina ambos:
ARG→ENV
¿Cuál es la diferencia principal entre ARG y ENV en Docker?
- A) No hay diferencia, son intercambiables
- B) ARG solo existe durante el build, ENV persiste en runtime
- C) ENV solo existe durante el build, ARG persiste en runtime
- D) ARG es más seguro que ENV
¿Cuándo deberías usar el patrón ARG + ENV combinado?
- A) Nunca, es una mala práctica
- B) Cuando necesitas un valor tanto en build como en runtime
- C) Solo cuando trabajas con múltiples stages
- D) Únicamente para variables de configuración