0Pricing
Linux Command Line & Bash Scripting Mastery · Aula

Criação de modelos de configurações com envsubst e heredocs

Gere configurações em tempo de execução a partir de variáveis de ambiente usando envsubst e heredocs entre aspas.

Criação de modelos de configurações com envsubst e heredocs é uma aula grátis de Linux Command Line & Bash Scripting Mastery no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Linux Command Line & Bash Scripting Mastery, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

Por que a geração de configurações em tempo de execução é importante

Nos fluxos de trabalho de DevOps e contêineres, arquivos de configuração como nginx.conf, prometheus.yml e docker-compose.yml frequentemente precisam mudar entre ambientes — homologação, produção e DR. Codificar valores diretamente cria divergências e expõe segredos.

A solução é a geração de configurações em tempo de execução a partir de modelos: inclua um modelo com marcadores e, em seguida, insira os valores reais na inicialização a partir de variáveis de ambiente. Isso mantém sua imagem imutável e sua configuração auditável.

  • Nenhum segredo incorporado às imagens
  • O mesmo artefato promovido entre ambientes
  • Configuração gerada imediatamente antes da inicialização do processo

Duas ferramentas complementares tornam isso trivial no Bash: envsubst e documentos incorporados entre aspas.

envsubst: o gerador de configurações em uma única linha

envsubst é um pequeno utilitário GNU que lê a entrada padrão, substitui os marcadores $VARIABLE e ${VARIABLE} pelos valores correspondentes do ambiente atual e grava o resultado na saída padrão.

Ele acompanha o pacote gettext e está disponível em praticamente todas as distribuições Linux e imagens base do Docker.

  • Funciona com qualquer formato de texto: NGINX, YAML, TOML, JSON, INI
  • Não avalia a sintaxe do interpretador de comandos — apenas substitui referências a variáveis
  • É seguro: não executa comandos dentro do modelo
#!/usr/bin/env bash
# Install check (usually already present)
which envsubst || apt-get install -y gettext-base

# Minimal demo
export APP_PORT=8080
export APP_HOST=api.example.com

echo 'server { listen ${APP_PORT}; server_name ${APP_HOST}; }' | envsubst
# Output: server { listen 8080; server_name api.example.com; }

Substituição seletiva de variáveis

Por padrão, envsubst substitui todo $VAR que encontra. Isso pode sobrescrever variáveis do NGINX, como $uri ou $host — elas são diretivas reais do NGINX, não variáveis do ambiente.

Informe uma lista explícita de variáveis como primeiro argumento para restringir a substituição apenas a esses nomes:

envsubst '$VAR1 $VAR2'

O argumento é uma string entre aspas simples (para que o interpretador de comandos não a expanda) contendo os nomes das variáveis que você deseja substituir, separados por espaços ou quebras de linha.

#!/usr/bin/env bash
export APP_PORT=8080
export APP_HOST=api.example.com

# NGINX template contains both our vars AND nginx vars ($uri, $host)
TEMPLATE='server {
  listen ${APP_PORT};
  server_name ${APP_HOST};
  location / {
    proxy_set_header Host $host;
    proxy_pass http://backend$uri;
  }
}'

# Only substitute APP_PORT and APP_HOST — leave $host and $uri untouched
echo "$TEMPLATE" | envsubst '${APP_PORT} ${APP_HOST}'

Arquivos de modelo no disco

Para configurações reais, armazene o modelo como um arquivo (por exemplo, nginx.conf.template) junto ao Dockerfile. Na inicialização do contêiner, execute envsubst para produzir o arquivo de configuração final antes de iniciar o processo de serviço.

Esse é o padrão clássico usado pela imagem oficial do NGINX.

#!/usr/bin/env bash
# File: nginx.conf.template
# (In practice this lives on disk; we write it here for demo purposes)
cat > /tmp/nginx.conf.template << 'TMPL'
server {
    listen ${NGINX_PORT};
    server_name ${SERVER_NAME};
    root /var/www/${APP_ENV};

    location / {
        proxy_pass http://app:${APP_PORT};
    }
}
TMPL

