0Pricing
Linux Command Line & Bash Scripting Mastery · Lekcja

Szablony konfiguracji za pomocą envsubst i heredoc

Generuj konfigurację środowiska uruchomieniowego ze zmiennych środowiskowych, używając envsubst i cytowanych heredoców.

Szablony konfiguracji za pomocą envsubst i heredoc to bezpłatna lekcja Linux Command Line & Bash Scripting Mastery na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Linux Command Line & Bash Scripting Mastery, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Dlaczego szablonowanie konfiguracji w czasie działania ma znaczenie

W procesach DevOps i pracy z kontenerami pliki konfiguracji, takie jak nginx.conf, prometheus.yml i docker-compose.yml, często muszą się różnić między środowiskami — testowym, produkcyjnym i awaryjnym (DR). Wpisywanie wartości na stałe powoduje rozbieżności i ujawnienie sekretów.

Rozwiązaniem jest szablonowanie konfiguracji w czasie działania: należy dostarczyć szablon z symbolami zastępczymi, a następnie podczas uruchamiania wstawić rzeczywiste wartości ze zmiennych środowiskowych. Dzięki temu obraz pozostaje niezmienny, a konfigurację można kontrolować.

  • Żadne sekrety nie są zapisane w obrazach
  • Ten sam artefakt można promować między środowiskami
  • Konfiguracja jest generowana bezpośrednio przed uruchomieniem procesu

Dwa uzupełniające się narzędzia sprawiają, że w Bashu jest to bardzo proste: envsubst i heredoki z cytowanym ogranicznikiem.

envsubst: generator konfiguracji w jednej linii

envsubst to niewielkie narzędzie GNU, które odczytuje standardowe wejście, zastępuje symbole zastępcze $VARIABLE i ${VARIABLE} wartościami z bieżącego środowiska, a następnie zapisuje wynik na standardowym wyjściu.

Narzędzie jest dostarczane w pakiecie gettext i jest dostępne praktycznie w każdej dystrybucji Linuksa oraz bazowym obrazie Docker.

  • Działa z dowolnym formatem tekstowym: NGINX, YAML, TOML, JSON, INI
  • Nie interpretuje składni powłoki — zastępuje wyłącznie odwołania do zmiennych
  • Jest bezpieczne: nie wykonuje poleceń znajdujących się w szablonie
#!/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; }

Selektywne podstawianie zmiennych

Domyślnie envsubst zastępuje każde znalezione wystąpienie $VAR. Może to nadpisać zmienne NGINX, takie jak $uri lub $host — są to rzeczywiste dyrektywy NGINX, a nie zmienne środowiskowe.

Aby ograniczyć podstawianie tylko do określonych nazw, należy przekazać jawną listę zmiennych jako pierwszy argument:

envsubst '$VAR1 $VAR2'

Argument jest pojedynczym łańcuchem ujętym w pojedyncze cudzysłowy (dzięki czemu powłoka go nie rozwija), zawierającym nazwy zmiennych, które mają zostać zastąpione, oddzielone spacjami lub znakami nowego wiersza.

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

Pliki szablonów na dysku

W przypadku rzeczywistych konfiguracji szablon należy przechowywać w pliku (np. nginx.conf.template) obok pliku Dockerfile. Podczas uruchamiania kontenera należy wykonać envsubst, aby utworzyć końcowy plik konfiguracji przed uruchomieniem demona.

Jest to kanoniczny wzorzec używany w oficjalnym obrazie Docker 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

Cytowane heredoki: szablony inline bez pliku tymczasowego

Cytowany heredok (z użyciem << 'EOF' i pojedynczych cudzysłowów wokół ogranicznika) zapobiega rozwijaniu zmiennych przez powłokę oraz wykonywaniu podstawień poleceń wewnątrz bloku. Zawartość jest traktowana jak literał tekstowy.

