Index denníkaDockup / poznámka z terénu
Note / env-vars-not-reaching-container

Premenné prostredia sa nedostávajú do kontajnera

Premenné prostredia, ktoré v kontajneri nefungujú, zvyčajne zlyhávajú z jedného z piatich dôvodov: build time verzus runtime, bundling frontendu, úvodzovky, načasovanie reštartu alebo nesprávny scope. Overujte ich v tomto poradí.

Nastavíte premennú. Dashboard ju zobrazuje. Aplikácia hlási, že je undefined. Premenné prostredia, ktoré v kontajneri nefungujú, patria medzi najčastejšie zlyhania konfigurácie pri hostovaní aplikácií a takmer vždy ide o jednu z piatich konkrétnych príčin.

Uvádzame ich v poradí, v ktorom problém nájdete najrýchlejšie.

1. Build time a runtime sú dva odlišné svety

Toto spôsobuje viac problémov než zvyšné štyri príčiny dohromady a zároveň ide o dôvod, ktorý ľudia považujú za najmenej intuitívny.

Premenné nastavené v službe existujú v momente, keď kontajner beží. Všetko, čo vykonáva váš Dockerfile, sa deje skôr, v oddelenom prostredí. Krok RUN nevidí runtime premennú, pretože v danom momente ešte žiadny 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"]

Ak hodnotu skutočne potrebujete počas buildu, musíte ju odovzdať ako build argument — ide o odlišný mechanizmus s inými bezpečnostnými vlastnosťami:

ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"

Týmto spôsobom nikdy neodovzdávajte secret. Build argumenty sa zaznamenávajú do histórie vrstiev image. Každý, kto si môže image stiahnuť, si ich môže prečítať.

2. Premenné frontendu sú vložené do buildu, nie načítané

Ak váš frontend v produkcii hlási undefined, takmer určite je toto dôvod.

Prehliadač nemá environment. Keď napíšete import.meta.env.VITE_API_URL alebo process.env.NEXT_PUBLIC_API_URL, bundler nahradí tento výraz konkrétnym textovým reťazcom počas buildu. V prehliadači sa nič nevyhľadáva — hodnota bola skompilovaná priamo do výsledku.

To má tri dôsledky, ktoré často zaskočia:

  • Zmena premennej nič neurobí, kým nespustíte nový build. Stará hodnota je uložená v JavaScriptovom súbore.
  • Prefix je povinný. Vite sprístupňuje iba premenné s prefixom VITE_, Next.js iba premenné s prefixom NEXT_PUBLIC_. Premenná bez prefixu je zámerne skrytá.
  • Všetko takto sprístupnené je verejné. Nachádza sa v súbore, ktorý poskytujete komukoľvek. Secret nikdy neschovávajte za NEXT_PUBLIC_, bez ohľadu na to, čo naznačuje názov.

Preto tiež nemožno takto dodatočne nakonfigurovať vopred zostavený image. Ak bol image zostavený inde a hodnoty boli skompilované priamo doň, nastavenie premenných v službe nič nezmení — reťazce už sú súčasťou bundlu.

3. Úvodzovky

Hodnoty so špeciálnymi znakmi sa môžu zmeniť spôsobmi, ktoré vedú k nejasným chybám namiesto jednoznačný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 spôsobujú napríklad tieto znaky: # (komentár), $ (expanzia), medzery (rozdelenie argumentov), ! (expanzia histórie v interaktívnom bash) a nové riadky — ktoré sa objavujú presne v jednom bežnom prípade, pri private keys.

Najväčší problém predstavujú viacriadkové hodnoty. PEM key vložený do poľa pre jeden riadok príde bez nových riadkov a spôsobí chybu pri parsovaní, ktorá vôbec nespomína nové riadky. Zakódujte ho pomocou Base64 a dekódujte ho v aplikácii:

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

4. Nespustili ste reštart

Proces načíta premenné prostredia pri svojom spustení. Ich zmena ovplyvní ďalší proces, nie ten, ktorý práve beží.

Väčšina platforiem to rieši automatickým redeployom po zmene konfigurácie, no nie všetky. Navyše čiastočná zmena — nastavíte tri premenné, spustíte redeploy a potom nastavíte štvrtú — môže zanechať jednu premennú bez aktualizácie.

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

Kontrola, ktorá to jednoznačne objasní: prečítajte premennú priamo z bežiaceho kontajnera, nie z dashboardu.

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

Ak sa nachádza vo výstupe a vaša aplikácia stále hlási undefined, problém je vo vašom kóde. Ak sa vo výstupe nenachádza, problém je v konfigurácii. Tento jediný príkaz rozdelí priestor možností na polovicu.

5. Nesprávny scope

Premenné majú zvyčajne scope — na úrovni služby, prostredia alebo projektu. Premenná nastavená v produkcii nie je viditeľná v preview prostredí. Rovnako nie je viditeľná premenná nastavená v inej službe v rámci toho istého projektu.

Toto je zvyčajná príčina situácie, keď niečo funguje na jednom mieste, ale na inom nie, hoci kód je rovnaký.

Poradie 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čnite krokom 1. Nejasný problém sa tým zmení na jeden z dvoch jednoznačných problémov.

Špecificky o secrets

Bez ohľadu na platformu sa oplatí osvojiť si dva návyky.

Označujte secrets ako secrets. V Dockup sa premenná označená ako secret maskuje vo výpisoch a API odpovediach — dockup env list zobrazí ******** namiesto hodnoty. Je to dôležitejšie, než sa môže zdať, pretože najčastejšie credential neunikne v dôsledku útoku, ale cez screenshot, support ticket alebo riadok v logu.

Nedávajte ich do build argumentov ani do frontendových bundlov. Oboje si môže prečítať každý, kto získa artefakt. Praktické pravidlo: ak skončí v súbore, ktorý distribuujete, už to nie je secret.

Často kladené otázky

Prečo je moja premenná prostredia počas buildu undefined? Pretože build a runtime sú oddelené prostredia. Runtime premenné počas zostavovania image neexistujú. Ak hodnotu počas buildu skutočne potrebujete, použite build argument — nikdy však secret.

Prečo môj frontend nevidí premennú? Bundlery nahrádzajú hodnotu počas buildu a sprístupňujú iba názvy s prefixom — VITE_, NEXT_PUBLIC_. Zmena premennej vyžaduje nový build a všetko takto sprístupnené je verejne čitateľné.

Musím po zmene premennej vykonať reštart? Áno. Bežiaci proces už svoje prostredie načítal. Väčšina platforiem po zmene automaticky vykoná redeploy; overte to pomocou printenv priamo v kontajneri namiesto toho, aby ste sa spoliehali na dashboard.

Ako odovzdám viacriadkovú hodnotu, napríklad private key? Zakódujte ju pomocou Base64, nastavte zakódovaný reťazec a dekódujte ho v aplikácii. Jednoriadkové polia pre premenné prostredia odstraňujú nové riadky a spôsobujú chyby pri parsovaní, ktoré nové riadky nespomínajú.