SSD Nodes Learn 8GB RAM — yılda $66
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-01

Docker Compose Birden Fazla Dosyayı Nasıl Birleştirir?

compose.override.yaml dosyasının tek başına nasıl yüklendiğini, dosya sırasını, portu açık bırakan ports tuzağını ve dev-prod ayrımı için include kullanımını öğrenin.

Compose birden fazla dosyayla ne yapar

Docker Compose, tek bir projeyi birden fazla dosyadan oluşturabilir. Dosyaları aldığı sırayla okur ve tek bir modelde birleştirir. Bu nedenle çakışan herhangi bir değerde sonraki dosyadaki değer geçerli olur. Komut satırında bunu sağlayan iki mekanizma vardır: Compose'un kendisinin yüklediği override dosyası ve elle belirtilen -f flag'i. Üçüncü mekanizma dosyanın içinde yer alan include öğesidir ve diğer ikisinden farklı çalışır.

Birleştirme işlemi basit bir üzerine yazma işlemi değildir. Eşlemeler anahtar bazında birleştirilir, diziler sona eklenir ve az sayıdaki alanın tamamı değiştirilir. Beklenmeyen sonuçlar bu farktan kaynaklanır. ports listesi ise neredeyse herkesi zorlayan listedir.

Aşağıdaki açıklamaların tümü eski docker-compose script'i yerine Compose v2 ve docker compose eklentisini temel alır. Denetlemek için docker compose version komutunu çalıştırın. Henüz bir Compose dosyası yazmadıysanız Docker Compose temelleri kılavuzuyla başlayın ve ardından buraya dönün.

Compose'un belirtilmeden yüklediği override dosyası

-f flag'i olmadan docker compose up çalıştırıldığında Compose çalışma dizininde, ardından üst dizinlerde compose.yaml veya docker-compose.yaml dosyalarını arar. Bir override dosyası temel dosyanın yanında bulunuyorsa Compose bu dosyayı kendiliğinden ikinci olarak yükler.

ls compose.yaml compose.override.yaml
docker compose up -d

Her iki dosya da mevcutsa sonuç, bunları elle birlikte belirtmekle aynıdır.

docker compose -f compose.yaml -f compose.override.yaml up -d

Compose'un tanıdığı adlar compose.override.yaml, compose.override.yml ve eski docker-compose.override.yml ile docker-compose.override.yaml adlarıdır. Örneğin compose.dev.yaml gibi başka bir ad, yalnızca -f ile belirtilirse yüklenir.

Bir -f geçirildiği anda otomatik yükleme durur. docker compose -f compose.yaml up tam olarak yalnızca belirtilen dosyayı okur ve override dosyasını yok sayar. Bu özellik, bu kılavuzda daha sonra kullanılan dev ve prod düzeninin temelidir.

Sunucuda bunun iki yönlü etkisi vardır. Deploy dizininde bırakılan bir override dosyası, bu dizinden çalıştırılan her yalın docker compose komutuyla yüklenir. Buna cron işinizin çalıştırdığı komut da dahildir. Üretim stack'inin, kimsenin göndermeyi amaçlamadığı bir kaynak dizinini bind mount olarak bağlamasının nedeni budur. Her deploy işleminden sonra docker compose config çalıştırın ve elde edilen çıktıyı okuyun.

-f ile Sıralama ve Göreli Yolların Çözümlendiği Konum

Compose yapılandırmayı, dosyaları belirttiğiniz sırayla oluşturur. Sonraki dosyalar önceki dosyaları geçersiz kılar ve onlara ekleme yapar. Soldan sağa doğru ilerlenir; son dosyadaki değer geçerlidir.

docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -d

Bu projedeki her komutta aynı dosya listesi kullanılmalıdır. up komutunu iki dosyayla, logs komutunu ise tek dosyayla çalıştırmak farklı birleştirilmiş modellerle işlem yapar. Bu, Compose'un var olmadığını belirttiği bir hizmetle karşılaşmanın hızlı bir yoludur. Bunun yerine listeyi COMPOSE_FILE ortam değişkeniyle bir kez ayarlayın.

export COMPOSE_FILE=compose.yaml:compose.prod.yaml
docker compose config
docker compose up -d