Dzięki temu heredoki są idealnym sposobem na zapisanie szablonu bezpośrednio w skrypcie i przekazanie go potokiem wprost do envsubst — bez potrzeby używania pliku pośredniego.

  • << EOF (bez cudzysłowów) — powłoka od razu rozwija $VAR
  • << 'EOF' (w cudzysłowach) — zawartość jest literałem; podstawienie jest odroczone do 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

Łączenie heredoków z przekierowaniem wyjścia

Przekieruj cytowany heredok przez envsubst, a następnie zapisz wynik do pliku w jednym wyrażeniu. To najbardziej przejrzysty idiom generowania plików konfiguracyjnych w skrypcie entrypoint.

Użyj wybiórczego podstawiania ('${VAR1} ${VAR2}'), gdy docelowy format (Prometheus, NGINX itd.) ma własną składnię $variable, którą należy chronić.

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

Wartości domyślne i walidacja przed podstawieniem

Nie należy zakładać, że wszystkie wymagane zmienne są ustawione. Użyj rozwijania parametrów Bash, aby podać wartości domyślne lub zakończyć działanie z wyraźnym komunikatem błędu:

  • ${VAR:-default} — użyj wartości default, jeśli VAR jest nieustawiona lub pusta
  • ${VAR:?error message} — przerwij działanie z błędem, jeśli VAR jest nieustawiona lub pusta

Ustaw te wartości przed wywołaniem envsubst, aby szablon zawsze otrzymał konkretną wartość albo skrypt wcześnie zatrzymał się z pomocnym komunikatem.

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

Generowanie konfiguracji wielosekcyjnych za pomocą wielu heredoków

W przypadku złożonych konfiguracji zbudowanych z logicznych sekcji można generować każdą sekcję niezależnie i łączyć je, albo użyć pojedynczego heredoka obejmującego cały plik. Oba podejścia działają — należy wybrać je na podstawie czytelności.

Gdy sekcje są dołączane warunkowo (np. blok TLS tylko wtedy, gdy ustawiona jest ścieżka certyfikatu), podejście z wieloma heredokami i blokami if jest bardziej przejrzyste.

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

Wzorzec Docker entrypoint

Zalecany wzorzec Docker entrypoint wykorzystuje skrypt powłoki (docker-entrypoint.sh) do generowania konfiguracji podczas uruchamiania, a następnie przekazuje sterowanie głównemu procesowi za pomocą exec. Użycie exec zastępuje proces powłoki procesem demona, dzięki czemu sygnały (SIGTERM, SIGINT) docierają bezpośrednio do demona — ma to kluczowe znaczenie dla kontrolowanego zamknięcia.

Pliki szablonów są dodawane do obrazu podczas budowania, a wartości są wstrzykiwane podczas uruchamiania za pomocą docker run -e lub 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}"

Wzorzec Kubernetes ConfigMap + envsubst

W Kubernetes zmienne środowiskowe są wstrzykiwane za pomocą env: lub envFrom: w specyfikacji Poda. Punkt wejścia kontenera wywołuje envsubst, aby wygenerować konfigurację przed uruchomieniem procesu — nie jest potrzebny osobny ConfigMap dla każdego środowiska.

Dzięki temu wartości specyficzne dla środowiska pozostają w Kubernetes Secrets i ConfigMaps (w przypadku danych niepoufnych), a szablon konfiguracji znajduje się w obrazie. Jeden obraz, wiele środowisk.

  • Budowanie: COPY nginx.conf.template /etc/nginx/templates/
  • Czas działania: punkt wejścia uruchamia envsubst i zapisuje /etc/nginx/nginx.conf
  • K8s wstrzykuje: APP_PORT, BACKEND_HOST z Secret/ConfigMap

Debugowanie envsubst: znajdowanie brakujących lub nierozwiązanych zmiennych

