Docker Compose'ta değişken interpolasyonu, Compose dosyasındaki ${TAG} veya $TAG gibi ifadelerin, uygulama modeli oluşturulmadan önce kabuk ortamından, proje dizinindeki .env dosyasından ya da --env-file ile verdiğiniz dosyadan gelen değerlerle değiştirilmesidir. ${VAR:-varsayılan} ile varsayılan değer, ${VAR:?ileti} ile zorunlu değer tanımlayabilirsiniz. Sonucu her zaman docker compose config ile görebilirsiniz; bu yazıdaki tüm çıktılar bu komutla Docker Compose v5.5.1 üzerinde alındı.

Interpolasyon, container'ın içindeki ortam değişkenleriyle aynı şey değildir. Interpolasyon Compose dosyasının metnini çözer; container ortamı ise environment ve env_file öznitelikleriyle kurulur. İkisi sık karıştırıldığı için yazının ikinci yarısında öncelik sırasını ayrıca ele alıyoruz. .env ve env_file kullanımının temelleri Docker Compose rehberinde anlatıldığı için burada sözdizimi ve öncelik kurallarına odaklanıyoruz. Serinin tamamı için Docker öğrenme rehberi.

İlk örnek: imaj etiketini .env dosyasından almak

Belgelerdeki en basit örnek, imaj etiketini dosyayı düzenlemeden değiştirmektir. Proje klasöründe şu iki dosya olsun:

ini
# uygulama sürümü
TAG=v1.5
yaml
services:
  web:
    image: "webapp:${TAG}"

Klasörün adı webapp iken docker compose config çıktısı şöyleydi:

bash
docker compose config
name: webapp
services:
  web:
    image: webapp:v1.5
    networks:
      default: null
networks:
  default:
    name: webapp_default

Aynı komutu kabukta değişken tanımlayarak çalıştırdığımızda image: webapp:v2.0, --env-file ./config/.env.prod ile (dosyada TAG=v1.6 varken) image: webapp:v1.6 satırı geldi. Bu üç sonuç, aşağıda anlatacağımız öncelik sırasının pratikteki karşılığıdır.

bash
TAG=v2.0 docker compose config
docker compose --env-file ./config/.env.prod config

Interpolasyon sözdizimi

Interpolasyon sözdizimi: ${VAR}, ${VAR:-default}, ${VAR-default}, ${VAR:?error}

Interpolasyon tırnaksız ve çift tırnaklı değerlere uygulanır; hem süslü parantezli (${VAR}) hem parantezsiz ($VAR) ifadeler desteklenir. Süslü parantezli biçimde aşağıdaki işleçler kullanılabilir. Tablodaki "boş" ifadesi, değişkenin tanımlı ama değerinin boş olduğu durumu anlatır; iki nokta üst üste (:) olan biçimler boş değeri tanımsız gibi kabul eder.

İfadeSonuç
${VAR}VAR değişkeninin değeri
${VAR:-default}VAR tanımlı ve boş değilse onun değeri, değilse default
${VAR-default}VAR tanımlıysa (boş olsa bile) onun değeri, değilse default
${VAR:?error}VAR tanımlı ve boş değilse onun değeri, değilse hata iletisiyle çıkış
${VAR?error}VAR tanımlıysa onun değeri, değilse hata iletisiyle çıkış
${VAR:+replacement}VAR tanımlı ve boş değilse replacement, değilse boş
${VAR+replacement}VAR tanımlıysa replacement, değilse boş

İfadeler iç içe de yazılabilir: ${VARIABLE:-${FOO}}, ${VARIABLE?$FOO} veya ${VARIABLE:-${FOO:-default}} geçerlidir. Buna karşılık ${VARIABLE/foo/bar} gibi kabuktaki diğer genişletilmiş özellikler Compose'ta desteklenmez. Compose, $ işaretinden sonra gelen metni ancak geçerli bir değişken tanımı oluşturuyorsa işler: ya [_a-zA-Z][_a-zA-Z0-9]* kalıbına uyan bir ad ya da ${ ile başlayan süslü parantezli bir ifade. Diğer durumlarda metin olduğu gibi bırakılır.

