Variabilele de mediu nu ajung în container
Variabilele de mediu care nu funcționează într-un container eșuează de obicei din unul dintre cele cinci motive: build time versus runtime, bundling frontend, ghilimele, momentul repornirii sau scope-ul greșit. Verifică-le în această ordine.
Setezi variabila. Dashboard-ul o afișează. Aplicația spune că este undefined. Variabilele de mediu care nu funcționează într-un container reprezintă una dintre cele mai frecvente erori de configurare în hostingul aplicațiilor și aproape întotdeauna are una dintre cele cinci cauze specifice.
Acestea sunt prezentate în ordinea în care problema poate fi identificată cel mai rapid.
1. Build time și runtime sunt lumi diferite
Această cauză explică mai multe astfel de probleme decât celelalte patru la un loc și este cea mai puțin intuitivă.
Variabilele setate pentru serviciul tău există atunci când containerul rulează. Tot ce face Dockerfile-ul are loc mai devreme, într-un mediu separat. Un pas RUN nu poate vedea o variabilă de runtime, deoarece în acel moment nu există încă runtime.
# 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"]
Dacă ai într-adevăr nevoie de o valoare în timpul build-ului, aceasta trebuie transmisă ca argument de build — un mecanism diferit, cu proprietăți de securitate diferite:
ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"
Nu transmite niciodată un secret în acest fel. Argumentele de build sunt înregistrate în istoricul layer-elor imaginii. Oricine poate face pull la imagine le poate citi.
2. Variabilele frontend sunt incluse în bundle, nu citite
Dacă frontend-ul tău afișează undefined în producție, acesta este aproape sigur motivul.
Un browser nu are environment. Când scrii import.meta.env.VITE_API_URL sau process.env.NEXT_PUBLIC_API_URL, bundler-ul înlocuiește valoarea literală în timpul build-ului. În browser nu are loc nicio căutare — valoarea a fost compilată în bundle.
Trei consecințe îi surprind pe mulți:
- Schimbarea variabilei nu are niciun efect până când nu faci rebuild. Valoarea veche se află în fișierul JavaScript.
- Prefixul este obligatoriu. Vite expune doar
VITE_, iar Next.js expune doarNEXT_PUBLIC_. O variabilă fără prefix este ascunsă intenționat. - Tot ce expui în acest fel este public. Se află într-un fișier pe care îl livrezi oricui. Nu pune niciodată un secret în spatele prefixului
NEXT_PUBLIC_, indiferent de ceea ce sugerează numele.
Acesta este și motivul pentru care o imagine preconstruită nu poate fi configurată astfel ulterior. Dacă imaginea a fost construită în altă parte, cu valorile compilate în bundle, setarea variabilelor pentru serviciu nu schimbă nimic — șirurile sunt deja în bundle.
3. Ghilimelele
Valorile cu caractere speciale sunt modificate în moduri care produc erori confuze, nu erori evidente.
# 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
Caracterele care cauzează astfel de probleme sunt: # (comentariu), $ (expansiune), spațiile (separarea argumentelor), ! (expansiunea istoricului în bash interactiv) și liniile noi — care apar într-un caz foarte frecvent: cheile private.
Valorile pe mai multe linii creează cele mai multe probleme. O cheie PEM lipită într-un câmp cu o singură linie ajunge fără liniile noi și produce o eroare de parsare care nu spune nimic despre acestea. Codific-o în Base64 și decodeaz-o în aplicație:
dockup env set "PRIVATE_KEY_B64=$(base64 -i key.pem)" my-project/my-api
4. Nu ai repornit aplicația
Variabilele de mediu sunt citite de un proces atunci când acesta pornește. Modificarea lor afectează următorul proces, nu procesul care rulează în prezent.
Majoritatea platformelor rezolvă acest lucru printr-un redeploy automat atunci când se schimbă configurația, dar nu toate fac asta, iar o modificare parțială — setezi trei variabile, faci redeploy, apoi setezi o a patra — lasă una dintre ele în urmă.
dockup env list my-project/my-api --json # what is configured
dockup restart my-project/my-api # make the process re-read it
Verificarea decisivă: citește variabila din interiorul containerului care rulează, nu din dashboard.
dockup exec "printenv | sort" my-project/my-api
Dacă apare în acel output, iar aplicația ta spune în continuare undefined, problema este în cod. Dacă nu apare în output, problema este în configurație. Acea singură comandă înjumătățește spațiul de căutare.
5. Scope greșit
Variabilele au de obicei un scope — pentru un serviciu, un environment sau un proiect. O variabilă setată în producție nu este vizibilă într-un preview environment. Nici una setată pentru un alt serviciu din același proiect nu este vizibilă.
Aceasta este cauza obișnuită atunci când ceva funcționează într-un loc, dar nu în altul, deși codul este identic.
Ordinea diagnosticării
# 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
Începe de fiecare dată cu pasul 1. Acesta transformă o problemă ambiguă într-una dintre două probleme clare.
Despre secrete, în mod specific
Merită să adopți două obiceiuri, indiferent de platformă.
Marchează secretele ca secrete. În Dockup, o variabilă marcată ca secret este ascunsă în listări și în răspunsurile API — dockup env list afișează ******** în locul valorii. Acest lucru contează mai mult decât pare, deoarece cea mai frecventă modalitate prin care secretele ajung să fie divulgate nu este un atac; este o captură de ecran, un tichet trimis către support sau o linie din loguri.
Păstrează-le în afara argumentelor de build și a bundle-urilor frontend. Ambele pot fi citite de oricine obține artefactul. Regula generală: dacă ajunge într-un fișier pe care îl distribui, nu mai este un secret.
Întrebări frecvente
De ce variabila mea de mediu este undefined în timpul build-ului?
Deoarece build-ul și runtime-ul sunt medii separate. Variabilele de runtime nu există cât timp imaginea este construită. Folosește un argument de build dacă ai cu adevărat nevoie de o valoare în timpul build-ului — și niciodată un secret.
De ce frontend-ul meu nu vede variabila?
Bundler-ele înlocuiesc valoarea în timpul build-ului și expun doar numele cu prefix — VITE_, NEXT_PUBLIC_. Schimbarea variabilei necesită un rebuild, iar orice valoare expusă astfel poate fi citită public.
Trebuie să repornesc aplicația după ce schimb o variabilă?
Da. Un proces care rulează și-a citit deja environment-ul. Majoritatea platformelor fac automat redeploy la modificare; verifică folosind printenv în interiorul containerului, în loc să te bazezi pe dashboard.
Cum transmit o valoare pe mai multe linii, cum ar fi o cheie privată? Codific-o în Base64, setează șirul codificat și decodeaz-o în aplicație. Câmpurile de environment cu o singură linie elimină liniile noi și produc erori de parsare care nu menționează liniile noi.