export NGINX_PORT=80
export SERVER_NAME=myapp.example.com
export APP_ENV=production
export APP_PORT=3000

# Generate final config
envsubst '${NGINX_PORT} ${SERVER_NAME} ${APP_ENV} ${APP_PORT}' \
  < /tmp/nginx.conf.template \
  > /tmp/nginx.conf

cat /tmp/nginx.conf

Blocos de texto entre aspas: modelos incorporados sem arquivo temporário

Um bloco de texto incorporado entre aspas (usando << 'EOF' com aspas simples ao redor do delimitador) impede que o interpretador de comandos expanda variáveis ou execute substituições de comandos dentro do bloco. O conteúdo é tratado como uma cadeia de caracteres literal.

Isso torna esses blocos a maneira ideal de escrever um modelo diretamente no código e canalizá-lo para envsubst — sem precisar de um arquivo intermediário.

  • << EOF (sem aspas) — o interpretador expande $VAR imediatamente
  • << 'EOF' (com aspas) — o conteúdo é literal; a expansão é adiada para envsubst
#!/usr/bin/env bash
export DB_HOST=postgres.internal
export DB_PORT=5432
export DB_NAME=myapp_prod

# Quoted heredoc: shell does NOT expand $DB_HOST etc. yet
envsubst << 'EOF'
[database]
host     = ${DB_HOST}
port     = ${DB_PORT}
dbname   = ${DB_NAME}
EOF
# Output uses actual env var values — expansion done by envsubst, not the shell

Combinando blocos de texto incorporados com redirecionamento de saída

Canalize um bloco de texto incorporado entre aspas por envsubst e redirecione o resultado para um arquivo em uma única expressão. Essa é a forma mais limpa de gerar arquivos de configuração em um script de entrada.

Use a substituição seletiva ('${VAR1} ${VAR2}') quando o formato de destino (Prometheus, NGINX etc.) tiver sua própria sintaxe $variable a ser protegida.

#!/usr/bin/env bash
# entrypoint.sh — Docker container entrypoint
set -euo pipefail

export PROM_PORT=${PROM_PORT:-9090}
export SCRAPE_INTERVAL=${SCRAPE_INTERVAL:-15s}
export TARGET_HOST=${TARGET_HOST:-localhost:8080}

envsubst '${PROM_PORT} ${SCRAPE_INTERVAL} ${TARGET_HOST}' << 'EOF' > /etc/prometheus/prometheus.yml
global:
  scrape_interval: ${SCRAPE_INTERVAL}
  evaluation_interval: ${SCRAPE_INTERVAL}

scrape_configs:
  - job_name: 'app'
    static_configs:
      - targets: ['${TARGET_HOST}']

EOF

echo "[entrypoint] Prometheus config written on port ${PROM_PORT}"
exec prometheus --config.file=/etc/prometheus/prometheus.yml --web.listen-address=":${PROM_PORT}"

Valores padrão e validação antes da substituição

Nunca presuma que todas as variáveis necessárias estão definidas. Use a expansão de parâmetros do Bash para fornecer valores padrão ou falhar de forma explícita:

  • ${VAR:-default} — use default se VAR não estiver definida ou estiver vazia
  • ${VAR:?error message} — aborte com um erro se VAR não estiver definida ou estiver vazia

Defina esses valores antes de chamar envsubst para que o modelo sempre receba um valor concreto ou o script seja interrompido antecipadamente com uma mensagem útil.

#!/usr/bin/env bash
set -euo pipefail

# Required — abort if missing
: "${DATABASE_URL:?DATABASE_URL must be set}"
: "${SECRET_KEY:?SECRET_KEY must be set}"

# Optional with defaults
export APP_PORT=${APP_PORT:-8000}
export LOG_LEVEL=${LOG_LEVEL:-info}
export WORKERS=${WORKERS:-4}

envsubst '${DATABASE_URL} ${SECRET_KEY} ${APP_PORT} ${LOG_LEVEL} ${WORKERS}' \
  < /app/config/app.conf.template \
  > /app/config/app.conf