Varsayılan, zorunlu ve alternatif değerler

İşleçlerin farkını görmek için şu dosyayı farklı ortamlarla çalıştırdık:

yaml
services:
  app:
    image: "nginx:${NGINX_TAG:-1.27}"
    environment:
      LOG_LEVEL: ${LOG_LEVEL-info}
      LOG_LEVEL_STRICT: ${LOG_LEVEL:-info}
      EXTRA: ${FEATURE:+enabled}
      DB_HOST: ${DB_HOST:?DB_HOST tanımlanmalı}

Önce LOG_LEVEL ve NGINX_TAG değişkenlerini tanımlı ama boş, FEATURE değişkenini dolu verdik. Çıktının ilgili kısmı:

bash
DB_HOST=db LOG_LEVEL= FEATURE=1 NGINX_TAG= docker compose config
name: ornek
services:
  app:
    environment:
      DB_HOST: db
      EXTRA: enabled
      LOG_LEVEL: ""
      LOG_LEVEL_STRICT: info
    image: nginx:1.27

Farkı burada açıkça görüyoruz: ${LOG_LEVEL-info} boş ama tanımlı değişkeni kabul edip boş değer verdi, ${LOG_LEVEL:-info} ise boş değeri tanımsız sayıp varsayılana döndü. NGINX_TAG boş olduğu için imaj etiketi 1.27 oldu. LOG_LEVEL değişkeni hiç tanımlı değilken iki satır da info, FEATURE yokken de EXTRA boş geldi.

DB_HOST hiç verilmediğinde Compose dosyayı işlemeyi reddetti ve kendi iletimizi gösterdi:

bash
docker compose config
error while interpolating services.app.environment.DB_HOST: required variable DB_HOST is missing a value: DB_HOST tanımlanmalı

Zorunlu değişkenler, sunucuda eksik bir .env dosyası yüzünden servisin boş parolayla veya yanlış adresle ayağa kalkmasını önlemenin en basit yoludur. Dosyanın hangi değişkenleri kullandığını görmek için --variables bayrağı işe yarar; aynı dosyada çıktı şuydu:

bash
docker compose config --variables
NAME                REQUIRED            DEFAULT VALUE       ALTERNATE VALUE
NGINX_TAG           false               1.27                
LOG_LEVEL           false               info                
FEATURE             false                                   enabled
DB_HOST             true

Varsayılanı olmayan bir değişken çözülemezse Compose bir uyarı gösterir ve yerine boş metin koyar. Belgelerdeki örnek bu durumun tehlikesini iyi anlatır: postgres:${POSTGRES_VERSION} ifadesinde değişken tanımlı değilse sonuç postgres: olur ve bu geçerli bir imaj referansı değildir.

Dolar işaretini kaçırmak: $$

Bazı değerlerde Compose'un değil container içindeki kabuğun çözmesi gereken değişkenler bulunur. Tipik örnek PostgreSQL sağlık kontrolüdür. Değişkeni Compose'dan saklamak için çift dolar ($$) yazarsınız; bu bir dolar işaretini harfiyen bırakır ve Compose o ifadeyi interpolasyona sokmaz.

yaml
services:
  db:
    image: postgres:18
    environment:
      POSTGRES_USER: app
      POSTGRES_DB: app
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s

docker compose config bu dosyayı yazdırırken test satırını yine pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB} olarak gösterdi. Bunun nedeni, komutun çıktısının kendisinin de geçerli bir Compose dosyası olmasıdır: harfiyen dolar işareti çıktıda da kaçırılmış haliyle durur. Sağlık kontrolü container içinde çalışırken ifade kabuk tarafından ${POSTGRES_USER} olarak çözülür.

