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.confBlocos 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$VARimediatamente<< 'EOF'(com aspas) — o conteúdo é literal; a expansão é adiada paraenvsubst
#!/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 shellCombinando 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}— usedefaultseVARnão estiver definida ou estiver vazia${VAR:?error message}— aborte com um erro seVARnã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
envsubste grava/etc/nginx/nginx.conf - O K8s injeta:
APP_PORT,BACKEND_HOSTa 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
envsubste use grep na saída para procurar padrões${restantes - Use
set -uno 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 aoenvsubst— 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
execpara 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
- Dockerfiles enxutos e pontos de entrada do Shell
- Criação de modelos de configurações com envsubst e heredocs
- Criação de scripts para recursos de nuvem com CLI e jq
- Sondagens de integridade, barreiras de prontidão e loops de espera