Linux'ta ayraç : değeridir; COMPOSE_PATH_SEPARATOR bu değeri değiştirir. COMPOSE_FILE, proje içindeki .env dosyasında da bulunabilir. Böylece değer, kabuk geçmişinin değil, checkout içeriğinin bir parçası olur. Komut satırında açıkça ayarlanan değer, ortam değişkeninin önceliğini geçersiz kılar.

Şimdi bind mount'ları bozan kurala bakalım. -f ile birden fazla dosya kullandığınızda, bu dosyaların tamamındaki göreli yollar, yolu içeren dosyaya göre değil, ilk dosyanın bulunduğu dizine göre çözülür. deploy/prod/compose.prod.yaml içinde ./data:/var/lib/postgresql/data yazsanız bile Compose ./data yolunu temel dosyanın yanında arar. Docker daha sonra bu yanlış konumda boş bir dizin oluşturur ve container bunun içinde hiçbir şey olmadan başlar. Bu durum veri kaybı gibi görünür, ancak veri kaybı değildir. Temel yolu kendiniz belirlemek için --project-directory seçeneğini geçin veya her dosyayı kendi dizinine göre çözümleyen include seçeneğini kullanın.

Proje adı da aynı temel dizinden türetilir. Bu nedenle ilk dosyanın değiştirilmesi proje adını değiştirebilir. Yeniden adlandırılan bir proje, yeni container adları ve yeni volume adları anlamına gelir. Eski volume, eski ad altında diskte kalır. Bunu önlemek için temel dosyada üst düzey name: tanımı kullanarak adı sabitleyin.

name: myapp

Hangi alanlar birleştirilir, hangileri değiştirilir

Compose, alan adına göre değil, değerin türüne göre birleştirme yapar.

  • Tek değerli alanlar değiştirilir. image, command, entrypoint ve mem_limit doğrudan sonraki değeri alır. Bir command değerine bir bağımsız değişken eklenemez; çünkü geçersiz kılma işlemi satırın tamamını yeniden yazar.
  • Eşlemeler anahtar bazında birleştirilir. environment, labels, volumes ve devices her iki dosyadaki tüm anahtarları korur. Her iki dosyada da bulunan bir anahtar için sonraki dosyanın değeri kullanılır. environment ve labels için anahtar, değişken veya etiket adıdır. volumes ve devices için anahtar, container yoludur.
  • Diziler sona eklenir. dns, dns_search, expose, tmpfs ve external_links birleştirilir. expose: ["3000"] içeren bir temel yapı, ["4000", "5000"] içeren bir geçersiz kılma dosyasıyla birleştirildiğinde ["3000", "4000", "5000"] elde edilir.

Dört dizi bir kimlik anahtarı taşır. Bu nedenle bu anahtarla eşleşen girdiler sona eklenmek yerine birleştirilir. volumes, secrets ve configs, target temelinde eşleşir. ports ise ip, target, published ve protocol birleşimine göre eşleşir.

ports kuralını iki kez okuyun; hata genellikle burada yapılır. İki port girdisi, yalnızca bu dört bölümün tamamı aynı olduğunda aynı girdi sayılır. Bunlardan herhangi birini değiştirirseniz Compose bunu ikinci ve ilgisiz bir port olarak görür ve her ikisini de korur.

Override sonrasında bağlantı noktanız neden hâlâ yayımlanıyor

Her arayüzde bir hizmet yayımlayan temel dosya:

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"

Bir reverse proxy önünde çalışacağı için hizmeti yalnızca localhost adresine bağlamak üzere yazılan override:

services:
  web:
    ports:
      - "127.0.0.1:8080:80"

Çalıştığını varsaymadan önce sonucu kontrol edin.

docker compose -f compose.yaml -f compose.prod.yaml config

Her iki giriş de çıktıda yer alıyor. ip bölümü farklıdır; 0.0.0.0 ile 127.0.0.1 karşılaştırıldığında bunların birleştirme açısından iki farklı bağlantı noktası olduğu görülür. Bu nedenle kaldırmayı denediğiniz genel erişime açık bağlama hâlâ modeldedir. Bu durum Docker'da diğer ortamlara göre daha önemlidir. Çünkü yayımlanan bir bağlantı noktası, güvenlik duvarı kurallarınızdan önce iptables içine yazılır. Mekanizma yayımlanan Docker bağlantı noktalarının ufw kurallarını nasıl aştığı bölümünde açıklanmaktadır.

