Contenido
Tutorial de variables de entorno en Docker: configuración con .env y gestión de secretos
La misma imagen puede conectarse a distintas bases de datos y usar distintas configuraciones en desarrollo, pruebas y producción. Lo más habitual es guardar estos ajustes en variables de entorno y pasarlos al ejecutar el contenedor.
Configurar con -e
$ docker run --rm -e NODE_ENV=production -e PORT=8080 alpine:3.23 sh -c "echo \$NODE_ENV \$PORT"
production 8080
$ export API_KEY=abc123 && docker run --rm -e API_KEY alpine:3.23 sh -c "echo API_KEY=\$API_KEY"
API_KEY=abc123
-e nombre=valorestablece el valor directamente.- Si escribes solo
-e nombre(sin valor), se usa la variable de entorno del mismo nombre que tenga el host.
Leer un archivo con --env-file
Cuando hay muchas variables, es difícil gestionarlas dentro del comando. Guárdalas en un archivo:
$ cat app.env
# app.env
NODE_ENV=production
PORT=8080
GREETING="hello world"
DATABASE_URL=postgres://app:secret@db:5432/app
$ docker run --rm --env-file app.env alpine:3.23 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=e311730363f7
NODE_ENV=production
PORT=8080
GREETING="hello world"
DATABASE_URL=postgres://app:secret@db:5432/app
HOME=/root
Fíjate en la línea GREETING: en el archivo está escrito como "hello world" y el valor que recibe el contenedor incluye las comillas. Estas son las reglas de docker run --env-file:
- Una línea por cada
KEY=VALUE; las líneas que empiezan por#son comentarios. - No pongas comillas alrededor del valor: se tratarán como parte del valor.
- No se admite la expansión de variables
$OTHER_VAR.
(Más adelante verás que Compose quita las comillas al leer el mismo archivo; el comportamiento es distinto.)
Establecer valores predeterminados en Dockerfile
ENV NODE_ENV=production \
PORT=3000
ENV establece valores predeterminados que docker run -e puede sobrescribir. Es adecuado para ajustes que «no suelen cambiar y no son secretos».
Prioridad
De mayor a menor:
docker run -edocker run --env-fileENVde DockerfileENVde la imagen base
¿Se pueden ver las variables de entorno?
Las variables de entorno son prácticas, pero no son seguras. Cualquier persona que pueda ejecutar docker inspect puede verlas:
$ docker run -d --name envdemo -e SECRET_TOKEN=abc123 alpine:3.23 sleep 60
431168d97dc8187ec79e420638155b2f53fd78a9d82f8a6d13eb6bd9aec09bcb
$ docker inspect --format '{{json .Config.Env}}' envdemo
["SECRET_TOKEN=abc123","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
$ docker rm -f envdemo
envdemo
Además, si un programa falla, las variables de entorno podrían aparecer en los registros, y los procesos secundarios también las heredan. Por eso, sigue las recomendaciones de la sección «Gestionar datos secretos» para contraseñas y claves de API.
Variables de entorno en Docker Compose
En Compose hay dos tipos de «variables de entorno» que se suelen confundir. Veamos un ejemplo. compose.yaml:
services:
app:
image: alpine:3.23
command: ["sh", "-c", "env | sort | grep -E 'APP_|DATABASE|NODE_ENV|PORT|GREETING'"]
environment:
APP_VERSION: ${APP_VERSION}
DATABASE_PASSWORD: ${DB_PASSWORD}
env_file:
- app.env
1. Variables que se pasan al contenedor: environment y env_file
environment se escribe directamente en compose.yaml; env_file lee un archivo (en este caso, reutilizamos el app.env anterior).
2. Variables para sustituir contenido de compose.yaml: .env
Compose lee automáticamente el archivo .env de la carpeta del proyecto para sustituir ${...} en compose.yaml. Con docker compose config puedes ver la configuración final después de la sustitución:
$ cat .env
APP_VERSION=1.4.2
DB_PASSWORD=change-me
$ docker compose config app
name: ch15
services:
app:
command:
- sh
- -c
- env | sort | grep -E 'APP_|DATABASE|NODE_ENV|PORT|GREETING'
environment:
APP_VERSION: 1.4.2
DATABASE_PASSWORD: change-me
DATABASE_URL: postgres://app:secret@db:5432/app
GREETING: hello world
NODE_ENV: production
PORT: "8080"
image: alpine:3.23
networks:
default: null
networks:
default:
name: ch15_default
$ docker compose run --rm app
[+] run 1/1
✔ Network ch15_default Created 0.0s
Container ch15-app-run-dfbcf95b7271 Creating
Container ch15-app-run-dfbcf95b7271 Created
APP_VERSION=1.4.2
DATABASE_PASSWORD=change-me
DATABASE_URL=postgres://app:secret@db:5432/app
GREETING=hello world
NODE_ENV=production
PORT=8080
${APP_VERSION}y${DB_PASSWORD}se sustituyeron por los valores de.env.- Al leer Compose
GREETING="hello world"deapp.env, quita las comillas; el comportamiento es distinto al dedocker run --env-file. - Se añadieron comillas a
PORT: "8080"para indicar que es una cadena (todas las variables de entorno son cadenas).
.env no se pasa automáticamente al contenedor; solo sirve para sustituir valores en compose.yaml. Para pasar una variable al contenedor, debes hacer referencia a ella en environment (por ejemplo, APP_VERSION: ${APP_VERSION}) o usar env_file: .env.
Valores predeterminados y comprobación de variables obligatorias
| Sintaxis | Significado |
|---|---|
${VAR} | Se sustituye por el valor de VAR |
${VAR:-valor predeterminado} | Usa el valor predeterminado si no está definida o está vacía |
${VAR:?mensaje de error} | Muestra un error directamente si no está definida o está vacía |
${VAR:?} es muy útil para variables que «deben estar definidas», como una contraseña. Si olvidas definirla, se detiene de inmediato en lugar de iniciar con una contraseña vacía:
services:
db:
image: postgres:18
environment:
POSTGRES_PASSWORD: ${MISSING_PASSWORD:?Define MISSING_PASSWORD en .env}
$ docker compose -f compose.required.yaml config
error while interpolating services.db.environment.POSTGRES_PASSWORD: required variable MISSING_PASSWORD is missing a value: Define MISSING_PASSWORD en .env
Gestionar datos secretos
- No escribas contraseñas en
ENVniARGde Dockerfile: quedan guardadas en la imagen (consulta las pruebas deARGen Referencia completa de instrucciones de Dockerfile). - No subas
.enva Git. Añade.enva.gitignorey proporciona un.env.examplesin valores reales. - Añade
.enva.dockerignorepara evitar que se incluya en la imagen al ejecutarCOPY . ..
Pasar secretos mediante archivos (secrets de Compose)
Muchas imágenes oficiales admiten variables que terminan en _FILE para leer contraseñas desde un archivo:
services:
db:
image: postgres:18
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
$ docker compose up -d db
[+] up 1/1
✔ Container ch15-db-1 Started 0.3s
$ docker compose exec db sh -c "ls -l /run/secrets; cat /run/secrets/db_password; echo; env | grep POSTGRES"
total 4
-rw-rw-r-- 1 1001 1001 16 Oct 12 14:25 db_password
s3cret-from-file
POSTGRES_PASSWORD_FILE=/run/secrets/db_password
$ docker compose down
[+] down 2/2
✔ Container ch15-db-1 Removed 0.1s
✔ Network ch15_default Removed 0.1s
El contenido secreto aparece como archivo en /run/secrets/db_password dentro del contenedor. La variable de entorno solo contiene la ruta del archivo, POSTGRES_PASSWORD_FILE; docker inspect no puede ver la contraseña.
Secretos necesarios durante la compilación
Por ejemplo, para instalar paquetes privados que requieren un token, móntalo como secret con BuildKit:
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
docker build --secret id=npm_token,env=NPM_TOKEN -t myapp .
El token solo existe mientras se ejecuta este RUN y no queda guardado en ninguna capa.
Resumen
- Prioridad:
-e/environment>--env-file/env_file>ENVde Dockerfile. .envsustituye${VAR}en compose.yaml y no se pasa automáticamente al contenedor.docker run --env-fileno quita las comillas de los valores; Compose sí.- Pasa los datos secretos mediante archivos (secrets); no los incluyas en la imagen.
Ejercicios
Ejercicio 1: La imagen tiene ENV MODE=prod. Ejecutas el contenedor con docker run -e MODE=dev. ¿Cuál es el valor de MODE dentro del contenedor?
Respuesta
dev. La prioridad de -e es mayor que la de ENV de Dockerfile.
Ejercicio 2: En compose.yaml escribes POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}, pero .env no contiene DB_PASSWORD. ¿Qué ocurre al ejecutar docker compose up?
Respuesta
Compose muestra un error y se detiene con DB_PASSWORD is required; no crea la base de datos con una contraseña vacía.
Preguntas frecuentes
¿Las variables de entorno del contenedor no cambian al modificar .env?
Las variables de entorno se determinan al crear el contenedor. Después de modificarlas, debes volver a crear el contenedor: con Compose, usa docker compose up -d; restart no aplica los cambios.
¿Se puede ver mi contraseña con docker inspect?
Sí. Los valores que pasas con -e aparecen en docker inspect. Para datos sensibles, pásalos mediante archivos (secrets).
¿Qué diferencia hay entre ${VAR:-valor predeterminado} y ${VAR:?mensaje}?
La primera expresión usa un valor predeterminado si la variable no está definida; la segunda muestra un error y se detiene si no está definida. Es adecuada para contraseñas obligatorias, pues evita que queden vacías.
Actualizado 14 de octubre de 2026