Docker Compose .env, env_file ve secrets farkları
Docker Compose'ta .env, env_file ve environment farklarını, öncelik sırasını ve parolaların neden environment yerine secrets ile saklanması gerektiğini öğrenin.
İnsanların env dosyası olarak adlandırdığı üç şey
Docker Compose, adları birbirine benzediği için karıştırılabilen üç ayrı mekanizma sunar. .env dosyası, Compose dosyayı ayrıştırmadan önce compose.yaml içindeki ${VARIABLE} yer tutucularını doldurur. env_file: özniteliği, anahtar/değer çiftlerinden oluşan bir dosyayı container ortamına yükler. environment: özniteliği ise değişkenleri compose dosyasında doğrudan tanımlayarak container üzerinde ayarlar. Bunlar birbirinin yerine kullanılamaz. İkisi aynı anahtarı ayarladığında, hangi değerin geçerli olacağı belgelenmiş bir öncelik sırasına göre belirlenir.
Bu kılavuzda her mekanizmanın nasıl çalıştığı gösterilir. Ardından çalıştırılabilecek bir komutla öncelik sırası doğrulanır. Daha önemli konu da ele alınır: ortam değişkenleri docker inspect çalıştırabilen herkes tarafından okunabilir. Bu nedenle parolalar ortam değişkenlerinde tutulmamalıdır. Compose dosyalarını genel olarak kullanmaya yeni başlanıyorsa, VPS üzerinde Docker Compose temelleri ile başlanabilir ve yapılandırma için buraya dönülebilir.
.env dosyası container için değil, compose dosyası içindir
Bir dizin oluşturun ve içine iki dosya yerleştirin.
mkdir -p ~/envdemo && cd ~/envdemo
printf 'ALPINE_TAG=3.20\n' > .envservices:
demo:
image: alpine:${ALPINE_TAG}
command: printenv ALPINE_TAGŞimdi Compose'un gerçekte neyi ayrıştırdığını kontrol edin.
docker compose configÇıktıda image: alpine:3.20 gösterilir. Yer tutucu artık yoktur, çünkü enterpolasyon ayrıştırma sırasında gerçekleşmiştir. Compose, proje dizininde, yani compose dosyasının bulunduğu dizinde .env dosyasını arar ve bulduğu her ${NAME} ifadesini değiştirir.
Ardından servisi çalıştırın.
docker compose run --rm demoprintenv ALPINE_TAG 1 durum koduyla çıkar ve hiçbir çıktı vermez. Değişken container içinde mevcut değildir. En yaygın yanlış anlama budur: .env compose dosyasını yapılandırır, işlemi değil. İçinde POSTGRES_PASSWORD=hunter2 bulunan bir .env dosyası, compose dosyasının herhangi bir bölümü bu dosyaya başvurmuyorsa veritabanınız için hiçbir işlem yapmaz.
${NAME:-default}, değişken ayarlanmamışsa veya boşsa bir varsayılan değer sağlar. ${NAME:?message} ise Compose'un başlatmayı reddetmesini ve belirttiğiniz mesajı yazdırmasını sağlar. Güvenli bir varsayılan değeri olmayan bir değer için doğru seçim budur.
env_file değişkenleri container içine yükler
env_file: özniteliği, içerikleri container ortam değişkenlerine dönüştürülen bir veya daha fazla dosyanın adını belirtir.
printf 'GREETING=from_env_file\nAPP_MODE=production\n' > app.envservices:
demo:
image: alpine:3.20
command: printenv GREETING
env_file:
- ./app.envdocker compose run --rm demoBu komut from_env_file çıktısını verir. Dosya biçimi, her satırda bir tane bulunan düz KEY=value satırlarından oluşur. Yorumlar # ile başlatılır. Bu biçim shell biçimi değildir. Çoğu durumda tırnak işaretleri değerin parçası olarak korunur ve export önekleri gerekli değildir. = işaretinin çevresine boşluk koyulmamalıdır. Aksi halde KEY = value değeri, değerinin başında boşluk bulunan ve adı kelimesi kelimesine KEY olan bir değişken oluşturur.
Bulunmayan env_file yolu hatadır ve Compose çalışmayı durdurur. Dosya geçerli olarak bulunmayabilecekse dosyayı isteğe bağlı olarak işaretleyin:
env_file:
- path: ./app.env
required: falseenvironment değişkenleri satır içinde ayarlar
services:
demo:
image: alpine:3.20
command: printenv GREETING
environment:
GREETING: from_environmentYukarıdaki eşleme biçimi ve - GREETING=from_environment kullanan liste biçimi olmak üzere 2 söz dizimi kabul edilir. İkisi de aynı şekilde çalışır. Liste biçiminin bir ek özelliği vardır: Değeri olmayan yalın bir anahtar, değişkeni docker compose komutunu çalıştırdığınız kabuktan aktarır.
environment:
- GREETINGGREETING=from_my_shell docker compose run --rm demoBu işlem from_my_shell çıktısını verir. Kabukta GREETING ayarlanmadan çalıştırıldığında Compose hiçbir değer ayarlamaz ve uyarı vermez. Sessiz geçiş hatlarının bilinmesi önemlidir. Boş bir parola değişkeniyle başlatılan bir hizmet çoğu zaman başarıyla başlar, ancak tamamen korumasız kalır.
Hangisi öncelikli
Docker, öncelik sırasını en yüksekten başlayarak belgeler: önce komut satırındaki docker compose run -e, ardından değeri kabuğunuzdan veya bir env dosyasından enterpole edilen environment ya da env_file, sonra compose dosyasındaki düz environment, ardından env_file ve son olarak image içine yerleştirilmiş ENV yönergesi.
Günlük kullanım için kısa özet: environment:, env_file: değerine üstün gelir; komut satırındaki -e ise her ikisine de üstün gelir. Bunu tek bir dosyada doğrulayın.
services:
demo:
image: alpine:3.20
command: printenv GREETING
env_file:
- ./app.env
environment:
GREETING: from_environmentdocker compose run --rm demo
docker compose run --rm -e GREETING=from_cli demo printenv GREETINGİlk komut from_environment çıktısını verir. Bunun nedeni environment: değerinin app.env içindeki değerin üzerine yazmasıdır. İkinci komut from_cli çıktısını verir. Compose dosyasındaki hiçbir ayar komut satırındaki değerin üzerine yazmaz.
Bir container, yapılandırmanız hiç uygulanmamış gibi davranıyorsa tahminde bulunmayın. docker compose config, tamamen çözümlenmiş dosyayı yazdırır. docker compose config --environment ise Compose'un kullandığı enterpolasyon değişkenlerini yazdırır. "env dosyam yok sayılıyor" bildirimlerinin çoğunda aynı değer iki farklı düzeyde tanımlanmıştır.
Ortam değişkenleri neden sızar
environment: içine bir parola ayarlanırsa parola, diskteki container yapılandırmasında depolanır ve docker grubundaki tüm kullanıcılar tarafından görülebilir.
docker compose run -d --name leaky -e DB_PASSWORD=hunter2 demo sleep 300
docker inspect leaky --format '{{json .Config.Env}}'Çıktı, "DB_PASSWORD=hunter2" değerini düz metin olarak içerir. Üç ek yol da aynı değeri açığa çıkarır. docker compose config bu değeri terminale yazdırır. Değer bu şekilde bir destek forumuna yapıştırılır. Container içindeki herhangi bir işlem /proc/1/environ değerini okuyabilir ve her alt işlem bu değişkeni devralır. Ayrıca uygulamaların çökme işleyicileri, ortamın tamamını rutin olarak bir günlüğe veya hata raporuna döker.
docker grubuna üyelik, host üzerinde fiilen root yetkisine eşdeğerdir. Bu nedenle bu üyelik, güvenilebilecek bir ayrıcalık sınırı değildir. VPS üzerinde en az ayrıcalıklı kullanıcı hesapları kılavuzu, paylaşımlı herhangi bir sunucuda bu grubun neden kısıtlanması gerektiğini açıklar.
Compose secret değerini bir dosyada tutar
Compose, dosya tabanlı secret'ları destekler. Değer, ortama aktarılmak yerine container içine dosya olarak mount edilir.
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txtSecret, container içinde /run/secrets/db_password yoluna mount edilir. Eğik çizgiden sonraki ad, üst düzey secrets: bloğundaki secret adıdır.
_FILE son eki, postgres, mysql ve mariadb dahil Docker Official Images tarafından kullanılan bir kuraldır. Bu entrypoint script'leri VARNAME_FILE değerini kontrol eder, dosyayı okur ve içeriğini kullanır. Bu bir Docker özelliği değildir. Bu nedenle yalnızca image bunu uyguluyorsa çalışır. SOMETHING_FILE değerinin dikkate alınacağını varsaymadan önce image belgelerini kontrol edin. Bunu desteklemeyen uygulamalar, başlangıçta dosyayı kendileri okuyabilir. Alternatif olarak yolu aktarabilir ve işlemi kendi entrypoint'inize yaptırabilirsiniz.
Çalışan container içinden doğrulayın:
docker compose exec db cat /run/secrets/db_password
docker compose exec db printenv POSTGRES_PASSWORDİlk komut parolayı yazdırır. İkinci komut hiçbir şey yazdırmaz, çünkü değer ortama hiç aktarılmamıştır. Amaç tam olarak budur: Bu container üzerindeki docker inspect yalnızca zararsız yolu gösterir.
Secret, arkasındaki dosya kadar gizli olduğundan host üzerindeki kaynak dosyayı koruyun:
chmod 600 db_password.txtVPS üzerinde uygulanabilir orta yol
Birçok self-hosted imaj _FILE değişkenlerini desteklemez. Bu nedenle içeriye geçiş için tek yol ortam değişkenleridir. Tek yöneticili bir VPS'te gerçekçi hedef, değerlerin proje dizininde herkes tarafından okunabilen bir dosyada bulunmasını önlemek ve bunları git dışında tutmaktır.
sudo install -o root -g root -m 600 /dev/null /etc/myapp/app.env
sudo nano /etc/myapp/app.env env_file:
- /etc/myapp/app.envinstall -m 600 dosyayı, izinleri baştan ayarlanmış şekilde oluşturur. Böylece dosyanın herkes tarafından okunabildiği bir zaman aralığı oluşmaz. Dosyanın sahibi root hesabıdır. Bu nedenle makinedeki root olmayan bir kullanıcı dosyayı okuyamaz. Ancak docker çalıştırabilen herkes değeri yine de container içinden okuyabilir. *.env ve .env satırlarını .gitignore dosyasına ekleyin. Bunun yerine anahtar adlarını boş değerlerle içeren bir app.env.example dosyasını commit edin. Commit edilmiş bir parola değiştirilmiş parola kabul edilir.
Bir değeri değiştirmek servisin yeniden başlatılmasını gerektirir. Ortam değişkenleri container işlemi başlatıldığında bir kez okunur. Bu nedenle dosyayı düzenlemek, docker compose up -d --force-recreate db çalıştırılana kadar hiçbir şeyi değiştirmez. Bu, VPS üzerinde HTTPS arkasında n8n kılavuzunda kullanılan yöntemin aynısıdır. Bu yöntemde şifreleme anahtarı compose dosyasının dışında tutulur.
Ortama göre yapılandırmayı ayırma
Compose, varsayılan olarak .env dosyasını proje dizininden okur. --env-file ile başka bir konum belirtilebilir.
docker compose --env-file .env.staging configBirden çok dosya sırayla okunur ve sonraki dosyalardaki değerler önceki değerleri geçersiz kılar. Gizli olmayan varsayılan değerler sürüm denetimine alınan bir dosyada, gizli bilgiler ise sunucudan hiçbir zaman çıkarılmayan bir dosyada tutulmalıdır. Aynı durum env_file: için de geçerlidir; yinelenen bir anahtar için listelenen son dosyanın değeri geçerli olur.
FAQ
.env dosyam neden container içinde yok sayılıyor?
Yok sayılmıyor. .env dosyası yalnızca compose dosyasındaki ${NAME} yer tutucularını değiştirir. Container içindeki değişkenleri hiçbir zaman ayarlamaz. Değeri container içine aktarmak için environment: { KEY: "${NAME}" } öğesine başvurun veya bunun yerine env_file: ./that-file.env kullanın.
environment, env_file değerini geçersiz kılar mı, yoksa tersi mi geçerlidir?
environment: önceliklidir. Docker'ın belgelenmiş öncelik sıralamasında environment özniteliği env_file özniteliğinin üzerinde, her ikisi de komut satırındaki docker compose run -e değerinin altında yer alır. Bir anahtar her iki yerde de ayarlanırsa env_file içindeki değer sessizce kullanılmaz.
Compose'un kullanacağı nihai değeri nasıl görebilirim?
Tüm enterpolasyon uygulanmış, tamamen çözümlenmiş compose dosyasını yazdırmak için docker compose config komutunu çalıştırın. Zaten çalışmakta olan bir container için docker inspect <container> --format '{{json .Config.Env}}', işlemin aldığı değerleri tam olarak gösterir.
Compose secret değerleri şifrelenir mi?
Hayır. Dosya tabanlı bir secret, /run/secrets/<name> konumunda düz metin dosyası olarak container içine bağlanır ve kaynak dosya host diskinde şifrelenmeden tutulur. Avantaj şifreleme değil, kapsamın sınırlı olmasıdır: değer container ortamından, docker inspect çıktısından ve ortam değişkenlerini yazdıran crash dump'larından uzak kalır.
Bir env dosyasında tırnak ve boşluk kullanabilir miyim?
KEY=value with spaces kullanın ve tırnakları eklemeyin. Compose, satırın geri kalanının tamamını değer olarak kabul eder. Bu nedenle tırnaklar genellikle değerde gerçek karakterler olarak kalır. = çevresine hiçbir zaman boşluk koymayın. Aksi halde anahtarın sonunda boşluk bulunur ve hiçbir değer bununla eşleşmez.