Anahtarlarda interpolasyon yapılmaz

Interpolasyon yalnızca YAML değerlerine uygulanır, anahtarlara uygulanmaz. Anahtarın kullanıcı tanımlı olduğu birkaç yerde, örneğin labels ve environment içinde, değişkenli bir anahtar istiyorsanız eşittir işaretli liste sözdizimini kullanmalısınız. Şu dosyayı ORTAM=prod ile çalıştırdık:

yaml
services:
  db:
    image: postgres:18
    labels:
      "com.example.${ORTAM}": "anahtar-interpolasyonu-yok"
  web:
    image: nginx:latest
    labels:
      - "com.example.${ORTAM}=liste-sozdizimi"

Çıktıda db servisinin etiketi com.example.$${ORTAM} olarak, yani hiç çözülmeden kaldı; web servisinde ise liste sözdizimi sayesinde etiket com.example.prod oldu.

Değişkenler nereden gelir ve hangisi kazanır?

Değişkenler nereden gelir ve hangisi kazanır? Kabuk ortamındaki değişkenler., --env-file ile verilen dosyadaki değişkenler., --env-file verilmemişse proje dizinindeki .env...

Aynı değişken birden fazla kaynakta tanımlıysa interpolasyon için şu öncelik geçerlidir (yukarıdaki kazanır):

  • Kabuk ortamındaki değişkenler.
  • --env-file ile verilen dosyadaki değişkenler.
  • --env-file verilmemişse proje dizinindeki .env dosyası. Proje dizini, verilmişse --project-directory, değilse -f ile verilen ilk Compose dosyasının dizini, o da yoksa kabuğun bulunduğu dizindir.

Birden fazla --env-file verebilirsiniz; Compose dosyaları sırayla okur ve sonraki dosya öncekindeki değeri ezer. --env-file yolu komutu çalıştırdığınız dizine göre çözülür. Var olmayan bir dosya verdiğimizde Compose couldn't find env file iletisi ve dosyanın tam yoluyla hata verip çıktı. Kullanılan değişkenleri ve değerlerini görmek için belgeler docker compose config --environment komutunu önerir.

bash
docker compose --env-file .env --env-file .env.override config
docker compose config --environment

Bir ayrıntı daha var: --env-file verilmediğinde Compose iki .env dosyası yükleyebilir. Proje dizinindeki .env dosyası COMPOSE_FILE değişkeniyle başka bir dizindeki Compose dosyasını gösteriyorsa, o dizindeki .env dosyası da daha düşük öncelikle yüklenir. Bu sayede mevcut bir projeyi komut satırına değişken yazmadan kendi değerlerinizle çalıştırabilirsiniz. Ayrıca .env dosyasından yapılan bu yerine koyma bir Docker Compose CLI özelliğidir; Swarm'da docker stack deploy ile çalışırken desteklenmez (bkz. Docker stack deploy).

.env dosyasının sözdizimi

.env dosyasının kuralları basit görünse de tırnak ve yorum kuralları sürpriz yaratabilir. Belgelerdeki kuralların özeti şöyledir: # ile başlayan satırlar ve boş satırlar yok sayılır; her satır bir anahtar ve değer çiftidir; ayırıcı = veya : olabilir; değerin önündeki ve arkasındaki boşluklar atılır. Tırnaksız ve çift tırnaklı değerlere interpolasyon uygulanır, tek tırnaklı değerler harfiyen alınır ve birden fazla satıra yayılabilir. Tırnaksız değerde satır içi yorumun önünde boşluk olmalıdır; tırnaklı değerde yorum kapanış tırnağından sonra gelmelidir. Çift tırnak içinde \n, \t gibi kaçış dizileri desteklenir.

Kuralları denemek için şu .env dosyasını kullandık:

ini
COMPOSE_PROJECT_NAME=blog
DEV_MODE=true
APP_DEBUG=${DEV_MODE:-false}
LITERAL='${DEV_MODE}'
NOT_COMMENT=deger# yorum degil
WITH_COMMENT=deger # bu bir yorum
QUOTED="deger # yorum degil"

