0Pricing
DevOps Bootcamp · Lektion

Konfigurationen mit envsubst und Heredocs templatisieren

Erzeugen Sie mithilfe von envsubst und quotierten Heredocs Laufzeitkonfigurationen aus Umgebungsvariablen.

Konfigurationen mit envsubst und Heredocs templatisieren ist eine kostenlose DevOps Bootcamp-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des DevOps Bootcamp-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der DevOps Bootcamp-Kurs umfasst insgesamt 4 Lektionen.

Warum Laufzeit-Templating für Konfigurationen wichtig ist

In DevOps- und Container-Workflows müssen sich Konfigurationsdateien wie nginx.conf, prometheus.yml und docker-compose.yml häufig zwischen Umgebungen unterscheiden — etwa zwischen Staging, Produktion und DR. Hartcodierte Werte führen zu Abweichungen und zur Offenlegung von Secrets.

Die Lösung ist Konfigurations-Templating zur Laufzeit: Liefern Sie ein Template mit Platzhaltern aus und setzen Sie beim Start die tatsächlichen Werte aus Umgebungsvariablen ein. So bleibt Ihr Image unveränderlich und Ihre Konfiguration überprüfbar.

  • Keine Secrets im Image eingebettet
  • Dasselbe Artefakt kann über mehrere Umgebungen hinweg bereitgestellt werden
  • Die Konfiguration wird unmittelbar vor dem Start des Prozesses erzeugt

Zwei sich ergänzende Werkzeuge machen dies in Bash besonders einfach: envsubst und quotierte Heredocs.

envsubst: Der Konfigurationsgenerator in einer Zeile

envsubst ist ein kleines GNU-Dienstprogramm, das von stdin liest, Platzhalter der Form $VARIABLE und ${VARIABLE} durch ihre Werte aus der aktuellen Umgebung ersetzt und auf stdout schreibt.

Es wird mit dem Paket gettext ausgeliefert und ist praktisch in jeder Linux-Distribution und jedem Docker-Basis-Image verfügbar.

  • Funktioniert mit jedem Textformat: NGINX, YAML, TOML, JSON, INI
  • Wertet keine Shell-Syntax aus — es ersetzt nur Variablenreferenzen
  • Sicher: Es führt keine Befehle innerhalb des Templates aus
#!/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; }

Selektive Variablenersetzung

Standardmäßig ersetzt envsubst jedes gefundene $VAR. Dadurch können NGINX-Variablen wie $uri oder $host überschrieben werden — dabei handelt es sich um echte NGINX-Direktiven und nicht um Ihre Umgebungsvariablen.

Übergeben Sie als erstes Argument eine explizite Variablenliste, um die Ersetzung auf genau diese Namen zu beschränken:

envsubst '$VAR1 $VAR2'

Das Argument ist eine Zeichenkette in einfachen Anführungszeichen (damit die Shell sie nicht erweitert), die die zu ersetzenden Variablennamen enthält, getrennt durch Leerzeichen oder Zeilenumbrüche.

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

Template-Dateien auf der Festplatte

Speichern Sie echte Konfigurationen als Datei (z. B. nginx.conf.template) neben Ihrem Dockerfile. Führen Sie beim Start des Containers envsubst aus, um vor dem Start des Daemons die finale Konfigurationsdatei zu erzeugen.

Dies ist das kanonische Muster, das vom offiziellen NGINX-Docker-Image verwendet wird.

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

Quoted-Heredocs: Inline-Templates ohne temporäre Datei

Ein Quoted-Heredoc (mit << 'EOF' und einfachen Anführungszeichen um das Trennzeichen) verhindert, dass die Shell Variablen expandiert oder Befehlsersetzungen innerhalb des Blocks ausführt. Der Inhalt wird als Literalzeichenkette behandelt.

Dadurch eignen sich Heredocs ideal, um ein Template direkt einzubetten und ohne Zwischendatei direkt an envsubst weiterzuleiten.

  • << EOF (ohne Anführungszeichen) – die Shell expandiert $VAR sofort
  • << 'EOF' (mit Anführungszeichen) – der Inhalt bleibt wörtlich erhalten; die Expansion wird an envsubst verschoben
#!/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

Heredocs mit Ausgabeumleitung kombinieren

Leiten Sie ein Quoted-Heredoc durch envsubst und schreiben Sie das Ergebnis in einem Ausdruck in eine Datei um. Dies ist das sauberste Idiom zum Erzeugen von Konfigurationsdateien in einem Entrypoint-Skript.

Verwenden Sie eine selektive Substitution ('${VAR1} ${VAR2}'), wenn das Zielformat (Prometheus, NGINX usw.) eine eigene $variable-Syntax besitzt, die geschützt werden muss.

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

Standardwerte und Validierung vor der Substitution

Gehen Sie niemals davon aus, dass alle erforderlichen Variablen gesetzt sind. Verwenden Sie die Parameterexpansion von Bash, um Standardwerte bereitzustellen oder einen Fehler auszugeben:

  • ${VAR:-default} – verwendet default, wenn VAR nicht gesetzt oder leer ist
  • ${VAR:?error message} – bricht mit einem Fehler ab, wenn VAR nicht gesetzt oder leer ist

Setzen Sie diese Werte vor dem Aufruf von envsubst, damit das Template immer einen konkreten Wert erhält oder das Skript frühzeitig mit einer hilfreichen Meldung beendet wird.

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

Mehrteilige Konfigurationen mit mehreren Heredocs erzeugen

Bei komplexen Konfigurationen, die aus logisch getrennten Abschnitten bestehen, können Sie jeden Abschnitt unabhängig erzeugen und anschließend zusammenfügen oder ein einzelnes Heredoc verwenden, das sich über die gesamte Datei erstreckt. Beide Ansätze funktionieren – wählen Sie je nach Lesbarkeit.

