Günlük diziniDockup / saha notu
Note / env-vars-not-reaching-container

Ortam Değişkenleri Container'a Ulaşmıyor

Bir container'da ortam değişkenleri genellikle beş nedenden biri yüzünden çalışmaz: build time ve runtime farkı, frontend bundling, tırnak kullanımı, yeniden başlatma zamanlaması veya yanlış scope. Sorunu bu sırayla kontrol edin.

Değişkeni ayarladınız. Dashboard'da görünüyor. Uygulama ise undefined diyor. Container'da çalışmayan ortam değişkenleri, uygulama hosting'inde en yaygın yapılandırma sorunlarından biridir ve neredeyse her zaman beş belirli nedenden birine dayanır.

Bunlar, sorunu en hızlı bulmanızı sağlayacak sırayla listelenmiştir.

1. Build time ve runtime farklı dünyalardır

Bu sorun, diğer dört nedenin toplamından daha fazla vakaya yol açar ve insanların en zor sezdiği konudur.

Servisinizde ayarladığınız değişkenler container çalışırken kullanılabilir. Dockerfile'ınızın yaptığı her şey ise daha önce, ayrı bir ortamda gerçekleşir. Bir RUN adımı runtime değişkenini göremez; çünkü o anda henüz runtime yoktur.

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

Build sırasında gerçekten bir değere ihtiyacınız varsa bunu build argument olarak aktarmanız gerekir — ancak bu, farklı güvenlik özelliklerine sahip, farklı bir mekanizmadır:

ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"

Bir secret'ı bu şekilde asla aktarmayın. Build argument'ları image'ın layer geçmişine kaydedilir. Image'ı çekebilen herkes bunları okuyabilir.

2. Frontend değişkenleri okunmaz, içine gömülür

Frontend'iniz production'da undefined diyorsa, bunun nedeni neredeyse kesinlikle budur.

Bir browser'ın environment'ı yoktur. import.meta.env.VITE_API_URL veya process.env.NEXT_PUBLIC_API_URL yazdığınızda bundler, build time sırasında literal string'i yerine koyar. Browser'da herhangi bir lookup gerçekleşmez — değer derlenerek kodun içine gömülmüştür.

İnsanların sıkça gözden kaçırdığı üç sonuç vardır:

  • Değişkeni değiştirmek, yeniden build edene kadar hiçbir şey yapmaz. Eski değer JavaScript dosyasının içindedir.
  • Prefix zorunludur. Vite yalnızca VITE_ ile başlayan değişkenleri, Next.js ise yalnızca NEXT_PUBLIC_ ile başlayan değişkenleri açığa çıkarır. Prefix içermeyen bir değişken bilerek gizli tutulur.
  • Bu şekilde açığa çıkarılan her şey public'tir. Herkese servis ettiğiniz bir dosyanın içinde yer alır. Adı neyi ima ederse etsin, bir secret'ı asla NEXT_PUBLIC_ arkasına koymayın.

Önceden build edilmiş bir image'ın sonradan bu şekilde yapılandırılamamasının nedeni de budur. Image başka bir yerde, değerler içine derlenmiş olarak build edildiyse serviste değişken ayarlamak hiçbir şeyi değiştirmez — string'ler zaten bundle'ın içindedir.

3. Tırnak kullanımı

Özel karakterler içeren değerler, belirgin hatalar yerine kafa karıştırıcı hatalar üretecek şekilde bozulabilir.

# 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

Buna yol açan karakterler şunlardır: # (yorum), $ (genişletme), boşluklar (argument'ların bölünmesi), ! (etkileşimli bash'te history expansion) ve tam olarak tek bir yaygın durumda görülen satır sonları: private key'lerde.

Birden çok satır içeren değerler en sorunlu olanlardır. PEM key'i tek satırlık bir alana yapıştırdığınızda satır sonları silinir ve new line'larla ilgisi olmayan bir parse error oluşur. Değeri Base64 ile encode edin ve uygulamada decode edin:

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

4. Yeniden başlatmadınız

Ortam değişkenleri bir process tarafından başlatılırken okunur. Bunları değiştirmek, o anda çalışan process'i değil, bir sonraki process'i etkiler.

Çoğu platform, yapılandırma değiştiğinde otomatik olarak yeniden deploy ederek bunu yönetir; ancak hepsi böyle davranmaz. Ayrıca kısmi bir değişiklik — üç değişkeni ayarlayıp yeniden deploy etmek, ardından dördüncüyü ayarlamak — bir değişkenin geride kalmasına neden olur.

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

Sonucu kesinleştiren kontrol şudur: değişkeni dashboard'dan değil, çalışan container'ın içinden okuyun.

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

Değişken bu çıktıda yer alıyor ve uygulamanız hâlâ undefined diyorsa sorun kodunuzdadır. Çıktıda yer almıyorsa sorun yapılandırmadadır. Bu tek komut, arama alanını ikiye böler.

5. Yanlış scope

Değişkenler genellikle bir service'e, environment'a veya project'e scope edilir. Production'da ayarlanan bir değişken preview environment'ında görünmez. Aynı project içindeki farklı bir service üzerinde ayarlanan değişken de görünmez.

Aynı kod bir yerde çalışıp başka bir yerde çalışmadığında, bunun en yaygın nedeni budur.

Teşhis sırası

# 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

Her seferinde önce 1. adımla başlayın. Belirsiz bir sorunu, net biçimde tanımlanabilen iki sorundan birine dönüştürür.

Özellikle secret'lar

Platformdan bağımsız olarak benimsemeye değer iki alışkanlık vardır.

Secret'ları secret olarak işaretleyin. Dockup'ta secret olarak işaretlenen bir değişken, listelerde ve API yanıtlarında maskelenir — dockup env list, değer yerine ******** gösterir. Bu, göründüğünden daha önemlidir; çünkü bir credential'ın sızmasının en yaygın yolu saldırı değil, bir ekran görüntüsü, destek talebi veya log satırıdır.

Bunları build argument'larından ve frontend bundle'larından uzak tutun. Her ikisi de artefact'ı elde eden herkes tarafından okunabilir. Pratik kural şudur: dağıttığınız bir dosyanın içinde yer alıyorsa artık secret değildir.

Sık sorulan sorular

Ortam değişkenim build time sırasında neden undefined oluyor? Çünkü build ve runtime ayrı ortamlardır. Image build edilirken runtime değişkenleri mevcut değildir. Build sırasında gerçekten bir değere ihtiyacınız varsa build argument kullanın — ancak asla bir secret kullanmayın.

Frontend'im değişkeni neden görmüyor? Bundler'lar değeri build time sırasında yerine koyar ve yalnızca prefix içeren adları açığa çıkarır — VITE_, NEXT_PUBLIC_. Değişkeni değiştirmek yeniden build etmeyi gerektirir ve bu şekilde açığa çıkarılan her şey public olarak okunabilir.

Bir değişkeni değiştirdikten sonra yeniden başlatmam gerekir mi? Evet. Çalışan bir process environment'ını zaten okumuştur. Çoğu platform değişiklik sonrasında otomatik olarak yeniden deploy eder; yine de dashboard'a güvenmek yerine container'ın içinden printenv ile doğrulayın.

Private key gibi birden çok satır içeren değeri nasıl aktarırım? Base64 ile encode edin, encode edilmiş string'i ayarlayın ve uygulamada decode edin. Tek satırlık environment alanları satır sonlarını siler ve new line'lardan bahsetmeyen parse error'lar üretir.