Docker Compose: env_file, environment e .env, o que cada um faz
Guia de env_file no Docker Compose
Docker Compose: env_file vs environment vs .env, explicado | We.Inc
O que env_file, environment e o arquivo .env fazem no Docker Compose, qual valor vence quando eles entram em conflito e como funciona a interpolação ${VAR:-default}, com um resolvedor.
No Docker Compose, env_file carrega um arquivo de linhas KEY=value no contêiner de um serviço. O atributo environment define variáveis do contêiner direto no arquivo e vence o env_file quando os dois usam a mesma chave. O arquivo .env ao lado do compose.yaml é outra coisa: o Compose o lê para preencher os placeholders ${VAR} no próprio YAML.
Três formas de passar variáveis para o Compose
Mecanismo
Escopo
Chega ao contêiner?
.env ao lado do compose.yaml
Interpolação de ${VAR} no arquivo do Compose
Só se um serviço fizer referência a ela
env_file: em um serviço
O contêiner desse serviço
Sim, todas as linhas
environment: em um serviço
O contêiner desse serviço
Sim, e vence o env_file
--env-file na CLI
Substitui o .env padrão na interpolação
Só se houver referência
A confusão vem do nome: um arquivo chamado .env e um atributo chamado env_file parecem a mesma coisa, mas um configura o arquivo do Compose e o outro configura um contêiner. Use o resolvedor para ver qual origem vence para uma variável e depois teste as formas de interpolação com uma variável definida, vazia ou não definida.
Marque cada lugar em que a sua variável é definida e digite o valor que ela tem ali.
O resolvedor percorre a lista de precedência documentada pelo Docker de cima para baixo e mostra com qual valor o contêiner fica.
Na caixa de interpolação, escolha uma forma como ${VAR:-default}, indique se VAR está definida, vazia ou não definida, e leia o resultado.
Rode docker compose config no seu projeto para confirmar o que o Compose realmente resolveu.
Rode docker compose config --environment para imprimir as variáveis que o Compose usou na interpolação. Isso resolve a maioria das discussões em segundos.
Marque arquivos env opcionais com required: false (Compose 2.24.0 ou posterior) para que a falta de um override local não derrube a stack.
Escreva $$ quando precisar de um cifrão literal no compose.yaml, por exemplo em uma senha ou um comando de shell.
Coloque booleanos entre aspas no mapa environment, como SHOW: "true", para que o YAML não os transforme em valores true e false.
Perguntas frequentes
Qual é a diferença entre env_file e environment?
Os dois colocam variáveis no contêiner de um serviço. env_file as lê de um ou mais arquivos, environment as lista no compose.yaml. Quando a mesma chave aparece nos dois, o valor de environment vence, mesmo que esteja vazio.
O Compose passa o meu arquivo .env para os contêineres automaticamente?
Não. O arquivo .env do projeto só é usado para substituir ${VAR} no arquivo do Compose. Uma variável só chega a um contêiner quando um serviço a cita em environment ou carrega o arquivo com env_file.
Onde o Compose procura o arquivo .env?
No diretório do projeto, que é a pasta passada com --project-directory, senão a pasta do primeiro arquivo -f, senão a sua pasta atual. Use --env-file para apontar para outro arquivo; com vários, os últimos sobrescrevem os primeiros.
Os caminhos do env_file são relativos ao lugar onde rodo o comando?
Não. Caminhos relativos no env_file são resolvidos a partir da pasta que contém o arquivo do Compose, então a stack funciona de onde quer que você a inicie.
O que acontece com ${VAR} quando VAR não está definida?
O Compose mostra um aviso e substitui por uma string vazia. Use ${VAR:-fallback} para fornecer um padrão, ou ${VAR:?message} para parar com um erro.
A lista de precedência, de cima para baixo
O Docker documenta cinco níveis. Um valor passado com docker compose run -e é o mais forte. Depois vem environment ou env_file quando o valor é interpolado do seu shell ou de um arquivo de ambiente, depois um valor literal em environment, depois um valor vindo de env_file e, por último, uma linha ENV embutida na imagem.
Repare que só um desses é o arquivo .env, e só indiretamente: ele alimenta o nível dois por meio da interpolação. Um valor no .env que nenhum serviço menciona nunca aparece dentro de um contêiner.
Chaves sem valor
Um nome sozinho em environment, como - API_TOKEN sem sinal de igual, copia o valor do shell que está rodando o Compose. Se o shell não tiver essa variável, ela fica sem definição.
Em um env_file, uma linha só com a chave remove a definição da variável e a tira do ambiente do contêiner, o que é útil para limpar de propósito algo que a imagem define.
Todas as formas de interpolação
O que cada forma retorna para VAR definida, vazia ou não definida
Forma
VAR=abc
VAR vazia
VAR não definida
${VAR} or $VAR
vazio, com um aviso
${VAR:-default}
${VAR-default}
${VAR:?msg}
erro msg
erro msg
${VAR?msg}
erro msg
${VAR:+other}
${VAR+other}
um $ literal
um $ literal
um $ literal
Arquivos do Compose para copiar
env_file com overrides em environment
As configurações compartilhadas vêm de arquivos; as entradas de environment vencem para as chaves que citam. O arquivo local é opcional.
.env do projeto usado só para interpolação
Esses dois valores preenchem placeholders no compose.yaml. Nenhum deles chega a um contêiner, a menos que um serviço o mencione.
Usando esses valores no compose.yaml
A tag da imagem e a porta publicada vêm do .env; a senha precisa estar definida, senão o Compose para com uma mensagem clara.
Confira o que o Compose resolveu
config imprime o modelo final com todas as variáveis preenchidas; --environment lista os valores usados na substituição.
Qual valor vence?
A variável APP_MODE está definida nos lugares marcados abaixo.
Onde a variável está definida
Valor
O contêiner recebe APP_MODE={v} de: {n}
Não está definida em lugar nenhum, então APP_MODE não existe no contêiner.
Testador de interpolação
Expressão
VAR está
definida, mas vazia
Valor de VAR
Resultado: {v}
Resultado: uma string vazia
O Compose para com o erro: {v}
Resultado: uma string vazia, e o Compose mostra um aviso