İki düzeltme yöntemi vardır. Açık yöntem, tüm özniteliği değiştiren ve birleştirme kurallarını atlayan !override etiketidir:

services:
  web:
    ports: !override
      - "127.0.0.1:8080:80"

!override için Compose v2.24.4 veya daha yeni bir sürüm gerekir. Taşınabilir düzeltme için hiçbir etiket gerekmez: ports ifadesini temel dosyanın tamamen dışında tutun ve yalnızca ortama özgü dosyalarda tanımlayın. Birleştirilecek bir şey yoksa sızacak bir şey de olmaz. Aşağıdaki uygulamalı örnekte kullanılan yöntem budur.

Temel dosya tarafından ayarlanan bir değeri silme

!reset bir özniteliği kaldırır ve özniteliği varsayılan değerine veya null değerine döndürür. Bir değer alır ancak bu değeri yok sayar. Bu nedenle geçerli ve boş bir değer yazılmalıdır.

services:
  web:
    ports: !reset []
    environment:
      DEBUG: !reset null

!reset için Compose v2.24 veya daha yeni bir sürüm gerekir. Temel dosya düzenlenemiyorsa, örneğin bir satıcı parçası içe aktarılıyorsa bu yöntem kullanılmalıdır.

parçalardan oluşturulan yığınlar için include

include başka bir Compose uygulamasını modelinize dahil eder. Bu, üst düzey bir öğedir; bir flag değildir.

include:
  - path: ../commons/compose.yaml

include içindeki her yol, kendi proje dizinine sahip ayrı bir Compose uygulama modeli olarak yüklenir. Bu nedenle dosya içindeki göreli yollar, dosyanın kendi dizinine göre çözümlenir. -f ile arasındaki gerçek fark budur. Parça başka bir klasörde veya başka bir repository'de bulunuyorsa include kullanılmasının nedeni de budur.

Uzun biçim, alt seçenekleri kabul eder.

include:
  - path:
      - ../monitoring/compose.yaml
      - ../monitoring/compose.vps.yaml
    project_directory: ../monitoring
    env_file: ../monitoring/.env

path bir liste kabul eder. Bu dosyalar, sonuç modelinize eklenmeden önce normal kurallara göre birleştirilir. project_directory, dahil edilen dosyadaki göreli yolları çözümlemek için kullanılan temel yolu belirler. env_file, dahil edilen dosyaya değişken enterpolasyonu için kendi değişkenlerini verir. Böylece paylaşılan bir parça, projenizin .env dosyasını fark edilmeden okuyamaz. include için Compose v2.20.0 veya daha yeni bir sürüm gerekir.

Dosyanız ile dahil edilen dosya arasındaki yinelenen kaynak adları, sessizce birleştirilmek yerine hata olarak bildirilir. Bu davranış kasıtlıdır. Dahil edilen dosyanın bildirdiği bir öğeyi değiştirmek için değişikliği compose.override.yaml içine yazın. Geçersiz kılma, oluşturulan modele uygulanır. Böylece dahil edilen kaynaklara ad çakışması oluşturmadan erişebilir.

Kısa biçim: include ayrı uygulamaları birleştirir, -f ise tek bir uygulamaya yapılandırma katmanı ekler.

Tek bir VPS üzerinde geliştirme ve üretim ayrımı

Tüm düzen üç dosyadan oluşur. Temel dosya her yerde geçerli olanları tanımlar ve hiçbir port yayımlamaz.

name: myapp

services:
  app:
    image: ghcr.io/example/app:1.4.2
    environment:
      DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/app
      LOG_LEVEL: info
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: app
      POSTGRES_DB: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  db_data:

depends_on koşulu, uygulamanın yalnızca mevcut olan bir container'ı değil, yanıt veren bir veritabanını beklemesini sağlar. Bu konu healthcheck'ler ve depends_on koşulları bölümünde açıklanmıştır. POSTGRES_PASSWORD, proje .env dosyasından alınarak yerine konur. Bu dosya hiçbir zaman git deposuna eklenmemelidir. Daha güvenli seçenekler için env dosyaları ve Compose secrets bölümüne bakılmalıdır.