Bu değişkenleri environment altında kullanan bir servis için docker compose config çıktısı şuydu:

yaml
name: blog
services:
  app:
    environment:
      APP_DEBUG: "true"
      LITERAL: $${DEV_MODE}
      NOT_COMMENT: deger# yorum degil
      QUOTED: 'deger # yorum degil'
      WITH_COMMENT: deger
    image: example/app

Sonuçlar belgelerle birebir uyuştu. .env içindeki ${DEV_MODE:-false} ifadesi aynı dosyadaki değerle çözüldü; tek tırnaklı değer harfiyen kaldı; boşluksuz # yorum sayılmadı; çift tırnak içindeki # değerin parçası oldu. .env içindeki COMPOSE_PROJECT_NAME da proje adını blog yaptı. Aynı klasörde COMPOSE_DISABLE_ENV_FILE=1 ile çalıştırdığımızda .env dosyası okunmadı, her değişken için The "APP_DEBUG" variable is not set. Defaulting to a blank string. biçiminde uyarılar geldi ve proje adı klasör adına döndü.

Container ortamında öncelik sırası

Container ortamında öncelik sırası: docker compose run -e ile komut satırında verilen değer., environment veya env_file içinde olup değeri kabuktan ya da bir ortam..., Yalnızca...

Interpolasyon dosyayı çözdükten sonra container'ın ortamı ayrı bir öncelik kuralıyla kurulur. Belgelerdeki sıra (yukarıdaki kazanır) şöyledir:

  • docker compose run -e ile komut satırında verilen değer.
  • environment veya env_file içinde olup değeri kabuktan ya da bir ortam dosyasından interpolasyonla gelen değer.
  • Yalnızca environment özniteliğiyle verilen değer.
  • env_file özniteliğiyle verilen değer.
  • İmajdaki ENV talimatıyla gelen değer. Dockerfile'daki ARG veya ENV ancak Compose tarafında environment, env_file ya da run --env girdisi yoksa etkili olur.

Belgelerdeki örneği doğruladık: webapp.env dosyasında NODE_ENV=test, environment altında NODE_ENV=production varken docker compose config servis ortamını tek satır olarak NODE_ENV: production gösterdi; yani environment kazandı. Ayrıca kabuk ortamı ve .env dosyası, Compose dosyasında karşılığı olmadıkça container'a kendiliğinden bir değişken eklemez. environment altında yalnızca - DEBUG yazarsanız değer kabuktan geçirilir ve tanımsızsa uyarı verilmez; - DEBUG=${DEBUG} yazarsanız değişken kabukta veya .env dosyasında yoksa Compose uyarır. Ortam değişkenlerinin ARG ile ilişkisi için ARG ve ENV farkı yazısına bakın.

COMPOSE_ ile başlayan önceden tanımlı değişkenler

Compose kendi davranışını da ortam değişkenleriyle ayarlamanıza izin verir. Bunlar .env dosyasına, kabuğa veya komut satırına yazılabilir. Sunucuda en çok işe yarayanlar şunlardır:

DeğişkenNe yapar
COMPOSE_PROJECT_NAMEProje adını belirler; container adları proje ve servis adından oluşur (myapp-web-1 gibi)
COMPOSE_FILEKullanılacak Compose dosyaları; Linux ve macOS'ta iki nokta, Windows'ta noktalı virgülle ayrılır
COMPOSE_PATH_SEPARATORCOMPOSE_FILE için farklı bir ayırıcı
COMPOSE_PROFILESup sırasında etkinleştirilecek profiller, virgülle ayrılır
COMPOSE_ENV_FILES--env-file verilmediğinde kullanılacak ortam dosyaları, virgülle ayrılır
COMPOSE_DISABLE_ENV_FILEtrue veya 1 ise varsayılan .env dosyası yok sayılır
COMPOSE_REMOVE_ORPHANSArtık dosyada olmayan servislerin container'larını otomatik kaldırır
COMPOSE_IGNORE_ORPHANSSahipsiz container tespitini kapatır
COMPOSE_PROGRESSİlerleme çıktısının türü: auto, tty, plain, json, quiet

