Päiväkirjan hakemistoDockup / kenttämuistio
Note / env-vars-not-reaching-container

Ympäristömuuttujat eivät välity konttiin

Kontissa toimimattomat ympäristömuuttujat johtuvat yleensä yhdestä viidestä syystä: build-vaiheen ja ajonaikaisen ympäristön erosta, frontendin bundlauksesta, lainausmerkeistä, uudelleenkäynnistyksen ajoituksesta tai väärästä scopesta. Tarkista syyt tässä järjestyksessä.

Asetit muuttujan. Hallintapaneeli näyttää sen. Sovellus ilmoittaa, että se on undefined. Kontissa toimimattomat ympäristömuuttujat ovat yksi sovellusten hostauksen yleisimmistä konfiguraatio-ongelmista, ja lähes aina taustalla on yksi viidestä tietystä syystä.

Ne on listattu tässä siinä järjestyksessä, jolla ongelma löytyy nopeimmin.

1. Build-aika ja ajoaika ovat eri maailmoja

Tämä aiheuttaa enemmän tällaisia ongelmia kuin neljä muuta syytä yhteensä, ja juuri tätä on yleensä vaikeinta hahmottaa.

Palvelulle asetetut muuttujat ovat olemassa, kun kontti suoritetaan. Kaikki Dockerfilen tekemä tapahtuu aiemmin, erillisessä ympäristössä. RUN-vaihe ei näe ajonaikaista muuttujaa, koska kyseisellä hetkellä ajoaikaa ei vielä ole.

# 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"]

Jos tarvitset arvon aidosti buildin aikana, se on välitettävä build-argumenttina — kyseessä on eri mekanismi, jolla on erilaiset tietoturvaominaisuudet:

ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"

Älä koskaan välitä salaisuutta tällä tavalla. Build-argumentit tallennetaan imagen layer-historiaan. Kuka tahansa, joka voi ladata imagen, voi lukea ne.

2. Frontend-muuttujat leivotaan mukaan, niitä ei lueta

Jos frontendisi ilmoittaa tuotannossa undefined, tämä on lähes varmasti syy.

Selaimella ei ole ympäristöä. Kun kirjoitat import.meta.env.VITE_API_URL tai process.env.NEXT_PUBLIC_API_URL, bundleri korvaa sen kirjaimellisella merkkijonolla build-aikana. Selaimessa ei tehdä hakua — arvo on käännetty suoraan mukaan.

Tällä on kolme seurausta, jotka aiheuttavat helposti ongelmia:

  • Muuttujan vaihtaminen ei vaikuta mihinkään ennen uutta buildia. Vanha arvo on JavaScript-tiedostossa.
  • Prefix on pakollinen. Vite välittää vain VITE_-alkuiset muuttujat ja Next.js vain NEXT_PUBLIC_-alkuiset muuttujat. Ilman prefixiä oleva muuttuja jätetään tarkoituksella välittämättä.
  • Kaikki tällä tavalla julkaistava on julkista. Arvo on tiedostossa, jonka tarjoat kenelle tahansa. Älä koskaan sijoita salaisuutta NEXT_PUBLIC_-muuttujan taakse nimestä huolimatta.

Tästä syystä valmiiksi rakennettua imagea ei voi konfiguroida tällä tavalla jälkikäteen. Jos image on rakennettu muualla ja arvot on käännetty siihen mukaan, muuttujien asettaminen palvelulle ei muuta mitään — merkkijonot ovat jo bundlessa.

3. Lainausmerkit

Erikoismerkkejä sisältävät arvot voivat muuttua odottamattomilla tavoilla ja aiheuttaa hämmentäviä virheitä selkeiden virheilmoitusten sijaan.

# 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

Tällaisia ongelmia aiheuttavat merkit ovat # (kommentti), $ (laajennus), välilyönnit (argumenttien pilkkominen), ! (historian laajennus interaktiivisessa bashissa) sekä rivinvaihdot — joita esiintyy juuri yhdessä yleisessä tapauksessa: private key -avaimissa.