echo "[init] Config generated — port=${APP_PORT} workers=${WORKERS} log=${LOG_LEVEL}"

Gerando configurações com várias seções usando vários blocos de texto incorporados

Para configurações complexas compostas por seções lógicas, você pode gerar cada seção independentemente e concatená-las ou usar um único bloco de texto incorporado que abranja todo o arquivo. As duas abordagens funcionam — escolha com base na legibilidade.

Quando as seções são incluídas condicionalmente (por exemplo, um bloco TLS somente se um caminho de certificado estiver definido), a abordagem com vários blocos e blocos if é mais clara.

#!/usr/bin/env bash
set -euo pipefail

export APP_HOST=${APP_HOST:-localhost}
export APP_PORT=${APP_PORT:-8080}
export TLS_CERT=${TLS_CERT:-}
export TLS_KEY=${TLS_KEY:-}

CONFIG_FILE=/tmp/app.conf

# Base section
envsubst '${APP_HOST} ${APP_PORT}' << 'BASE' > "$CONFIG_FILE"
[server]
host = ${APP_HOST}
port = ${APP_PORT}
BASE

# Conditional TLS section — only appended when cert is provided
if [[ -n "$TLS_CERT" && -n "$TLS_KEY" ]]; then
  envsubst '${TLS_CERT} ${TLS_KEY}' << 'TLS' >> "$CONFIG_FILE"

[tls]
cert_file = ${TLS_CERT}
key_file  = ${TLS_KEY}
TLS
  echo "[init] TLS enabled"
else
  echo "[init] TLS disabled (no cert/key provided)"
fi

cat "$CONFIG_FILE"

Padrão de ponto de entrada do Docker

O padrão recomendado de ponto de entrada do Docker usa um script de shell (docker-entrypoint.sh) para gerar as configurações na inicialização e, em seguida, transferir o controle ao processo principal com exec. Usar exec substitui o processo do interpretador pelo serviço, fazendo com que os sinais (SIGTERM, SIGINT) cheguem diretamente ao serviço — algo essencial para um desligamento controlado.

Os arquivos de modelo são adicionados à imagem durante a compilação; os valores são injetados durante a execução por docker run -e ou pelo Kubernetes usando env: / envFrom:.

#!/usr/bin/env bash
# docker-entrypoint.sh
set -euo pipefail

# Validate required env vars
for var in DATABASE_URL REDIS_URL SECRET_KEY; do
  : "${!var:?$var is required}"
done

export APP_PORT=${APP_PORT:-8000}
export WORKERS=${WORKERS:-$(nproc)}

echo "[entrypoint] Generating configuration..."
envsubst '${DATABASE_URL} ${REDIS_URL} ${SECRET_KEY} ${APP_PORT} ${WORKERS}' \
  < /app/config/settings.toml.template \
  > /app/config/settings.toml

echo "[entrypoint] Starting server on port ${APP_PORT} with ${WORKERS} workers"
exec gunicorn app:application \
  --bind "0.0.0.0:${APP_PORT}" \
  --workers "${WORKERS}"

Padrão Kubernetes ConfigMap + envsubst

No Kubernetes, as variáveis de ambiente são injetadas por meio de env: ou envFrom: na especificação do Pod. O ponto de entrada do contêiner chama envsubst para materializar as configurações antes do início do processo — não é necessário um ConfigMap para cada ambiente.

Isso mantém os valores específicos de cada ambiente nos Segredos e ConfigMaps do Kubernetes (para dados não confidenciais), enquanto o modelo de configuração permanece na imagem. Uma imagem, muitos ambientes.

  • Compilação: COPY nginx.conf.template /etc/nginx/templates/
  • Execução: o ponto de entrada executa envsubst e grava /etc/nginx/nginx.conf
  • O K8s injeta: APP_PORT, BACKEND_HOST a partir de um Secret/ConfigMap

Depurando envsubst: encontrando variáveis ausentes ou não resolvidas

