Miljøvariabler når ikke frem til containeren
Miljøvariabler, der ikke virker i en container, skyldes som regel én af fem ting: build-tid kontra runtime, frontend-bundling, citationstegn, genstartstidspunkt eller forkert scope. Kontrollér dem i denne rækkefølge.
Du har angivet variablen. Dashboardet viser den. Applikationen siger, at den er undefined. Miljøvariabler, der ikke virker i en container, er en af de mest almindelige konfigurationsfejl ved hosting af applikationer, og det skyldes næsten altid én af fem specifikke ting.
De er angivet i den rækkefølge, der hurtigst finder problemet.
1. Build-tid og runtime er to forskellige verdener
Dette er årsag til flere af disse problemer end de fire andre tilsammen, og det er den forklaring, folk har sværest ved at forstå intuitivt.
Variabler, du angiver på din service, findes, når containeren kører. Alt, hvad din Dockerfile gør, sker tidligere og i et separat miljø. Et RUN-trin kan ikke se en runtime-variabel, fordi der på det tidspunkt ikke findes nogen 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"]
Hvis du reelt har brug for en værdi under buildet, skal den sendes som et build-argument — hvilket er en anden mekanisme med andre sikkerhedsegenskaber:
ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"
Send aldrig en secret på denne måde. Build-argumenter gemmes i image-lagets historik. Alle, der kan hente imaget, kan læse dem.
2. Frontend-variabler bygges ind – de læses ikke
Hvis din frontend siger undefined i produktion, er dette næsten helt sikkert årsagen.
En browser har ikke noget miljø. Når du skriver import.meta.env.VITE_API_URL eller process.env.NEXT_PUBLIC_API_URL, indsætter bundleren den bogstavelige streng under buildet. Der sker ikke noget opslag i browseren — værdien blev kompileret ind.
Tre konsekvenser, der ofte overrasker folk:
- Det hjælper ikke at ændre variablen, før du bygger igen. Den gamle værdi ligger inde i JavaScript-filen.
- Præfikset er obligatorisk. Vite eksponerer kun
VITE_, og Next.js eksponerer kunNEXT_PUBLIC_. En variabel uden præfikset holdes bevidst skjult. - Alt, der eksponeres på denne måde, er offentligt. Det ligger i en fil, du sender til alle. Læg aldrig en secret bag
NEXT_PUBLIC_, uanset hvad navnet antyder.
Det er også derfor, at et prebuilt image ikke kan konfigureres på denne måde efterfølgende. Hvis imaget blev bygget et andet sted med værdierne indkompileret, ændrer det ikke noget at angive variabler på servicen — strengene findes allerede i bundlen.
3. Citationstegn
Værdier med specialtegn bliver ændret på måder, der giver forvirrende fejl i stedet for tydelige fejlmeddelelser.
# 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
Tegn, der giver problemer: # (kommentar), $ (substitution), mellemrum (opdeling af argumenter), ! (historikudvidelse i interaktiv bash) og linjeskift — som forekommer i netop ét almindeligt tilfælde: private keys.
Værdier over flere linjer er det værste eksempel. En PEM-key, der indsættes i et felt med én linje, ankommer uden sine linjeskift og giver en parse-fejl, der ikke siger noget om linjeskift. Base64-enkod den, og dekod den i applikationen:
dockup env set "PRIVATE_KEY_B64=$(base64 -i key.pem)" my-project/my-api
4. Du genstartede ikke
Miljøvariabler læses af en proces, når den starter. Ændringer påvirker den næste proces, ikke den, der kører i øjeblikket.
De fleste platforme håndterer dette ved automatisk at lave en ny deployment, når konfigurationen ændres, men det gælder ikke alle, og en delvis ændring — angiv tre variabler, lav en ny deployment, og angiv derefter en fjerde — efterlader én variabel ude.
dockup env list my-project/my-api --json # what is configured
dockup restart my-project/my-api # make the process re-read it
Den kontrol, der afgør sagen: Læs variablen fra den kørende container, ikke fra dashboardet.
dockup exec "printenv | sort" my-project/my-api
Hvis den findes i outputtet, men din app stadig siger undefined, ligger problemet i din kode. Hvis den ikke findes i outputtet, ligger problemet i konfigurationen. Den ene kommando halverer søgeområdet.
5. Forkert scope
Variabler er normalt afgrænset til en service, et miljø eller et projekt. En variabel, der er angivet i produktion, er ikke synlig i et preview-miljø. En variabel, der er angivet på en anden service i det samme projekt, er heller ikke synlig.
Dette er den sædvanlige årsag, når noget virker ét sted, men ikke et andet, selv om koden er identisk.
Den diagnostiske rækkefølge
# 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
Start altid med trin 1. Det omdanner et uklart problem til ét af to entydige problemer.
Specifikt om secrets
Der er to vaner, der er værd at indføre uanset platform.
Markér secrets som secrets. På Dockup bliver en variabel, der er markeret som secret, maskeret i lister og API-svar — dockup env list viser ******** i stedet for værdien. Det er vigtigere, end det måske lyder, fordi den mest almindelige måde, en credential lækker på, ikke er et angreb; det er et screenshot, en supportsag eller en linje i en log.
Hold dem ude af build-argumenter og frontend-bundler. Begge dele kan læses af alle, der får fat i artefaktet. Tommelfingerreglen er: Hvis det ender i en fil, du distribuerer, er det ikke længere en secret.
Ofte stillede spørgsmål
Hvorfor er min miljøvariabel undefined under buildet? Fordi build og runtime er separate miljøer. Runtime-variabler findes ikke, mens imaget bliver bygget. Brug et build-argument, hvis du virkelig har brug for en værdi under buildet — og aldrig en secret.
Hvorfor kan min frontend ikke se variablen?
Bundlere indsætter værdien under buildet og eksponerer kun navne med præfiks — VITE_, NEXT_PUBLIC_. Hvis du ændrer variablen, kræver det et nyt build, og alt, der eksponeres på denne måde, kan læses offentligt.
Skal jeg genstarte efter at have ændret en variabel?
Ja. En kørende proces har allerede læst sit miljø. De fleste platforme laver automatisk en ny deployment ved ændringer; kontrollér med printenv inde i containeren i stedet for at stole på dashboardet.
Hvordan sender jeg en værdi over flere linjer, f.eks. en private key? Base64-enkod den, angiv den enkodede streng, og dekod den i applikationen. Felter til miljøvariabler med én linje fjerner linjeskift og giver parse-fejl, der ikke nævner linjeskift.
