Varijable okruženja ne dolaze do containera
Varijable okruženja koje ne rade u containeru obično ne rade iz jednog od pet razloga: build time nasuprot runtimeu, bundlanje frontenda, navodnici, trenutak ponovnog pokretanja ili pogrešan opseg. Provjerite ih tim redoslijedom.
Postavili ste varijablu. Dashboard je prikazuje. Aplikacija kaže da je undefined. Varijable okruženja koje ne rade u containeru jedan su od najčešćih problema s konfiguracijom pri hostanju aplikacija i gotovo uvijek je riječ o jednoj od pet konkretnih stvari.
Ovdje su navedene redoslijedom kojim ćete najbrže pronaći problem.
1. Build time i runtime dva su različita svijeta
Ovo uzrokuje više takvih problema nego preostala četiri razloga zajedno, a ljudima je obično i najmanje intuitivno.
Varijable postavljene na vašem servisu postoje kada se container pokrene. Sve što radi vaš Dockerfile događa se ranije, u zasebnom okruženju. Korak RUN ne može vidjeti runtime varijablu jer u tom trenutku runtime ne postoji.
# 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"]
Ako vam je vrijednost doista potrebna tijekom builda, mora se proslijediti kao build argument — što je drugačiji mehanizam s drugačijim sigurnosnim svojstvima:
ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"
Nikad na ovaj način ne prosljeđujte tajnu. Build argumenti bilježe se u povijesti layera imagea. Svatko tko može preuzeti image može ih pročitati.
2. Varijable frontenda ugrađuju se u bundle, a ne čitaju se
Ako vaš frontend u produkciji prikazuje undefined, gotovo je sigurno riječ o ovome.
Preglednik nema environment. Kada napišete import.meta.env.VITE_API_URL ili process.env.NEXT_PUBLIC_API_URL, bundler zamjenjuje izraz konkretnim stringom tijekom builda. U pregledniku se ništa ne dohvaća — vrijednost je već ugrađena u kompajlirani kod.
Tri posljedice često iznenade korisnike:
- Promjena varijable ne znači ništa dok ponovno ne napravite build. Stara vrijednost nalazi se unutar JavaScript datoteke.
- Prefiks je obavezan. Vite izlaže samo
VITE_, a Next.js samoNEXT_PUBLIC_. Varijabla bez prefiksa namjerno se ne izlaže. - Sve što se izloži na ovaj način javno je. Nalazi se u datoteci koju poslužujete bilo kome. Nikad ne stavljajte tajnu iza
NEXT_PUBLIC_, bez obzira na to što naziv možda sugerira.
Zato se unaprijed izgrađeni image ne može naknadno konfigurirati na ovaj način. Ako je image izgrađen negdje drugdje, s vrijednostima ugrađenima u kod, postavljanje varijabli na servisu ne mijenja ništa — stringovi su već u bundlu.
3. Navodnici
Vrijednosti s posebnim znakovima mogu se izmijeniti na načine koji proizvode zbunjujuće, a ne očite pogreške.
# 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
Znakovi koji uzrokuju ovaj problem: # (komentar), $ (proširivanje), razmaci (razdvajanje argumenata), ! (proširivanje povijesti u interaktivnom bashu) i novi redovi — koji se pojavljuju upravo u jednom uobičajenom slučaju: privatnim ključevima.
Vrijednosti u više redaka najčešći su uzrok problema. PEM ključ zalijepljen u polje za jedan red stiže bez novih redova i proizvodi pogrešku parsiranja koja uopće ne spominje nove redove. Kodirajte ga u Base64 i dekodirajte u aplikaciji:
dockup env set "PRIVATE_KEY_B64=$(base64 -i key.pem)" my-project/my-api
4. Niste ponovno pokrenuli aplikaciju
Proces čita varijable okruženja kada se pokrene. Promjena varijabli utječe na sljedeći proces, a ne na onaj koji trenutačno radi.
Većina platformi to rješava automatskim redeployem kada se promijeni konfiguracija, ali ne sve. Osim toga, djelomična promjena — postavite tri varijable, napravite redeploy, pa postavite četvrtu — može ostaviti jednu varijablu neprimijenjenom.
dockup env list my-project/my-api --json # what is configured
dockup restart my-project/my-api # make the process re-read it
Provjera koja daje konačan odgovor: pročitajte varijablu iz pokrenutog containera, a ne s dashboarda.
dockup exec "printenv | sort" my-project/my-api
Ako se nalazi u tom ispisu, a vaša aplikacija i dalje prikazuje undefined, problem je u vašem kodu. Ako je nema u ispisu, problem je u konfiguraciji. Ta jedna naredba prepolovljuje prostor za traženje problema.
5. Pogrešan opseg
Varijable obično imaju opseg — prema servisu, environmentu ili projektu. Varijabla postavljena u produkciji nije vidljiva u preview environmentu. Jednako tako, varijabla postavljena na drugom servisu u istom projektu nije vidljiva ni ovdje.
To je uobičajen uzrok situacije u kojoj nešto radi na jednom mjestu, a na drugom ne radi, iako je kod identičan.
Redoslijed dijagnostike
# 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
Uvijek počnite s prvim korakom. Time se nejasan problem pretvara u jedan od dva jasna problema.
Posebno o tajnama
Bez obzira na platformu, vrijedi usvojiti dvije navike.
Označite tajne kao tajne. Na Dockupu se varijabla označena kao tajna maskira u popisima i API odgovorima — dockup env list prikazuje ********, a ne vrijednost. To je važnije nego što se možda čini jer najčešći način curenja vjerodajnice nije napad; to su snimka zaslona, ticket podršci ili redak u logu.
Držite ih podalje od build argumenata i frontend bundlova. Oboje može pročitati svatko tko dođe do artefakta. Praktično pravilo: ako završi u datoteci koju distribuirate, više nije tajna.
Često postavljana pitanja
Zašto je moja varijabla okruženja nedefinirana tijekom builda? Zato što su build i runtime zasebna okruženja. Runtime varijable ne postoje dok se image izrađuje. Upotrijebite build argument ako vam je vrijednost doista potrebna tijekom builda — ali nikad ne koristite tajnu.
Zašto moj frontend ne vidi varijablu?
Bundleri zamjenjuju vrijednost tijekom builda i izlažu samo nazive s prefiksom — VITE_, NEXT_PUBLIC_. Promjena varijable zahtijeva novi build, a sve što se izloži na ovaj način javno je čitljivo.
Moram li ponovno pokrenuti aplikaciju nakon promjene varijable?
Da. Pokrenuti proces već je pročitao svoje okruženje. Većina platformi automatski radi redeploy nakon promjene; provjerite pomoću printenv unutar containera umjesto da se oslanjate na dashboard.
Kako proslijediti vrijednost u više redaka, poput privatnog ključa? Kodirajte je u Base64, postavite kodirani string i dekodirajte ga u aplikaciji. Polja za varijable u jednom retku uklanjaju nove redove i proizvode pogreške parsiranja koje ne spominju nove redove.