Moniriviset arvot aiheuttavat eniten ongelmia. PEM-avain yhteen rivikenttään liitettynä menettää rivinvaihtonsa ja tuottaa jäsentämisvirheen, jossa ei mainita rivinvaihtoja lainkaan. Koodaa arvo Base64-muotoon ja pura se sovelluksessa:

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

4. Et käynnistänyt prosessia uudelleen

Prosessi lukee ympäristömuuttujat käynnistyessään. Muutokset vaikuttavat seuraavaan prosessiin, eivät parhaillaan käynnissä olevaan prosessiin.

Useimmat alustat hoitavat tämän ottamalla automaattisesti uuden deployn konfiguraation muuttuessa, mutta kaikki eivät toimi näin. Lisäksi osittainen muutos — asetat kolme muuttujaa, teet uuden deployn ja asetat neljännen — jättää yhden muuttujan vanhaan prosessiin.

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

Ratkaiseva tarkistus on lukea muuttuja käynnissä olevan kontin sisältä, ei hallintapaneelista.

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

Jos muuttuja näkyy tulosteessa mutta sovelluksesi ilmoittaa edelleen undefined, ongelma on koodissasi. Jos muuttujaa ei näy tulosteessa, ongelma on konfiguraatiossa. Tämä yksi komento puolittaa tutkittavan ongelma-avaruuden.

5. Väärä scope

Muuttujat on yleensä rajattu tiettyyn palveluun, ympäristöön tai projektiin. Tuotantoon asetettu muuttuja ei näy preview-ympäristössä. Eikä samassa projektissa toiselle palvelulle asetettu muuttuja näy tässä palvelussa.

Tämä on tavallisin syy tilanteessa, jossa jokin toimii yhdessä paikassa mutta ei toisessa, vaikka koodi on identtinen.

Vianmääritysjärjestys

# 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

Aloita aina kohdasta 1. Se muuttaa epämääräisen ongelman yhdeksi kahdesta yksiselitteisestä ongelmasta.

Erityisesti salaisuuksista

Kaksi tapaa kannattaa omaksua alustasta riippumatta.

Merkitse salaisuudet salaisuuksiksi. Dockupissa secret-merkinnällä varustettu muuttuja peitetään listauksissa ja API-vastauksissa — dockup env list näyttää arvon sijaan ********. Tämä on tärkeämpää kuin miltä se kuulostaa, koska yleisin tapa tunnistetiedon vuotamiseen ei ole hyökkäys, vaan kuvakaappaus, tukipyyntö tai lokirivi.

Pidä ne poissa build-argumenteista ja frontend-bundleista. Kuka tahansa artefaktin saanut voi lukea molemmat. Nyrkkisääntö: jos arvo päätyy jakamaasi tiedostoon, se ei enää ole salaisuus.

Usein kysytyt kysymykset

Miksi ympäristömuuttujani on build-aikana määrittelemätön? Koska build- ja ajoaikainen ympäristö ovat erillisiä. Ajonaikaisia muuttujia ei ole olemassa imagen buildin aikana. Käytä build-argumenttia, jos todella tarvitset arvon buildin aikana — mutta älä koskaan välitä salaisuutta sitä kautta.

Miksi frontendini ei näe muuttujaa? Bundlerit korvaavat arvon build-aikana ja julkaisevat vain prefixillä alkavat nimet — VITE_, NEXT_PUBLIC_. Muuttujan vaihtaminen edellyttää uutta buildia, ja kaikki tällä tavalla julkaistu on julkisesti luettavissa.

Pitääkö prosessi käynnistää uudelleen muuttujan vaihtamisen jälkeen? Kyllä. Käynnissä oleva prosessi on jo lukenut ympäristönsä. Useimmat alustat tekevät muutoksen yhteydessä automaattisesti uuden deployn, mutta varmista asia lukemalla printenv kontin sisältä sen sijaan, että luottaisit hallintapaneeliin.

Miten välitän monirivisen arvon, kuten private key -avaimen? Koodaa se Base64-muotoon, aseta koodattu merkkijono ja pura se sovelluksessa. Yksiriviset ympäristömuuttujakentät poistavat rivinvaihdot ja tuottavat jäsentämisvirheitä, joissa ei mainita rivinvaihtoja.