Wenn Abschnitte bedingt eingebunden werden (z. B. ein TLS-Block nur, wenn ein Zertifikatspfad gesetzt ist), ist der Ansatz mit mehreren Heredocs und if-Blöcken übersichtlicher.

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

Docker-Entrypoint-Muster

Das empfohlene Docker-Entrypoint-Muster verwendet ein Shell-Skript (docker-entrypoint.sh), um Konfigurationen beim Start zu erzeugen und anschließend mit exec an den Hauptprozess zu übergeben. Durch exec wird der Shell-Prozess durch den Daemon ersetzt, sodass Signale (SIGTERM, SIGINT) den Daemon direkt erreichen – entscheidend für ein ordnungsgemäßes Herunterfahren.

Template-Dateien werden beim Erstellen zum Image hinzugefügt; Werte werden zur Laufzeit über docker run -e oder Kubernetes env: / envFrom: injiziert.

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

Kubernetes-ConfigMap- und envsubst-Muster

In Kubernetes werden Umgebungsvariablen über env: oder envFrom: in der Pod-Spezifikation injiziert. Der Entrypoint Ihres Containers ruft envsubst auf, um Konfigurationen zu materialisieren, bevor der Prozess startet – eine ConfigMap pro Umgebung ist nicht erforderlich.

Dadurch bleiben umgebungsspezifische Werte in Kubernetes-Secrets und ConfigMaps (für nicht vertrauliche Daten), während das Konfigurations-Template im Image liegt. Ein Image, viele Umgebungen.

  • Build: COPY nginx.conf.template /etc/nginx/templates/
  • Laufzeit: Der Entrypoint führt envsubst aus und schreibt /etc/nginx/nginx.conf
  • K8s injiziert: APP_PORT, BACKEND_HOST aus einem Secret/einer ConfigMap

envsubst debuggen: Fehlende oder nicht aufgelöste Variablen finden

Wenn eine erzeugte Konfiguration anstelle eines Werts das Literal ${VAR} enthält, wurde die Variable entweder nicht exportiert oder nicht in die Substitutionsliste aufgenommen. Verwenden Sie zum Debuggen die folgenden Techniken:

  • printenv | sort – listet alle exportierten Variablen auf
  • Vergleichen Sie die Platzhalter im Template mit den exportierten Variablen mithilfe von grep
  • Führen Sie envsubst aus und durchsuchen Sie die Ausgabe mit grep nach verbleibenden ${-Mustern
  • Verwenden Sie set -u im aufrufenden Skript, damit Verweise auf nicht gesetzte Variablen im Bash-Code sofort zum Abbruch führen
#!/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"

Wissenscheck: Selektive Substitution mit envsubst

Betrachten Sie ein NGINX-Konfigurationstemplate, das sowohl Ihre Anwendungsvariable ${APP_PORT} als auch die native NGINX-Variable $uri enthält. Sie führen den folgenden Befehl aus:

envsubst < nginx.conf.template > nginx.conf

Was ist das Ergebnis?

Lektionszusammenfassung: Konfigurationen mit envsubst und Heredocs templatisieren

Sie verfügen nun über ein produktionsreifes Werkzeugset zur Erzeugung von Laufzeitkonfigurationen in Bash:

  • envsubst ersetzt Platzhalter wie ${VAR} in jeder Textdatei mithilfe der aktuellen Umgebung – ohne Skripting und ohne spezielle Maskierung
  • Selektive Substitution (envsubst '${VAR1} ${VAR2}') schützt native Variablen in NGINX, Prometheus und ähnlichen Tools vor versehentlichem Ersetzen
  • Quoted-Heredocs (<< 'EOF') verschieben die Expansion durch die Shell, sodass der Template-Inhalt unverändert bei envsubst ankommt – temporäre Dateien sind nicht erforderlich
  • Vor der Substitution validieren: Verwenden Sie ${VAR:?message}, um bei fehlenden erforderlichen Variablen abzubrechen, und ${VAR:-default} für optionale Variablen
  • Docker-Entrypoint-Muster: Erzeugen Sie Konfigurationen beim Start des Containers und führen Sie anschließend den Daemon mit exec aus, damit Signale korrekt verarbeitet werden
  • Nicht aufgelöste Platzhalter debuggen, indem Sie die Ausgabe vor dem Start des Prozesses mit grep nach verbleibenden ${-Mustern durchsuchen

Diese Muster halten Ihre Container-Images unveränderlich, Ihre Secrets aus der Quellcodeverwaltung heraus und Ihre Konfigurationen in allen Umgebungen konsistent.

Häufig gestellte Fragen

Ist die Lektion „Konfigurationen mit envsubst und Heredocs templatisieren“ kostenlos?

Ja — der vollständige Text von „Konfigurationen mit envsubst und Heredocs templatisieren“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des DevOps Bootcamp-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der DevOps Bootcamp-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Konfigurationen mit envsubst und Heredocs templatisieren“?

Erzeugen Sie mithilfe von envsubst und quotierten Heredocs Laufzeitkonfigurationen aus Umgebungsvariablen. Du übst DevOps Bootcamp mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um DevOps Bootcamp zu starten?

Keine Vorkenntnisse erforderlich. DevOps Bootcamp auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „Konfigurationen mit envsubst und Heredocs templatisieren“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser DevOps Bootcamp-Lektion Code schreiben und ausführen?

Ja. Jede DevOps Bootcamp-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Schlanke Dockerfiles und Shell-Entrypoints schreiben
  2. Konfigurationen mit envsubst und Heredocs templatisieren
  3. Cloud-Ressourcen per CLI und jq skripten
  4. Health-Probes, Readiness-Gates und Warteschleifen
← Zurück zu DevOps Bootcamp