Jeśli wygenerowana konfiguracja zawiera dosłowne ${VAR} zamiast wartości, zmienna nie została wyeksportowana albo nie uwzględniono jej na liście podstawiania. Do debugowania można użyć następujących technik:

  • printenv | sort — wyświetlenie wszystkich wyeksportowanych zmiennych
  • Porównanie symboli zastępczych w szablonie ze zmiennymi wyeksportowanymi za pomocą grep
  • Uruchomienie envsubst i wyszukanie w wyjściu pozostałych wzorców ${
  • Użycie set -u w wywołującym skrypcie, aby odwołania do nieustawionych zmiennych w kodzie Bash natychmiast przerywały działanie
#!/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"

Sprawdź wiedzę: wybiórcze podstawianie za pomocą envsubst

Rozważ szablon konfiguracji NGINX, który zawiera zarówno zmienną aplikacji ${APP_PORT}, jak i natywną zmienną NGINX $uri. Uruchamiasz następujące polecenie:

envsubst < nginx.conf.template > nginx.conf

Jaki będzie rezultat?

Podsumowanie lekcji: tworzenie szablonów konfiguracji za pomocą envsubst i heredoków

Masz teraz gotowy do użycia w środowisku produkcyjnym zestaw narzędzi do generowania konfiguracji w Bash:

  • envsubst zastępuje symbole zastępcze ${VAR} w dowolnym pliku tekstowym, korzystając z bieżącego środowiska — bez pisania skryptów i specjalnego maskowania
  • Wybiórcze podstawianie (envsubst '${VAR1} ${VAR2}') chroni natywne zmienne w NGINX, Prometheus i podobnych narzędziach przed przypadkowym zastąpieniem
  • Cytowane heredoki (<< 'EOF') odraczają rozwijanie powłoki, dzięki czemu zawartość szablonu dociera do envsubst bez zmian — bez potrzeby tworzenia plików tymczasowych
  • Waliduj przed podstawieniem: użyj ${VAR:?message}, aby przerwać działanie w przypadku braku wymaganych zmiennych, oraz ${VAR:-default} dla zmiennych opcjonalnych
  • Wzorzec Docker entrypoint: generuj konfigurację podczas uruchamiania kontenera, a następnie użyj exec dla demona, aby sygnały były prawidłowo obsługiwane
  • Debuguj nierozwiązane symbole zastępcze, wyszukując w wyjściu pozostałe wzorce ${ przed uruchomieniem procesu

Wzorce te pozwalają zachować niezmienność obrazów kontenerów, nie umieszczać sekretów w systemie kontroli wersji oraz utrzymywać spójność konfiguracji we wszystkich środowiskach.

Często zadawane pytania

Czy lekcja „Szablony konfiguracji za pomocą envsubst i heredoc” jest bezpłatna?

Tak — pełny tekst „Szablony konfiguracji za pomocą envsubst i heredoc” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Linux Command Line & Bash Scripting Mastery, przejdź na CoddyKit PRO. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Co nauczysz się w „Szablony konfiguracji za pomocą envsubst i heredoc”?

Generuj konfigurację środowiska uruchomieniowego ze zmiennych środowiskowych, używając envsubst i cytowanych heredoców. Ćwiczysz Linux Command Line & Bash Scripting Mastery z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Linux Command Line & Bash Scripting Mastery?

Nie wymagamy żadnego doświadczenia. Linux Command Line & Bash Scripting Mastery w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Szablony konfiguracji za pomocą envsubst i heredoc”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Linux Command Line & Bash Scripting Mastery?

Tak. Każda lekcja Linux Command Line & Bash Scripting Mastery zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Odchudzone Dockerfile i punkty wejścia powłoki
  2. Szablony konfiguracji za pomocą envsubst i heredoc
  3. Skryptowanie zasobów chmurowych za pomocą CLI i jq
  4. sondy kondycji, bramki gotowości i pętle oczekiwania
← Powrót do Linux Command Line & Bash Scripting Mastery