Sonra, Compose'un kendiliğinden yüklediği compose.override.yaml dosyası gelir. Bu, geliştirici dosyasıdır.

services:
  app:
    build: .
    command: npm run dev
    environment:
      LOG_LEVEL: debug
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src

  db:
    ports:
      - "127.0.0.1:5432:5432"

Bir dizüstü bilgisayarda tek başına kullanılan docker compose up, bu iki dosyayı birleştirir. command tek değerli olduğu için image varsayılanının yerine geçer. LOG_LEVEL, info değerinin yerine geçer; çünkü environment anahtara göre birleştirilir. Bind mount ve yayımlanan iki port doğrudan eklenir. Veritabanı portu localhost'a bağlanır. Böylece paylaşılan bir ağdaki dizüstü bilgisayar PostgreSQL'i aynı ağdaki diğer cihazlara açmaz.

Son olarak compose.prod.yaml dosyası gelir. Compose bu adı aramadığı için dosya yanlışlıkla yüklenmez.

services:
  app:
    ports:
      - "127.0.0.1:8000:3000"
    deploy:
      resources:
        limits:
          memory: 512M

VPS üzerinde her iki dosyanın adını belirtmek gerekir. Bu adlandırma işlemi override dosyasını devre dışı bırakır.

docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose -f compose.yaml -f compose.prod.yaml ps

ps her iki servisin çalıştığını göstermelidir. db çıktısında (healthy) görünmelidir. -f iletildiği için compose.override.yaml okunmamıştır. Bu nedenle dev komutu, kaynak bind mount'u ve public port 3000, dosya aynı dizinde bulunsa bile production ortamına ulaşamaz. Port 8000 yalnızca localhost üzerinde dinlenir ve bir proxy için hazırdır. İkinci servisi eklediğinizde Traefik arkasında birden çok uygulama çalıştırma bölümüne bakılmalıdır.

Sunucunun .env dosyasında COMPOSE_FILE=compose.yaml:compose.prod.yaml değerini ayarlayın. Bundan sonra diğer komutlarınız yeniden doğrudan docker compose logs -f app olur.

Dağıtım yapmadan önce birleştirilmiş modeli okuyun

docker compose config, tamamen birleştirilmiş ve tüm değişkenleri işlenmiş modeli yazdırır. Bu bir önizleme değildir. Compose'un işlem yapacağı tam girdidir. Bu nedenle çıktı beklentinizle uyuşmadığında doğru olan çıktıdır.

docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml config --no-interpolate
docker compose -f compose.yaml -f compose.prod.yaml config --services

--no-interpolate, ${VAR} değerlerini genişletmeden bırakır. Çıktıyı herhangi bir yere yapıştırmadan önce bunu kullanın. Çünkü düz config, çözümlenen tüm gizli bilgileri açık metin olarak yazdırır. --services yalnızca hizmet adlarını listeler. Bu, bir include öğesinin beklenen içeriği alıp almadığını hızlıca doğrulamanızı sağlar.

Hata türleri ve görülecekler

no configuration file provided: not found. Compose okunacak bir şey bulamadı. Proje dizininin dışındasınız veya COMPOSE_FILE mevcut olmayan bir yolu belirtiyor. Compose, varsayılan temel dosyayı bulmak için üst dizinlerde arama yapar. Ancak kendinizin adını verdiği bir dosyayı herhangi bir yerde aramaz.

WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string. Değişken yerleştirme, proje .env dosyası ve kabuk ortamı üzerinden çözülür. Buradaki proje dizini, ilk -f dosyasının bulunduğu dizindir. .env dosyasının bulunduğu dizinden farklı bir dizinden dağıtım yapılırsa bu uyarı alınır. Ardından veritabanı hiçbir bağlantıyı kabul etmez.

Override düzenlemeniz docker compose config içinde görünmüyor. Ya otomatik override yüklemesini devre dışı bırakan -f seçeneğini geçtiniz ya da Compose üst dizinde compose.yaml dosyasını buldu ve override dosyanız bu dosyanın yanında değil. Başka bağımsız değişken olmadan docker compose config çalıştırıldığında Compose'un gerçekte hangi modeli oluşturduğu görülür.