Proje adı için öncelik sırası şöyledir: -p bayrağı, COMPOSE_PROJECT_NAME, Compose dosyasındaki en üst düzey name: (birden fazla -f varsa sonuncusu), proje dizininin adı ve son olarak bulunduğunuz dizinin adı. Proje adları yalnızca küçük harf, rakam, tire ve alt çizgi içerebilir ve küçük harf ya da rakamla başlamalıdır; klasör adınız bu kurala uymuyorsa diğer yollardan birini kullanmanız gerekir. Belgeler ayrıca COMPOSE_API_VERSION, COMPOSE_HTTP_TIMEOUT gibi bazı eski değişkenlerin Compose V2'de etkisi olmadığını belirtir.

Interpolasyonun ne zaman çalıştığı da önemlidir. Belirtime göre interpolasyon, birden fazla dosya birleştirilmeden önce her dosyaya ayrı ayrı uygulanır. YAML anchor ve alias çözümlemesi ise interpolasyondan önce yapılır; bu yüzden anchor veya alias adlarını değişkenle belirleyemezsiniz. Dosya birleştirme ve fragment kullanımı include, extends ve merge yazısında anlatılıyor.

Sık yapılan hatalar

  • Varsayılansız değişkene güvenmek. Tanımsız değişken boş metne dönüşür ve postgres: gibi geçersiz değerler oluşur. Kritik değerlerde :? kullanın.
  • :- ile - farkını gözden kaçırmak. Boş bırakılmış bir değişken - biçiminde boş değer olarak geçer.
  • Container içi değişkeni $ ile yazmak. Compose onu kendi ortamından çözmeye çalışır; container'ın çözmesi gerekiyorsa $$ yazın.
  • Anahtarda değişken kullanmak. Anahtarlar çözülmez; labels ve environment için liste sözdizimini kullanın.
  • .env dosyasını yanlış dizine koymak. -f ile başka bir dizindeki dosyayı verdiğinizde proje dizini o dosyanın dizinidir ve .env orada aranır.
  • Kabukta kalmış eski bir değişken. Kabuk ortamı .env dosyasını ezer; beklenmeyen bir değer görüyorsanız önce kabuktaki değişkenleri kontrol edin.

Sık Sorulan Sorular

.env dosyası container'a otomatik olarak geçer mi?

Hayır. .env dosyası Compose dosyasının interpolasyonu ve Compose'un kendi ayarları içindir. Bir değerin container ortamına girmesi için environment veya env_file ile açıkça verilmesi gerekir.

Compose dosyasının gerçekte hangi değerlerle çözüldüğünü nasıl görürüm?

docker compose config çözülmüş modeli yazdırır, --variables dosyadaki değişkenleri ve varsayılanlarını, --environment ise interpolasyon için kullanılan ortamı gösterir.

Farklı ortamlar için farklı .env dosyaları nasıl kullanılır?

Dosyaları .env.prod, .env.test gibi adlandırıp --env-file ile seçebilir ya da COMPOSE_ENV_FILES değişkenine yazabilirsiniz. Belgelerin en iyi uygulama sayfası da ortamlar için ayrı dosyalar kullanmayı önerir.

${VAR/foo/bar} gibi kabuk değiştirmeleri çalışır mı?

Hayır. Compose yalnızca tablodaki varsayılan, zorunlu ve alternatif değer biçimlerini ve bunların iç içe kullanımını destekler.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Docker öğrenme rehberi · Docker Compose rehberi · Compose secrets ve configs · Compose include, extends ve merge · ARG ve ENV farkı