0Pricing
Linux Command Line & Bash Scripting Mastery · Lezione

Creare template di configurazione con envsubst e heredoc

Generi la configurazione a runtime dalle variabili d'ambiente usando envsubst e heredoc tra virgolette.

Creare template di configurazione con envsubst e heredoc è una lezione Linux Command Line & Bash Scripting Mastery gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Linux Command Line & Bash Scripting Mastery, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Perché è importante generare la configurazione a runtime

Nei flussi di lavoro DevOps e con i container, i file di configurazione come nginx.conf, prometheus.yml e docker-compose.yml devono spesso cambiare tra gli ambienti — staging, produzione e DR. Inserire i valori direttamente nei file causa divergenze ed esposizione dei secret.

La soluzione è la generazione della configurazione a runtime: distribuisca un template con segnaposto, quindi inserisca i valori reali all'avvio tramite le variabili d'ambiente. In questo modo l'immagine rimane immutabile e la configurazione verificabile.

  • Nessun secret incorporato nelle immagini
  • Lo stesso artifact promosso tra gli ambienti
  • Configurazione generata subito prima dell'avvio del processo

In Bash, due strumenti complementari rendono tutto questo semplicissimo: envsubst e gli heredoc quotati.

envsubst: il generatore di configurazione in una riga

envsubst è una piccola utility GNU che legge dallo stdin, sostituisce i segnaposto $VARIABLE e ${VARIABLE} con i rispettivi valori dell'ambiente corrente e scrive sullo stdout.

È incluso nel pacchetto gettext ed è disponibile praticamente in ogni distribuzione Linux e immagine base Docker.

  • Funziona con qualsiasi formato testuale: NGINX, YAML, TOML, JSON, INI
  • Non valuta la sintassi della shell: sostituisce solo i riferimenti alle variabili
  • È sicuro: non esegue i comandi contenuti nel template
#!/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; }

Sostituzione selettiva delle variabili

Per impostazione predefinita, envsubst sostituisce ogni $VAR che trova. Questo può alterare variabili NGINX come $uri o $host: sono direttive NGINX reali, non variabili d'ambiente.

Passi un elenco esplicito di variabili come primo argomento per limitare la sostituzione esclusivamente a quei nomi:

envsubst '$VAR1 $VAR2'

L'argomento è una stringa racchiusa tra apici singoli (in modo che la shell non la espanda) contenente i nomi delle variabili da sostituire, separati da spazi o da ritorni a capo.

#!/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}'

File template su disco

Per le configurazioni reali, memorizzi il template in un file (ad es. nginx.conf.template) insieme al Dockerfile. All'avvio del container, esegua envsubst per produrre il file di configurazione finale prima di avviare il demone.

Questo è il pattern canonico utilizzato dall'immagine Docker ufficiale di 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

Heredoc quotati: template inline senza file temporanei

Un heredoc quotato (che utilizza << 'EOF' con il delimitatore racchiuso tra virgolette singole) impedisce alla shell di espandere le variabili o eseguire sostituzioni di comandi all'interno del blocco. Il contenuto viene trattato come una stringa letterale.

Questo rende gli heredoc il modo ideale per scrivere un template inline e passarlo direttamente tramite pipe a envsubst, senza bisogno di un file intermedio.

  • << EOF (senza virgolette) — la shell espande immediatamente $VAR
  • << 'EOF' (tra virgolette) — il contenuto è letterale; l'espansione viene rimandata a 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

Combinare gli heredoc con il reindirizzamento dell'output

Convogli un heredoc quotato tramite envsubst e reindirizzi il risultato a un file con una sola espressione. Questo è l'idioma più chiaro per generare file di configurazione in uno script dell'entrypoint.

Utilizzi la sostituzione selettiva ('${VAR1} ${VAR2}') quando il formato di destinazione (Prometheus, NGINX e così via) dispone di una propria sintassi $variable da proteggere.

#!/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}"

Valori predefiniti e convalida prima della sostituzione

Non dia mai per scontato che tutte le variabili obbligatorie siano impostate. Utilizzi l'espansione dei parametri di Bash per fornire valori predefiniti o interrompere esplicitamente l'esecuzione:

  • ${VAR:-default} — usa default se VAR non è impostata o è vuota
  • ${VAR:?error message} — interrompe l'esecuzione con un errore se VAR non è impostata o è vuota

Imposti questi valori prima di chiamare envsubst, in modo che il template riceva sempre un valore concreto oppure che lo script si interrompa subito mostrando un messaggio utile.

#!/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}"

Generare configurazioni con più sezioni usando più heredoc

Per configurazioni complesse composte da sezioni logiche, è possibile generare ogni sezione indipendentemente e concatenarle, oppure utilizzare un unico heredoc che comprenda l'intero file. Entrambi gli approcci funzionano: scelga in base alla leggibilità.

Quando le sezioni vengono incluse condizionalmente (ad esempio, il blocco TLS solo se è impostato un percorso per il certificato), l'approccio con più heredoc e blocchi if risulta più chiaro.