Quando uma configuração gerada contém literalmente ${VAR} em vez de um valor, a variável não foi exportada ou não foi incluída na lista de substituição. Use estas técnicas para depurar:

  • printenv | sort — liste todas as variáveis exportadas
  • Compare os marcadores do modelo com as variáveis exportadas usando grep
  • Execute envsubst e use grep na saída para procurar padrões ${ restantes
  • Use set -u no script que faz a chamada para que referências a variáveis não definidas no código Bash interrompam a execução imediatamente
#!/usr/bin/env bash
set -euo pipefail

TEMPLATE=/tmp/app.conf.template
OUTPUT=/tmp/app.conf

# Write a demo template
cat > "$TEMPLATE" << 'EOF'
host=${DB_HOST}
port=${DB_PORT}
name=${DB_NAME}
EOF

export DB_HOST=db.internal
export DB_PORT=5432
# DB_NAME intentionally left unset

envsubst < "$TEMPLATE" > "$OUTPUT"

# Detect unresolved placeholders
if grep -qE '\$\{[A-Z_]+\}' "$OUTPUT"; then
  echo "ERROR: unresolved placeholders found:"
  grep -oE '\$\{[A-Z_]+\}' "$OUTPUT" | sort -u
  exit 1
fi

echo "Config OK:"
cat "$OUTPUT"

Verificação de conhecimento: substituição seletiva com envsubst

Considere um modelo de configuração do NGINX que contenha tanto a variável da sua aplicação ${APP_PORT} quanto a variável nativa do NGINX $uri. Você executa o seguinte comando:

envsubst < nginx.conf.template > nginx.conf

Qual é o resultado?

Recapitulação da lição: criando modelos de configurações com envsubst e blocos de texto incorporados

Agora você tem um conjunto de ferramentas de nível de produção para gerar configurações em tempo de execução com Bash:

  • envsubst substitui marcadores ${VAR} em qualquer arquivo de texto usando o ambiente atual — sem scripts, sem escapes especiais
  • Substituição seletiva (envsubst '${VAR1} ${VAR2}') protege variáveis nativas do NGINX, do Prometheus e de ferramentas semelhantes contra substituição acidental
  • Blocos de texto incorporados entre aspas (<< 'EOF') adiam a expansão do interpretador para que o conteúdo do modelo chegue intacto ao envsubst — sem necessidade de arquivos temporários
  • Valide antes de substituir: use ${VAR:?message} para interromper a execução quando faltarem variáveis obrigatórias e ${VAR:-default} para as opcionais
  • Padrão de ponto de entrada do Docker: gere as configurações na inicialização do contêiner e depois use exec para iniciar o serviço, garantindo o tratamento correto dos sinais
  • Depure marcadores não resolvidos procurando padrões ${ restantes na saída antes do início do processo

Esses padrões mantêm suas imagens de contêiner imutáveis, seus segredos fora do controle de versão e suas configurações consistentes em todos os ambientes.

Perguntas Frequentes

A aula “Criação de modelos de configurações com envsubst e heredocs” é grátis?

Sim — o texto completo de “Criação de modelos de configurações com envsubst e heredocs” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Linux Command Line & Bash Scripting Mastery, atualize para CoddyKit PRO. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

O que vou aprender em “Criação de modelos de configurações com envsubst e heredocs”?

Gere configurações em tempo de execução a partir de variáveis de ambiente usando envsubst e heredocs entre aspas. Você pratica Linux Command Line & Bash Scripting Mastery com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Linux Command Line & Bash Scripting Mastery?

Nenhuma experiência prévia é necessária. Linux Command Line & Bash Scripting Mastery no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Criação de modelos de configurações com envsubst e heredocs”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Linux Command Line & Bash Scripting Mastery?

Sim. Cada aula de Linux Command Line & Bash Scripting Mastery inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Dockerfiles enxutos e pontos de entrada do Shell
  2. Criação de modelos de configurações com envsubst e heredocs
  3. Criação de scripts para recursos de nuvem com CLI e jq
  4. Sondagens de integridade, barreiras de prontidão e loops de espera
← Voltar para Linux Command Line & Bash Scripting Mastery