Açıklanan Ortam Değişkenleri: .env Dosyaları, Sırlar ve Yapılandırma Doğru Yapıldı
Ortam değişkenleri aynı kodun bir dizüstü bilgisayarda, CI’da ve üretimde farklı ayarlarla çalıştırılmasına izin verir. İşte onları test ederken karşılaştığımız sürprizlerle gerçekte nasıl davrandıkları.
- Ortam değişkenleri, bir işlemin ortamından aldığı anahtar/değer ayarlarıdır.
- Bağlantı noktaları ve veritabanı URL’leri gibi yapılandırmaları kodunuzun dışında tutarlar.
- Değerler her zaman dizelerdir, dolayısıyla siz onu ayrıştırmadığınız sürece “yanlış” doğrudur.
- Hiçbir zaman gerçek sırlara sahip
.envdosyaları işlemeyin ve uygulama başlatıldığında gerekli ayarları doğrulayın.
Uygulamanızın bir veritabanı URL’sine ihtiyacı var. Dizüstü bilgisayarınızda yerel bir veritabanıdır, CI’da tek kullanımlıktır ve üretimde yönetilen bir kümedir. Bunlardan herhangi birinin sabit kodlanması, her ortam için kodun değiştirilmesi anlamına gelir. Ortam değişkenleri bunu çözer. Kod DATABASE_URL‘yi okur ve her ortam kendi değerini sağlar.
Bu fikir, dağıtımlar arasında değişen yapılandırmaların ortama ait olduğunu söyleyen On İki Faktörlü Uygulama yönteminin merkezinde yer alır. Aşağıdaki davranışı Windows’ta Python 3.13 ile test ettik. Gösterilen her çıktı bu çalıştırmadan alınmıştır.
Ortam değişkenleri nelerdir?
Çalışan her işlemin, ortamı adı verilen bir dizi adlandırılmış metin değeri vardır. Bilinen örnekler, kabuğa programları nerede bulacağını söyleyen PATH ve HOME veya USERPROFILE‘tür. Kendi uygulamanız APP_PORT, LOG_LEVEL veya DATABASE_URL gibi ayarlar için aynı mekanizmayı kullanabilir.
Ortam değişkenlerini ayarlama
| Kabuk | Bu oturum için | Bir komut için |
|---|---|---|
| Bash / zsh | APP_PORT=8080'i dışa aktar |
APP_PORT=8080 python app.py |
| PowerShell | $env:APP_PORT = "8080" |
Ayarlayın, çalıştırın ve ardından kaldırın |
| Windows cmd’si | APP_PORT=8080'i ayarla |
Yerleşik değil |
Bunlar yalnızca geçerli terminal oturumu için geçerlidir. Bunları kalıcı kılmak için, bunları ~/.bashrc gibi bir kabuk profiline ekleyin veya Windows’ta sistem ortamı ayarlarını veya setx kullanın. Uygulamalar için, bunları sistem genelinde ayarlamak yerine dağıtım zamanında sağlamak genellikle daha iyidir.
Bunları kod halinde okumak
import os
port = os.environ.get("APP_PORT", "8000") # default if missing
print(port) # 8000
db = os.environ["DATABASE_URL_MISSING_DEMO"]
# KeyError: 'DATABASE_URL_MISSING_DEMO'
İsteğe bağlı ayarlar için varsayılan değerle .get() kullanın. Uygulamanın onsuz çalışamayacağı ayarlar için KeyError değerini yükselten köşeli parantezleri kullanın. Diğer diller de benzerdir: Node.js’de process.env.APP_PORT, Java’da System.getenv("APP_PORT") ve Go’da os.Getenv("APP_PORT").
Her şey bir dizedir
Bu her dilden insanı yakalar. Bir bağlantı noktası belirledik ve ardından ona “1” ekledik:
os.environ["APP_PORT"] = "8080"
port = os.environ["APP_PORT"]
print(type(port).__name__, repr(port), port + "1")
# str '8080' 80801
os.environ["APP_PORT"] = 8080
# TypeError: str expected, not int
Değer metin olarak geri geldi ve eklenmesi 8081 değil 80801 sonucunu verdi. int(os.environ["APP_PORT"])‘deki gibi açıkça dönüştürün. Boolean’lar daha kötü:
os.environ["DEBUG"] = "false"
print(bool(os.environ["DEBUG"])) # True
Boş olmayan herhangi bir dize Python’da doğrudur, bu nedenle "false", True oldu. Hata ayıklama modu üretimde açılmış olurdu. Boolean’ları kasıtlı olarak ayrıştırın:
def env_bool(name, default=False):
value = os.environ.get(name)
if value is None:
return default
return value.strip().lower() in {"1", "true", "yes", "on"}
env_bool("DEBUG") # False
env_bool("NOT_SET", default=True) # True
Süreçler onları nasıl miras alır?
Bir alt süreç, üst ortamının kopyasını alır. Bunu görmek için alt Python işlemlerini başlattık:
child sees: 8080 inherited # default: full copy of the parent's environment
child sees: 9000 None # given a custom env: only what we passed
parent sees child var: None # a child's changes never flow back
Bunu üç pratik ders takip ediyor. Dışa aktardığınız değişkenler, yazmadığınız komut dosyaları da dahil olmak üzere (gizler için önemli olan) başlattığınız her program tarafından görülebilir. Özel bir ortamın geçmesi her şeyin yerini alır, bu nedenle çocuğun ihtiyaç duyduğu her şeyi ekleyin. Ve bir komut dosyası ana kabuğunun değişkenlerini değiştiremez; bu nedenle araçlar sizden bir dosyayı çalıştırmak yerine source yapmanızı ister.
.env dosyaları
Birçok değişkeni elle yazmak sıkıcı olur, bu nedenle çoğu proje yerel geliştirme değerlerini bir .env dosyasında tutar:
# local development only
APP_PORT=8080
DATABASE_URL="postgres://dev:devonly@localhost:5432/shop"
FEATURE_SEARCH=true
Python-dotenv ve Node.js için dotenv gibi kitaplıklar bu dosyayı başlangıçta yükler. Node.js 20.6 ve üzeri, --env-file ile yerel olarak da yüklenebilir. Fikri anlamak için yukarıdaki dosyayı şuna dönüştüren küçük bir ayrıştırıcı yazdık:
{'APP_PORT': '8080',
'DATABASE_URL': 'postgres://dev:devonly@localhost:5432/shop',
'FEATURE_SEARCH': 'true'}
Pratikte gerçek bir kütüphane kullanın. 10 satırlık versiyonumuzun göz ardı ettiği alıntılama, kaçış, yorum ve çok satırlı değerleri yönetir. Varsayılan olarak çoğu dotenv yükleyici, önceden ayarlanmış değişkenleri geçersiz kılmazdeğildir, böylece gerçek ortam değerleri dosyanın üzerinde kazanır. Genellikle istediğin budur.
İpucu: İlk işleminizden önce .env‘yi .gitignore‘e ekleyin ve bunun yerine her değişken adı ve güvenli yer tutucu değerleri ile bir .env.example kaydedin. Yeni geliştiriciler bunu kopyalayıp kendi değerlerini doldururlar.
Başlangıçta yapılandırmayı doğrulayın
Eksik bir değişken, açık bir mesajla uygulamayı hemen durdurmalı, bir saat sonra kafa karıştırıcı bir hataya neden olmamalıdır. Yükleme sırasında gerekli ayarları kontrol ettik:
REQUIRED = ["DATABASE_URL", "SECRET_KEY"]
def check_required(env):
missing = [k for k in REQUIRED if not env.get(k)]
if missing:
raise SystemExit(f"Missing required settings: {', '.join(missing)}")
# Missing required settings: SECRET_KEY
Yazılan yapılandırma kitaplıkları daha da ileri gider. Python’daki Pydantic Ayarları, Node.js’deki zod veya envalid ve Java’daki Spring’in yapılandırma özelliklerinin tümü türleri dönüştürür ve her sorunu aynı anda bildirir.
Ortam değişkenleri ve sırlar
Ortam değişkenleri, API anahtarları gibi sırları bir uygulamaya aktarmanın yaygın yoludur ve bunları sabit kodlamaktan çok daha iyidir. Bilmeleri gereken zayıf yönleri var:
- Testimizin gösterdiği gibi çocuk süreçleri onları miras alır.
- Ortamı boşaltan kilitlenme raporlarında, hata ayıklama sayfalarında ve günlüklerde görünebilirler.
- Bazı sistemlerde aynı kullanıcı tarafından çalıştırılan diğer işlemler bunları okuyabilir.
Üretim için birçok ekip, sırları HashiCorp Vault, AWS Secrets Manager, Azure Key Vault veya Google Secret Manager gibi özel bir yöneticide saklar ve bunları çalışma zamanında enjekte eder. Bazıları sırları değişkenler yerine dosyalar olarak birleştirmeyi tercih ediyor. Her iki durumda da, asla günlüklerdeki yapılandırmaları yazdırmayın ve Git’e aktarılmış herhangi bir sırrı geçmişten kaldırdıktan sonra bile döndürün.
Docker ve CI’da
# Docker (not run for this article)
docker run -e APP_PORT=8080 --env-file .env.production myapp
# GitHub Actions (not run for this article)
env:
APP_PORT: 8080
API_KEY: ${{ secrets.API_KEY }}
CI platformları sırları şifrelenmiş olarak saklar ve bunları günlüklerde maskeler. Docker dosyasındaki ENV ile Docker görüntülerine sırlar eklemekten kaçının çünkü bunlar görüntü katmanlarında okunabilir durumda kalır. Kurulumların tamamı için Docker Compose eğitimimize ve GitHub Actions CI/CD kılavuzuna bakın.
En iyi uygulamalar
SHOP_DB_URLgibi bir önekle birlikte anlaşılır, büyük harfli adlar kullanın.- Tüm yapılandırmaları tek bir modülde okuyun, türleri orada dönüştürün ve başlangıçta doğrulayın.
- Yalnızca hassas olmayan ayarlar için güvenli varsayılanlar sağlayın.
.env‘i Git’ten uzak tutun ve bir.env.example‘yi koruyun.- Hassas değerler için üretimde bir gizli dizi yöneticisi kullanın.
- Her değişkeni, türünü ve örnek değerini belgeleyin.
Ortam değişkeni problemlerinde hata ayıklama
Bir uygulama, bir ayar eksikmiş gibi davrandığında şu kontrolleri sırayla gerçekleştirin:
- Doğru yere ayarlanmış mı? Bir terminal sekmesinde dışa aktarılan bir değişken, diğerinde veya sistem tarafından başlatılan bir hizmette mevcut değil.
- Uygulama yeniden başlatıldı mı? Çalışan bir işlem, başlatıldığı ortamı korur. Daha sonra bir değişkeni değiştirmenin yeniden başlatmaya kadar hiçbir etkisi yoktur.
- Ad tam mı? Linux ve macOS’ta adlar büyük/küçük harfe duyarlıdır, dolayısıyla
App_PortveAPP_PORTfarklı değişkenlerdir. Windows onlara aynı şekilde davranır. - Bir .env dosyası onu geçersiz kılıyor mu, yoksa yok sayılıyor mu? Yükleyicinizin mevcut değerleri geçersiz kılıp kılmadığını ve gerçekte hangi dosyayı okuduğunu kontrol edin.
- Başıboş tırnak işaretleri veya boşluklar var mı? Sonunda boşluk veya fazladan tırnak işaretleri ile kopyalanan bir değer, fark edilmesi zor şekillerde ayrıştırılamayabilir veya eşleşmeyebilir.
Bir sürecin gerçekte ne aldığını görmek için değişken adlarını yazdırın, gizli dizilerin değerlerini asla yazdırmayın. Linux ve macOS’ta printenv mevcut kabuğun ortamını listeler ve PowerShell’de Get-ChildItem Env: de aynısını yapar. Bir konteynerin içinde, env‘ten docker exec‘e kadar çalışmak, konteynerin görünümünü gösterir ve bu genellikle kendi kabuğunuzunkinden farklıdır.
Son bir ipucu: başlangıçta hangi isteğe bağlı ayarların varsayılanlarını kullandığını listeleyen bir satır kaydedin. Hiçbir maliyeti yok ve çoğu kişinin cevabını “bunu neden yapıyor?” hemen sorular.
Son sözler
Ortam değişkenleri basittir ancak birkaç tuzağı gizlerler: Her şey bir iptir, çocuklar bunları miras alır ve sırlar bunlardan sızabilir. Bunları uygulamanıza bir girdi olarak değerlendirin. Bunları tek bir yerde okuyun, erkenden dönüştürüp doğrulayın ve gerçek sırları işlenen dosyalardan uzak tutun.
Sık sorulan sorular
Ortam değişkeni nedir?
Bir işlemin kendi ortamından aldığı, APP_PORT=8080 gibi adlandırılmış bir metin değeridir. Uygulamalar bunları ortamlar arasında değişen ayarlar için kullanır.
.env dosyası nedir?
Başlangıçta python-dotenv gibi bir kitaplık tarafından yüklenen KEY=value satırlarından oluşan bir metin dosyası. Esas olarak yerel kalkınma için kullanılır ve gerçek sırlarla işlenmemelidir.
Ortam değişkenim neden bir dize?
İşletim sistemleri ortam değerlerini metin olarak saklar. Sayıları int() ile dönüştürün ve “false” dizesi doğru olarak sayıldığından booleanları açıkça ayrıştırın.
Ortam değişkenleri sırlar açısından güvenli midir?
Sabit kodlamadan daha iyidirler ancak alt süreçler bunları devralır ve günlükler bunları açığa çıkarabilir. Üretim sistemleri genellikle özel bir sır yöneticisi kullanır.
Bir komut dosyası ana kabuğunun değişkenlerini değiştirebilir mi?
Hayır. Bir alt süreç ortamın bir kopyasını alır, dolayısıyla değişiklikleri geri akmaz. Geçerli kabuktaki değişkenleri ayarlamak için bunun yerine dosyayı kaynaklayın.
Öğrenmeye devam et
Test, WordPress veya SEO konusunda yardıma mı ihtiyacınız var?
Ekiplerin daha iyi yazılımlar sunmasına ve sitelerini büyütmesine yardımcı oluyoruz. Bize ne üzerinde çalıştığınızı söyleyin, biz de bir sonraki adım için net bir öneride bulunalım.
Daha fazla kılavuz test, yapay zeka ve modern geliştirme
Bu makaleyi beğendiniz mi? Bir konu seçin ve doğrudan en yeni eğitimlerimize geçin.
Yapay Zeka Halüsinasyonları Açıklandı: Dil Modelleri Neden İşleri Düzeltiyor ve Nasıl Azaltılabilir?
Yapay zeka halüsinasyonları açıkladı: ne olduklarını, dil modellerinin bunları neden ürettiğini, yaygın türlerini, temellendirme ve yönlendirmelerle…
Makaleyi okuyun →DevOpsAçıklanan Ortam Değişkenleri: .env Dosyaları, Sırlar ve Yapılandırma Doğru Yapıldı
Çalıştırdığımız Python örnekleriyle açıklanan ortam değişkenleri: bunları okumak ve ayarlamak, neden her değerin bir dize olduğu, .env dosyaları, sü…
Makaleyi okuyun →Yazılım geliştirmeAPI Hız Sınırlamasının Açıklaması: Algoritmalar, Başlıklar ve 429 Hatalarının Ele Alınması
API hızı sınırlaması, çalıştırdığımız bir simülasyonla açıklanmıştır: belirteç kümesi, sabit pencere, kayan pencere, 429 yanıt, hız sınırı başlıklar…
Makaleyi okuyun →Test otomasyonuPython'da alay etme: Unittest.mock, patch ve Testleri Yalan Yapan Hatalar
Unittest.mock ile Python'da alay etme, test edildi: Sahte ve dönüş_değeri, yan_etki, bir adın kullanıldığı yerde yama uygulama, spesifikasyon ve oto…
Makaleyi okuyun →Yazılım testiKod Kapsamının Açıklaması: Hat ve Şube Kapsamı ve %100'ün Gerçek Anlamı
Kod kapsamı gerçek bir kapsama.py çalışmasıyla açıklanmıştır: hat, şube ve durum kapsamı, bir raporun okunması, %100 kapsamın neden hâlâ hataları ka…
Makaleyi okuyun →Veritabanları ve SQLSQL'de DELETE vs TRUNCATE vs DROP: Farklılıklar, Geri Alma ve Her Biri Ne Zaman Kullanılmalı
DELETE vs TRUNCATE vs DROP test edilmiş SQL ile açıklandı: her birinin neyi kaldırdığı, geri aldığı, tetiklediği, kimlik sıfırlaması, hızı ve Postgr…
Makaleyi okuyun →Veritabanları ve SQLAçıklanan SQL Görünümleri: Örneklerle Tuzakları Oluşturun, Kullanın ve Önleyin
Çalıştırdığımız sorgularla açıklanan SQL görünümleri: görünüm oluşturma, canlı sonuçlar, sütunları gizleme, performans, güncellenebilir ve gerçekleş…
Makaleyi okuyun →Yazılım geliştirmeTypeScript Arayüzü ve Tür: Gerçek Farklılıklar, Derleyiciyle Test Edildi
TypeScript arayüzü ve türü, gerçek derleyiciyle kontrol edildi: her ikisinin de yapabileceği, yalnızca birinin yapabileceği, bildirim birleştirme, g…
Makaleyi okuyun →Yazılım geliştirmePython *args ve **kwargs'ın Açıklaması: Açık Örneklerle Esnek Fonksiyonlar
Python *args ve **kwargs çalıştırdığımız kodla açıklanmıştır: paketleme ve paketten çıkarma, parametre sırası, yalnızca anahtar kelime ve yalnızca k…
Makaleyi okuyun →Yazılım geliştirmePython Lambda İşlevleri: Söz Dizimi, Gerçek Kullanımlar ve Ne Zaman Kullanılmaması Gerektiği
Çalıştırdığımız kodla açıklanan Python lambda işlevleri: sözdizimi, anahtarla sıralama, harita ve filtre, kapatmalar, geç bağlama tuzağı ve normal b…
Makaleyi okuyun →Yapay zekâYapay Zeka Ajanları Nelerdir? Çalıştırabileceğiniz Basit Bir Aracı Döngüsüyle Nasıl Çalışırlar?
Yapay zeka ajanları nedir? Aracı döngüsüne, araçlara, belleğe ve korkuluklara ilişkin basit bir kılavuz, çalıştırdığımız küçük bir Python döngüsü, g…
Makaleyi okuyun →DevOpsİzleme ve Gözlemlenebilirlik: Günlükler, Metrikler ve İzlerle Gerçek Fark
İzleme ve gözlemlenebilirliğin açıklanması: bilinen ve bilinmeyen arızalar, günlükler, ölçümler ve izler, ödeme olayının gözden geçirilmesi, altın s…
Makaleyi okuyun →DevOpsDocker Birimleri ve Bağlama Bağlantıları: Konteyner Verilerini Doğru Şekilde Kalıcılaştırın
Docker birimleri ile bağlama bağlamaları arasındaki karşılaştırma açıklandı: kapsayıcı verilerinin neden kaybolduğu, adlandırılmış birimler, bağlama…
Makaleyi okuyun →Test otomasyonuTDD ve BDD: Temel Farklılıklar, Her İki Şekilde Geliştirilmiş Bir Özellik ve Her Birinin Ne Zaman Kullanılacağı
TDD ve BDD, her iki yönde de oluşturulmuş bir indirim özelliğiyle açıklandı: çalıştırdığımız kodla kırmızı-yeşil-refactor, Verilen-Ne Zaman-O Zaman …
Makaleyi okuyun →Yazılım geliştirmeGit merge vs rebase: farklar, örnekler ve hangisi ne zaman kullanılır
Git merge vs rebase; gerçek log çıktısı, karşılaştırma tablosu, rebase'in altın kuralı ve güvenli bir ekip iş akışıyla anlatılıyor.
Makaleyi okuyun →Yazılım geliştirmePython Liste Üreteci (List Comprehension): Sözdizimi, Örnekler ve Kaçınılacak Durumlar
Python list comprehension anlatımı: sözdizimi, filtreleme, if-else, iç içe döngüler, ölçülmüş süreler ve düz for döngüsünün daha iyi olduğu durumlar.
Makaleyi okuyun →Veritabanları ve SQLSQL JOIN Örneklerle Açıklama (Inner, Left, Right, Full)
SQL JOIN'leri örnek tablolar ve sorgularla adım adım öğrenin: INNER, LEFT, RIGHT, FULL, CROSS ve SELF; yaygın hatalar ve performans ipuçları.
Makaleyi okuyun →