Bir bind mount boş ve Docker istemediğiniz bir dizini oluşturdu. Göreli yol, ilk dosyanın bulunduğu dizine göre çözümlendi. Yolu düzeltin, --project-directory seçeneğini geçin veya parçayı include arkasına taşıyın.

Container'lar yeni adlarla geri geliyor ve bir volume boş görünüyor. Proje adı değişti. Bunun nedeni, proje adının ilk dosyanın bulunduğu dizini izlemesidir. Temel dosyaya üst düzey bir name: ekleyin; adlandırma artık değişmez. Eski volume eski ön ekin altında hâlâ bulunur ve docker volume ls bunu gösterir.

Override dosyasında kaldırdığınız bir port hâlâ açık. ports birleştirme işlemi değiştirmek yerine ekleme yaptı. docker compose config ile doğrulayın. Ardından ya !override kullanın ya da ports seçeneğini temel dosyanın dışına taşıyın.

FAQ

Compose, compose.override.yaml dosyasını otomatik olarak yükler mi?

Evet. -f flag'i olmadan docker compose çalıştırıldığında yükler. Compose, çalışma dizininde ve üst dizinlerinde compose.yaml veya docker-compose.yaml dosyasını arar. Bir override dosyası bu dosyanın yanında bulunuyorsa ikinci olarak yüklenir. Tanınan adlar compose.override.yaml, compose.override.yml, docker-compose.override.yml ve docker-compose.override.yaml dosyalarıdır. Herhangi bir -f geçirilmesi bu davranışı devre dışı bırakır. Bu durumda docker compose -f compose.yaml up yalnızca tek bir dosyayı okur.

Birden çok -f dosyası hangi sırayla birleştirilir?

Soldan sağa. Compose yapılandırmayı dosyaları sağladığınız sırayla oluşturur. Her dosya, kendisinden önceki dosyalara değer ekler ve onların değerlerini geçersiz kılar. Bu nedenle satırdaki son dosya çakışan değerlerde önceliklidir. Bu projedeki her komutta aynı liste kullanılmalıdır. COMPOSE_FILE=compose.yaml:compose.prod.yaml bunun için kullanılır.

Değeri geçersiz kıldığım halde port neden hâlâ yayımlanıyor?

Bunun nedeni, ports girdilerinin ip, target, published ve protocol değerlerinin tamamı kullanılarak tanımlanmasıdır. 127.0.0.1:8080:80 değerinin 8080:80 temel değerine karşı geçersiz kılınması ip bölümünde farklılık oluşturur. Bu nedenle Compose bunu ikinci bir port olarak değerlendirir ve her ikisini de korur. docker compose config çalıştırıldığında iki girdi görülür. Compose v2.24.4 veya daha yeni bir sürümde ports: !override kullanın. Alternatif olarak ports değerini temel dosyadan çıkarın; böylece birleştirilecek bir değer kalmaz.

include ile -f arasındaki fark nedir?

-f birden çok dosyayı tek bir uygulama üzerinde katmanlar. Her dosyadaki göreli yollar, ilk dosyanın dizinine göre çözümlenir. include ayrı bir Compose uygulamasını içeri alır. İçeri alınan her yol kendi proje dizinini korur. Bu nedenle göreli yollar ilgili dosyanın kendi dizinine göre çözümlenir. Kendi yığınınızdaki ortam katmanları için -f kullanın. Başka bir yerde bakımı yapılan bir parça için include kullanın. include için Compose v2.20.0 veya daha yeni bir sürüm gerekir.

Temel dosyanın belirlediği bir değeri nasıl kaldırabilirim?

Compose v2.24 veya daha yeni bir sürümde !reset etiketini kullanın. Geçersiz kılan dosyada ports: !reset [] veya MY_VAR: !reset null yazın. Bu işlem özniteliği varsayılan değerine veya null değerine döndürür. Etikete verilen değer zorunludur ancak dikkate alınmaz. Bir özniteliği temizlemek yerine değiştirmek istiyorsanız !override bunu yapar. Bunun için v2.24.4 veya daha yeni bir sürüm gerekir.