Conteúdo

Tutorial de variáveis de ambiente no Docker: configure variáveis e arquivos .env

A mesma imagem pode precisar se conectar a bancos de dados diferentes e usar configurações diferentes nos ambientes de desenvolvimento, teste e produção. A forma mais comum de fazer isso é guardar essas configurações em variáveis de ambiente e passá-las ao executar o contêiner.

Configure com -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 NOME=VALOR define o valor diretamente.
  • Se você escrever apenas -e NOME (sem valor), será usada a variável de ambiente de mesmo nome que estiver definida no host.

Leia um arquivo com --env-file

Quando há muitas variáveis, é difícil gerenciá-las na linha de comando. Coloque-as em um arquivo:

$ 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

Observe a linha GREETING: no arquivo está escrito "hello world", e o valor recebido pelo contêiner inclui as aspas. As regras de docker run --env-file são:

  • Uma linha para cada KEY=VALUE; linhas que começam com # são comentários.
  • Não coloque aspas nos valores; elas serão tratadas como parte do valor.
  • Não há suporte à expansão de variáveis como $OTHER_VAR.

(Como você verá a seguir, ao ler o mesmo arquivo, o Compose remove as aspas. O comportamento é diferente.)

Defina valores padrão no Dockerfile

ENV NODE_ENV=production \
    PORT=3000

ENV define valores padrão, que podem ser substituídos por docker run -e. É adequado para configurações que "não mudam muito e não são confidenciais".

Ordem de precedência

Ordem de precedência das variáveis de ambiente: docker run -e ou compose environment têm prioridade máxima, seguidos por env-file e Dockerfile ENV; .env é usado para substituir variáveis em compose.yaml
Ordem de precedência das variáveis de ambiente e o uso diferente de .env

Da maior para a menor prioridade:

  1. docker run -e
  2. docker run --env-file
  3. ENV do Dockerfile
  4. ENV da imagem base

As variáveis de ambiente ficam visíveis?

As variáveis de ambiente são práticas, mas não são seguras. Qualquer pessoa que possa executar docker inspect consegue vê-las:

$ 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

Além disso, as variáveis de ambiente podem aparecer nos logs quando um programa falha, e os processos filhos também as herdam. Por isso, siga as recomendações em "Como lidar com dados confidenciais" ao usar senhas e chaves de API.

Variáveis de ambiente no Docker Compose

No Compose, há dois tipos de "variáveis de ambiente" que podem ser confundidos. Veja este exemplo. 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. Variáveis passadas ao contêiner: environment e env_file

environment é escrito diretamente em compose.yaml; env_file lê um arquivo (neste caso, o app.env usado acima).

2. Variáveis que substituem valores em compose.yaml: .env

O Compose lê automaticamente o arquivo .env na pasta do projeto para substituir ${...} em compose.yaml. Com docker compose config, você pode ver a configuração final após a substituição:

$ 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} e ${DB_PASSWORD} foram substituídos pelos valores de .env.
  • Depois que o Compose lê GREETING="hello world" em app.env, o valor fica sem aspas, ao contrário de docker run --env-file.
  • As aspas em PORT: "8080" indicam que o valor é uma string (variáveis de ambiente são sempre strings).

O .env não é passado automaticamente ao contêiner; ele serve apenas para substituir valores em compose.yaml. Para passá-lo ao contêiner, você precisa referenciá-lo em environment (por exemplo, APP_VERSION: ${APP_VERSION}) ou usar env_file: .env.

Valores padrão e validação de campos obrigatórios

FormaSignificado
${VAR}Substitui pelo valor de VAR
${VAR:-valor-padrao}Usa o valor padrão se a variável não estiver definida ou estiver vazia
${VAR:?mensagem-de-erro}Gera um erro se a variável não estiver definida ou estiver vazia

${VAR:?} é útil para variáveis que precisam ser definidas, como senhas. Se você esquecer de defini-las, a execução será interrompida imediatamente, em vez de iniciar com uma senha vazia:

services:
  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: ${MISSING_PASSWORD:?Defina MISSING_PASSWORD em .env}
$ docker compose -f compose.required.yaml config
error while interpolating services.db.environment.POSTGRES_PASSWORD: required variable MISSING_PASSWORD is missing a value: Defina MISSING_PASSWORD em .env

Como lidar com dados confidenciais

  • Não coloque senhas em ENV ou ARG no Dockerfile; elas permanecerão na imagem (veja os testes de ARG em Referência completa das instruções do Dockerfile).
  • Não envie .env para o Git. Adicione .env ao .gitignore e forneça também um .env.example sem valores reais.
  • Adicione .env ao .dockerignore para evitar que ele seja incluído na imagem por COPY . ..

Passe dados confidenciais em arquivos (Compose secrets)

Muitas imagens oficiais aceitam variáveis terminadas em _FILE para ler senhas de um arquivo:

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

O conteúdo confidencial aparece como arquivo em /run/secrets/db_password no contêiner. A variável de ambiente contém apenas o caminho do arquivo, POSTGRES_PASSWORD_FILE; docker inspect não mostra a senha em si.

Dados confidenciais necessários durante o build

Por exemplo, se você precisa de um token para instalar um pacote privado, use uma montagem de secret do 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 .

O token só existe durante a execução desse RUN e não permanece em nenhuma camada.

Resumo

  • Ordem de precedência: -e/environment > --env-file/env_file > ENV do Dockerfile.
  • .env substitui ${VAR} em compose.yaml e não é passado automaticamente ao contêiner.
  • docker run --env-file não remove aspas dos valores; o Compose remove.
  • Passe dados confidenciais em arquivos (secrets); não os coloque na imagem.

Exercícios

Exercício 1: A imagem define ENV MODE=prod. Se você executar docker run -e MODE=dev, qual será o valor de MODE no contêiner?

Resposta

dev. -e tem precedência sobre ENV do Dockerfile.

Exercício 2: Em compose.yaml, você define POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}, mas .env não contém DB_PASSWORD. O que acontece ao executar docker compose up?

Resposta

O Compose gera um erro e interrompe a execução, mostrando DB_PASSWORD is required. O banco de dados não é criado com uma senha vazia.

Perguntas frequentes

As variáveis de ambiente do contêiner não mudaram depois que editei o .env. Por quê?

As variáveis de ambiente são definidas quando o contêiner é criado. Depois de editá-las, recrie o contêiner: no Compose, use docker compose up -d; restart não aplica as alterações.

Minha senha fica visível com docker inspect?

Sim. Os valores passados com -e aparecem em docker inspect. Para dados confidenciais, use arquivos (secrets).

Qual é a diferença entre ${VAR:-valor-padrao} e ${VAR:?mensagem}?

A primeira forma usa o valor padrão quando a variável não está definida; a segunda gera um erro e interrompe a execução se ela não estiver definida. É adequada para senhas obrigatórias, pois evita que fiquem vazias.

Atualizado 14 de outubro de 2026