Rejstřík deníkuDockup / terénní poznámka
Note / env-vars-not-reaching-container

Proměnné prostředí se nedostávají do kontejneru

Proměnné prostředí, které v kontejneru nefungují, obvykle selžou z jednoho z pěti důvodů: rozdíl mezi dobou sestavení a runtime, bundling frontendu, uvozovky, načasování restartu nebo nesprávný rozsah. Ověřte je v uvedeném pořadí.

Proměnnou nastavíte. Dashboard ji zobrazuje. Aplikace hlásí, že je undefined. Proměnné prostředí, které v kontejneru nefungují, patří mezi nejčastější konfigurační problémy při hostování aplikací a téměř vždy jde o jednu z pěti konkrétních příčin.

Níže jsou uvedeny v pořadí, ve kterém problém odhalíte nejrychleji.

1. Doba sestavení a runtime jsou dva odlišné světy

Toto způsobuje více těchto problémů než zbývající čtyři příčiny dohromady a zároveň jde o důvod, který lidé považují za nejméně intuitivní.

Proměnné nastavené u služby existují ve chvíli, kdy kontejner běží. Všechno, co provádí Dockerfile, se děje dříve a v odděleném prostředí. Krok RUN runtime proměnnou nevidí, protože v danou chvíli žádný runtime neexistuje.

# This is empty during build. Always.
RUN echo $DATABASE_URL

# This is available at runtime, because it is the running process reading it
CMD ["node", "server.js"]

Pokud hodnotu skutečně potřebujete během sestavení, musíte ji předat jako build argument — jde o jiný mechanismus s odlišnými bezpečnostními vlastnostmi:

ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"

Tímto způsobem nikdy nepředávejte secret. Build argumenty se ukládají do historie vrstev image. Každý, kdo může image stáhnout, si je může přečíst.

2. Proměnné frontendu se zapíší při sestavení, nečtou se

Pokud váš frontend v produkci hlásí undefined, téměř jistě je to tento případ.

Prohlížeč nemá vlastní prostředí. Když napíšete import.meta.env.VITE_API_URL nebo process.env.NEXT_PUBLIC_API_URL, bundler při sestavení nahradí výraz konkrétním textovým řetězcem. V prohlížeči se žádné vyhledávání neprovádí — hodnota byla zkompilována přímo do výsledku.

To má tři důsledky, které často zaskočí:

  • Změna proměnné se neprojeví, dokud znovu nesestavíte aplikaci. Stará hodnota je uvnitř JavaScriptového souboru.
  • Prefix je povinný. Vite zpřístupňuje pouze proměnné s prefixem VITE_, Next.js pouze proměnné s prefixem NEXT_PUBLIC_. Proměnná bez prefixu je záměrně skryta.
  • Všechno takto zpřístupněné je veřejné. Nachází se v souboru, který poskytujete komukoli. Nikdy neschovávejte secret za NEXT_PUBLIC_, bez ohledu na to, co název naznačuje.

Proto také tímto způsobem nelze dodatečně nakonfigurovat předem sestavený image. Pokud byl image sestaven jinde a hodnoty byly zkompilovány dovnitř, nastavení proměnných u služby nic nezmění — řetězce už jsou součástí bundlu.

3. Uvozovky

Hodnoty se speciálními znaky se mohou upravit způsobem, který vede ke zmatečným chybám místo těch zjevných.

# The shell eats everything after #
dockup env set DB_PASS=p@ss#word my-project/my-api

# Quote it
dockup env set 'DB_PASS=p@ss#word' my-project/my-api

Problémy způsobují tyto znaky: # (komentář), $ (expanze), mezery (rozdělení argumentů), ! (expanze historie v interaktivním bashe) a nové řádky — ty se objevují v jediném běžném případě, u private keys.

Nejhorší jsou víceřádkové hodnoty. PEM klíč vložený do jedn řádkového pole dorazí bez nových řádků a způsobí chybu při parsování, která o nových řádcích nic neříká. Převeďte jej do Base64 a dekódujte v aplikaci:

dockup env set "PRIVATE_KEY_B64=$(base64 -i key.pem)" my-project/my-api

4. Nerestartovali jste aplikaci

Proces načte proměnné prostředí při svém spuštění. Jejich změna ovlivní další proces, nikoli ten, který právě běží.

Většina platforem to řeší automatickým redeployem po změně konfigurace, ale ne všechny. Částečná změna — nastavíte tři proměnné, provedete redeploy a nastavíte čtvrtou — navíc může způsobit, že jedna zůstane nezohledněná.

dockup env list my-project/my-api --json   # what is configured
dockup restart my-project/my-api            # make the process re-read it

Rozhodující kontrola je přečíst proměnnou přímo z běžícího kontejneru, nikoli z dashboardu.

dockup exec "printenv | sort" my-project/my-api

Pokud je ve výstupu a vaše aplikace stále hlásí undefined, problém je v kódu. Pokud ve výstupu není, problém je v konfiguraci. Tento jediný příkaz rozdělí prostor pro hledání problému na dvě poloviny.

5. Nesprávný rozsah

Proměnné se obvykle nastavují v určitém rozsahu — pro službu, prostředí nebo projekt. Proměnná nastavená v produkci není viditelná v preview prostředí. Proměnná nastavená u jiné služby ve stejném projektu není viditelná také.

To je obvyklá příčina situace, kdy něco funguje na jednom místě, ale jinde ne, přestože kód je stejný.

Pořadí diagnostiky

# 1. Is it actually in the container's environment?
dockup exec "printenv | sort" my-project/my-api

# 2. Is it configured on the service you think it is?
dockup env list my-project/my-api --json

# 3. Is the running process older than the change?
dockup status my-project/my-api --json

Vždy začněte krokem 1. Nejasný problém převede na jeden ze dvou jednoznačných problémů.

Konkrétně k secretům

Bez ohledu na platformu se vyplatí osvojit si dva návyky.

Označujte secrety jako secrety. V Dockup je secret proměnná v seznamech a API odpovědích skrytá — dockup env list zobrazí ******** namísto hodnoty. Je to důležitější, než se může zdát, protože nejčastějším způsobem úniku přihlašovacích údajů není útok, ale screenshot, požadavek na podporu nebo řádek v logu.

Nedávejte je do build argumentů ani do frontendových bundlů. Obojí si může přečíst kdokoli, kdo získá artefakt. Praktické pravidlo: pokud hodnota skončí v souboru, který distribuujete, už nejde o secret.

Často kladené otázky

Proč je moje proměnná prostředí během sestavení nedefinovaná? Protože sestavení a runtime jsou oddělená prostředí. Runtime proměnné během sestavování image neexistují. Pokud hodnotu během sestavení skutečně potřebujete, použijte build argument — nikdy však secret.

Proč frontend proměnnou nevidí? Bundlery nahrazují hodnotu při sestavení a zpřístupňují pouze názvy s prefixem — VITE_, NEXT_PUBLIC_. Změna proměnné vyžaduje nové sestavení a vše takto zpřístupněné je veřejně čitelné.

Musím po změně proměnné provést restart? Ano. Běžící proces už své prostředí načetl. Většina platforem při změně automaticky provede redeploy; ověřte to pomocí printenv uvnitř kontejneru a nespoléhejte pouze na dashboard.

Jak předám víceřádkovou hodnotu, například private key? Převeďte ji do Base64, nastavte zakódovaný řetězec a dekódujte jej v aplikaci. Jednořádková pole pro proměnné prostředí odstraňují nové řádky a způsobují chyby při parsování, které se o nových řádcích nezmiňují.