Docker Compose env_file, environment y .env: qué hace cada uno
Guía de env_file en Docker Compose
Docker Compose: env_file vs environment vs .env, explicado | We.Inc
Qué hacen env_file, environment y el archivo .env en Docker Compose, qué valor gana cuando chocan y cómo funciona la interpolación ${VAR:-default}, con un resolvedor.
En Docker Compose, env_file carga un archivo de líneas KEY=value en el contenedor de un servicio. El atributo environment define variables del contenedor en línea y gana a env_file cuando ambos usan la misma clave. El archivo .env junto a compose.yaml es distinto: Compose lo lee para rellenar los marcadores ${VAR} del propio YAML.
Tres formas de pasar variables a Compose
Mecanismo
Alcance
¿Llega al contenedor?
.env junto a compose.yaml
Interpolación de ${VAR} en el archivo Compose
Solo si un servicio lo referencia
env_file: en un servicio
El contenedor de ese servicio
Sí, cada línea
environment: en un servicio
El contenedor de ese servicio
Sí, y gana a env_file
--env-file en la CLI
Sustituye al .env por defecto para la interpolación
Solo si se referencia
La confusión viene del nombre: un archivo llamado .env y un atributo llamado env_file parecen lo mismo, pero uno configura el archivo Compose y el otro configura un contenedor. Usa el resolvedor para ver qué fuente gana para una variable y luego prueba las formas de interpolación con una variable definida, vacía o sin definir.
Marca cada lugar donde está definida tu variable y escribe el valor que tiene ahí.
El resolvedor recorre desde arriba la lista de precedencia documentada por Docker y muestra con qué valor acaba el contenedor.
En el cuadro de interpolación, elige una forma como ${VAR:-default}, indica si VAR está definida, vacía o sin definir, y lee el resultado.
Ejecuta docker compose config en tu proyecto para confirmar lo que Compose resolvió de verdad.
Ejecuta docker compose config --environment para imprimir las variables que Compose usó en la interpolación. Zanja la mayoría de las discusiones en segundos.
Marca los archivos env opcionales con required: false (Compose 2.24.0 y posteriores) para que la falta de un override local no detenga el stack.
Escribe $$ cuando necesites un signo de dólar literal en compose.yaml, por ejemplo en una contraseña o un comando de shell.
Pon entre comillas los booleanos en el mapa environment, como SHOW: "true", para que YAML no los convierta en valores true y false.
Preguntas frecuentes
¿Qué diferencia hay entre env_file y environment?
Ambos meten variables en el contenedor de un servicio. env_file las lee de uno o varios archivos, environment las enumera en compose.yaml. Cuando la misma clave aparece en ambos, gana el valor de environment, aunque esté vacío.
¿Compose pasa mi archivo .env a los contenedores automáticamente?
No. El archivo .env del proyecto solo se usa para sustituir ${VAR} en el archivo Compose. Una variable llega a un contenedor solo cuando un servicio la nombra en environment, o carga el archivo con env_file.
¿Dónde busca Compose el archivo .env?
En el directorio del proyecto, que es la carpeta indicada con --project-directory, si no la carpeta del primer archivo -f, y si no tu carpeta actual. Usa --env-file para apuntar a otro archivo; si hay varios, los posteriores sobrescriben a los anteriores.
¿Las rutas de env_file son relativas al lugar donde ejecuto el comando?
No. Las rutas relativas de env_file se resuelven desde la carpeta que contiene el archivo Compose, así que el stack funciona desde donde lo arranques.
¿Qué pasa con ${VAR} cuando VAR no está definida?
Compose muestra una advertencia y la sustituye por una cadena vacía. Usa ${VAR:-fallback} para dar un valor por defecto, o ${VAR:?message} para detenerte con un error.
La lista de precedencia, de arriba abajo
Docker documenta cinco niveles. Un valor pasado con docker compose run -e es el más fuerte. Después viene environment o env_file cuando el valor se interpola desde tu shell o un archivo de entorno, luego un valor literal en environment, luego un valor de env_file, y por último una línea ENV incluida en la imagen.
Fíjate en que solo uno de ellos es el archivo .env, y solo de forma indirecta: alimenta el nivel dos mediante la interpolación. Un valor que está en .env y que ningún servicio menciona nunca aparece dentro de un contenedor.
Claves sin valor
Un nombre suelto en environment, como - API_TOKEN sin signo igual, copia el valor del shell que ejecuta Compose. Si el shell no lo tiene, la variable queda sin definir.
En un env_file, una línea que solo contiene una clave anula esa variable y la elimina del entorno del contenedor, lo que resulta útil para borrar a propósito algo que define la imagen.
Todas las formas de interpolación
Qué da cada forma para una VAR definida, vacía o sin definir
Forma
VAR=abc
VAR vacía
VAR sin definir
${VAR} or $VAR
vacío, con una advertencia
${VAR:-default}
${VAR-default}
${VAR:?msg}
error msg
error msg
${VAR?msg}
error msg
${VAR:+other}
${VAR+other}
un $ literal
un $ literal
un $ literal
Archivos Compose que puedes copiar
env_file más overrides con environment
La configuración compartida viene de archivos; las entradas de environment ganan para las claves que nombran. El archivo local es opcional.
El .env del proyecto usado solo para interpolación
Estos dos valores rellenan marcadores en compose.yaml. Ninguno llega a un contenedor salvo que un servicio lo mencione.
Usar esos valores en compose.yaml
La etiqueta de la imagen y el puerto publicado vienen de .env; la contraseña debe estar definida o Compose se detiene con un mensaje claro.
Comprobar lo que Compose resolvió
config imprime el modelo final con todas las variables rellenadas; --environment enumera los valores usados en la sustitución.
¿Qué valor gana?
La variable APP_MODE está definida en los lugares marcados abajo.
Dónde está definida la variable
Valor
El contenedor recibe APP_MODE={v} de: {n}
No está definida en ningún sitio, así que APP_MODE no existe en el contenedor.
Probador de interpolación
Expresión
VAR está
definida pero vacía
Valor de VAR
Resultado: {v}
Resultado: una cadena vacía
Compose se detiene con el error: {v}
Resultado: una cadena vacía, y Compose muestra una advertencia