#!/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"

Pattern dell'entrypoint Docker

Il pattern consigliato per l'entrypoint Docker utilizza uno script shell (docker-entrypoint.sh) per generare le configurazioni all'avvio, quindi cedere il controllo al processo principale con exec. L'uso di exec sostituisce il processo della shell con il demone, così i segnali (SIGTERM, SIGINT) arrivano direttamente al demone: un aspetto fondamentale per un arresto ordinato.

I file template vengono aggiunti all'immagine durante la build; i valori vengono inseriti a runtime tramite docker run -e o Kubernetes 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}"

Pattern Kubernetes ConfigMap + envsubst

In Kubernetes, le variabili d'ambiente vengono inserite tramite env: o envFrom: nella specifica del Pod. L'entrypoint del container chiama envsubst per generare le configurazioni prima dell'avvio del processo: non è necessario creare una ConfigMap per ogni ambiente.

In questo modo i valori specifici dell'ambiente restano in Kubernetes, nelle Secrets e nelle ConfigMaps (per i dati non sensibili), mentre il template di configurazione risiede nell'immagine. Una sola immagine per molti ambienti.

  • Build: COPY nginx.conf.template /etc/nginx/templates/
  • Runtime: l'entrypoint esegue envsubst e scrive /etc/nginx/nginx.conf
  • K8s inserisce: APP_PORT, BACKEND_HOST da una Secret o ConfigMap

Debugging di envsubst: trovare variabili mancanti o non risolte

Quando una configurazione generata contiene il valore letterale ${VAR} invece di un valore effettivo, la variabile non è stata esportata oppure non è stata inclusa nell'elenco di sostituzione. Utilizzi queste tecniche per eseguire il debugging:

  • printenv | sort — elenca tutte le variabili esportate
  • Confronti i segnaposto del template con le variabili esportate usando grep
  • Esegua envsubst e cerchi nell'output i pattern ${ ancora presenti
  • Utilizzi set -u nello script chiamante, così i riferimenti a variabili non impostate nel codice Bash interrompono immediatamente l'esecuzione
#!/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 delle conoscenze: sostituzione selettiva con envsubst

Consideri un template di configurazione NGINX che contiene sia la variabile dell'applicazione ${APP_PORT} sia la variabile nativa di NGINX $uri. Esegue il comando seguente:

envsubst < nginx.conf.template > nginx.conf

Qual è il risultato?

Riepilogo della lezione: creare template per le configurazioni con envsubst ed heredoc

Ora dispone di uno strumentario adatto alla produzione per generare configurazioni a runtime in Bash:

  • envsubst sostituisce i segnaposto ${VAR} in qualsiasi file di testo usando l'ambiente corrente, senza dover scrivere script né gestire caratteri di escape speciali
  • La sostituzione selettiva (envsubst '${VAR1} ${VAR2}') protegge le variabili native di NGINX, Prometheus e strumenti simili dalla sostituzione accidentale
  • Gli heredoc quotati (<< 'EOF') rimandano l'espansione della shell, così il contenuto del template arriva intatto a envsubst, senza bisogno di file temporanei
  • Convalidare prima della sostituzione: utilizzi ${VAR:?message} per interrompere l'esecuzione in caso di variabili obbligatorie mancanti e ${VAR:-default} per quelle facoltative
  • Pattern dell'entrypoint Docker: generi le configurazioni all'avvio del container, quindi utilizzi exec per il demone, così i segnali vengono gestiti correttamente
  • Eseguire il debugging dei segnaposto non risolti cercando nell'output i pattern ${ ancora presenti prima dell'avvio del processo

Questi pattern mantengono immutabili le immagini dei container, tengono i segreti fuori dal controllo versione e garantiscono configurazioni coerenti in ogni ambiente.

Domande Frequenti

La lezione «Creare template di configurazione con envsubst e heredoc» è gratuita?

Sì — il testo completo di «Creare template di configurazione con envsubst e heredoc» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Linux Command Line & Bash Scripting Mastery, passa a CoddyKit PRO. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Cosa imparerò in «Creare template di configurazione con envsubst e heredoc»?

Generi la configurazione a runtime dalle variabili d'ambiente usando envsubst e heredoc tra virgolette. Eserciti Linux Command Line & Bash Scripting Mastery con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Linux Command Line & Bash Scripting Mastery?

Non è richiesta alcuna esperienza precedente. Linux Command Line & Bash Scripting Mastery su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Creare template di configurazione con envsubst e heredoc»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Linux Command Line & Bash Scripting Mastery?

Sì. Ogni lezione Linux Command Line & Bash Scripting Mastery include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Scrivere Dockerfile essenziali ed entrypoint shell
  2. Creare template di configurazione con envsubst e heredoc
  3. Gestire risorse cloud tramite CLI e jq
  4. Probe di salute, controlli di readiness e cicli di attesa
← Torna a Linux Command Line & Bash Scripting Mastery