Docker Compose'ta birden fazla dosyayla çalışmanın üç yolu vardır. Merge, -f ile verdiğiniz dosyaları sırayla üst üste birleştirir; compose.override.yaml bu yolla kendiliğinden okunur. extends, tek bir servis tanımını başka bir servisten veya başka bir dosyadan devralır. include ise başka bir Compose uygulamasını kendi proje dizini ve kendi .env dosyasıyla birlikte modelinize kopyalar. Bunlara ek olarak tek dosya içinde tekrarı azaltmak için YAML fragment'leri ve x- ile başlayan extension alanları kullanılır.
Bu yazı bu dört mekanizmanın kurallarını, birbirinden farklarını ve en çok kafa karıştıran noktaları anlatır. Temel override dosyası kullanımı Docker Compose rehberinde anlatıldığı için burada birleştirme kurallarının ayrıntısına iniyoruz. Örneklerdeki tüm çıktılar Docker Compose v5.5.1 ile docker compose config çalıştırılarak alındı. Serinin tamamı için Docker öğrenme rehberi.
Hangi yöntem ne zaman?

Belgeler en basit yolun -f ile birleştirme olduğunu, ancak yapılandırma büyüdükçe birleştirme kurallarının yönetimi zorlaştırabileceğini söyler. Ekiplerin ayrı alt dizinlerde kendi Compose dosyalarını tuttuğu bir monorepo için include önerilir, çünkü merge ve extends'in yarattığı göreli yol sorununu çözer.
| Yöntem | Birimi | Göreli yollar | Tipik kullanım |
|---|---|---|---|
| Merge (-f, override) | Tüm dosya | İlk (temel) dosyaya göre | Geliştirme ve production farkları |
| extends | Tek servis | Devralınan dosyadaki yollar dönüştürülür | Ortak ayarları paylaşan servisler |
| include | Bütün Compose uygulaması | Her dosya kendi dizinine göre | Başka ekibin veya bileşenin dosyası |
| Fragment ve x- alanları | Dosya içi YAML parçası | Etkilemez | Aynı dosyada tekrar eden bloklar |
Merge: dosyaları üst üste birleştirmek
Compose varsayılan olarak iki dosya okur: temel yapılandırmayı içeren compose.yaml ve isteğe bağlı compose.override.yaml. Başka adlı dosyalar veya ikiden fazla dosya için -f bayrağını ya da COMPOSE_FILE değişkenini kullanırsınız. Dosyalar komut satırında verildikleri sırayla birleştirilir; sonraki dosya öncekine ekleme yapabilir, onu ezebilir. -f verilmezse Compose çalışma dizininde ve üst dizinlerde bu iki dosyayı arar; aynı düzeydeyse ikisini birleştirir. -f - yazarak yapılandırmayı standart girdiden de okutabilirsiniz; bu durumda tüm yollar bulunduğunuz dizine göre çözülür.
Compose belirtimi birleştirme kurallarını şöyle tanımlar:
- Mapping (eşleme): Eksik anahtarlar eklenir, çakışan anahtarlarda sonraki dosyanın değeri geçerli olur.
environmentvelabelsbu yüzden değişken veya etiket adına göre birleşir. - Sequence (dizi): Sonraki dosyadaki öğeler öncekinin sonuna eklenir. Örneğin iki dosyadaki
dnslisteleri birleşir. - Komut istisnası:
command,entrypointvehealthcheck.testdizi olsa da eklenmez; son dosyadaki değer öncekinin yerine geçer. - Benzersiz kaynaklar:
ports,volumes,secretsveconfigsdizi olarak yazılır ama benzersiz anahtara göre birleşir.volumes,secretsveconfigsiçin anahtartarget,portsiçin ip, target, published ve protocol dörtlüsüdür. Aynı anahtarlı girdi birleşir, farklı olan eklenir.
Aşağıdaki temel dosya geliştirme için yazılmış; production dosyası ise portu yalnızca yerel adrese açıyor, DEBUG değişkenini kaldırıyor, komutu değiştiriyor ve veritabanı portunu tamamen siliyor:
services:
web:
image: example/my_web_app:latest
ports:
- "8080:80"
environment:
DEBUG: "true"
LOG_LEVEL: info
command: ["npm", "run", "dev"]
depends_on:
- db
db:
image: postgres:18
ports:
- "5432:5432"services:
web:
ports: !override
- "127.0.0.1:8080:80"
environment:
DEBUG: !reset null
LOG_LEVEL: warn
command: ["npm", "start"]
restart: always
db:
ports: !reset []docker compose -f compose.yaml -f compose.prod.yaml config çıktısında web servisi şöyleydi; db servisinde ise ports anahtarı hiç yoktu:
web:
command:
- npm
- start
depends_on:
db:
condition: service_started
required: true
environment:
LOG_LEVEL: warn
image: example/my_web_app:latest
networks:
default: null
ports:
- mode: ingress
host_ip: 127.0.0.1
target: 80
published: "8080"
protocol: tcp
restart: alwaysBurada üç kural birlikte çalıştı. command eklenmedi, değiştirildi. environment anahtar bazında birleşti: LOG_LEVEL yeni değeri aldı, !reset null ile DEBUG silindi. !override etiketi ise ports listesini birleştirme kurallarını atlayıp tamamen değiştirdi. Aynı production dosyasından !override etiketini kaldırdığımızda çıktıda iki port girdisi vardı: 8080:80 ve 127.0.0.1:8080:80. İkisinin ip değeri farklı olduğu için benzersiz anahtar da farklıdır ve liste birleşmiştir. Port yayınlamanın güvenlik tarafı için Docker port yayınlama ve Docker ve UFW yazılarına bakın.
!reset etiketi bir değeri temizler: geçerli bir değer yazmanız gerekir ama bu değer yok sayılır ve öznitelik kendi türünün varsayılanına veya null değerine çekilir. Okunabilirlik için belirtim !reset null veya !reset [] yazmanızı önerir. !override ise özniteliği olduğu gibi değiştirir; aynı adla tamamen farklı bir tanım kullanmak istediğinizde işe yarar.
extends: bir servisin ayarlarını devralmak
extends, ortak seçenekleri bir yerde tanımlayıp birden fazla serviste kullanmanızı sağlar. Değeri zorunlu service ve isteğe bağlı file anahtarlarından oluşan bir eşlemedir. file yoksa aynı dosyadaki bir servis kastedilir; göreli file yolu ana Compose dosyasının konumuna göre çözülür. Başka bir dosyadan devraldığınızda devralınan servis son projeye girmez; yalnızca özellikleri kopyalanır. Aynı dosya içinde devraldığınızda ise iki servis de son yapılandırmada yer alır.
Belgelerdeki web uygulaması ve kuyruk işçisi örneğinden uyarladığımız ortak dosya şöyle:
services:
app:
build: .
environment:
CONFIG_FILE_PATH: /code/config
LOG_LEVEL: info
cpu_shares: 5services:
webapp:
extends:
file: common.yaml
service: app
command: /code/run_web_app
ports:
- "127.0.0.1:8080:8080"
depends_on:
- queue
queue_worker:
extends:
file: common.yaml
service: app
command: /code/run_worker
environment:
LOG_LEVEL: debug
depends_on:
- queue
queue:
image: redis:latestdocker compose config --services çıktısında yalnızca queue, queue_worker ve webapp vardı; app servisi projeye girmedi. queue_worker için birleşik ortam şuydu:
environment:
CONFIG_FILE_PATH: /code/config
LOG_LEVEL: debugextends'in birleştirme kuralı merge'e benzer ama aynı değildir. Eşlemelerde ana servisteki anahtar devralınanı ezer; environment, labels, healthcheck, deploy.resources.limits gibi anahtarlar bu gruptadır. volumes ve devices da container içindeki hedef yol anahtar kabul edilerek eşleme gibi birleşir. Dizi kabul edilen anahtarlarda (cap_add, ports, secrets, security_opt gibi) devralınan öğeler önce, ana servisinkiler sonra gelir ve tekrar eden öğeler silinir. Bunların dışındaki her şey skalerdir ve ana servis kazanır. Devralınan servisin kendisi de extends içeriyorsa süreç hiç extends kalmayana kadar tekrarlanır; döngüsel referans ise hata verir.
extends'in en sık yanlış anlaşılan kısıtı, devralınan servisin başvurduğu kaynakların otomatik gelmemesidir. Ortak dosyadaki servis bir named volume kullanıyor ve bu volume yalnızca o dosyanın en üst düzeyinde tanımlıysa, devralan dosya bunu bilmez. Denememizde Compose bu durumda şu hatayı verdi:
docker compose config --quiet
service "cli" refers to undefined volume veri: invalid compose projectÇözüm, kullanılan volume, network, secret ve config tanımlarını extends kullanan dosyaya da yazmaktır. Göreli yollar konusunda extends yardımcı olur: başka bir klasördeki dosyadan devraldığınızda o servisteki göreli yollar, aynı dosyayı göstermeye devam edecek şekilde dönüştürülür. Son olarak extends, docker stack deploy ile dağıtımda desteklenmez (bkz. Docker stack deploy).
include: başka bir Compose uygulamasını içe almak
include, en üst düzeyde bir liste olarak yazılır. Listede verilen her yol, kendi proje dizinine sahip ayrı bir Compose uygulaması olarak yüklenir ve göreli yollar o dosyanın kendi konumuna göre çözülür. Yüklenen uygulamanın tüm kaynak tanımları sizin modelinize kopyalanır; içe alınan servisleri, volume'ları ve network'leri kendi dosyanızda tanımlanmış gibi kullanabilirsiniz. include özyinelemelidir: içe alınan dosyanın kendi include bölümü varsa onlar da yüklenir.
Aşağıdaki yapıda veritabanını yöneten dosya veritabani/ klasöründe, kendi .env ve db.env dosyalarıyla birlikte duruyor. veritabani/.env içinde PG_VERSION=17 yazıyor.
services:
db:
image: "postgres:${PG_VERSION}"
env_file: ./db.env
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:include:
- ../veritabani/compose.yaml
services:
web:
build: .
depends_on:
- dbapp/ klasöründen çalıştırdığımız komutların çıktıları şöyleydi:
docker compose config --services
db
web
docker compose config --images
postgres:17
app-web
PG_VERSION=18 docker compose config --images
postgres:18
app-webBu çıktılar include'un üç özelliğini gösteriyor. db servisi yerel dosyada tanımlanmış gibi modele girdi ve depends_on ile kullanılabildi. PG_VERSION değeri, içe alınan dosyanın kendi klasöründeki .env dosyasından geldi; ./db.env yolu da veritabani/ klasörüne göre çözüldü. Yerel projenin ortamı ise o varsayılanı ezdi: kabukta PG_VERSION=18 verince imaj değişti. Belgeler include yolunda interpolasyon kullanılabileceğini de söyler ve bu durumda değişkeni :? ile zorunlu yapmayı önerir.
Uzun sözdizimi üç alan sunar. path zorunludur ve tek bir dosya ya da birleştirilecek dosyaların listesi olabilir. project_directory göreli yolların çözüleceği temel dizini belirler; varsayılanı içe alınan dosyanın dizinidir. env_file interpolasyon varsayılanlarını verecek ortam dosyasıdır; varsayılanı project_directory içindeki .env dosyasıdır ve liste olarak birden fazla dosya verilebilir. Üçüncü taraf bir dosyayı kendi ihtiyacınıza göre değiştirmek için path listesine bir override dosyası ekleyebilirsiniz:
include:
- path:
- third-party/compose.yaml
- override.yaml
env_file: ./cache.env
services:
web:
image: nginx:latest
depends_on:
- cacheÜçüncü taraf dosyada image: "redis:${REDIS_TAG:-7}" ve "6379:6379" portu, override.yaml dosyasında ports: !override ile "127.0.0.1:6379:6379", cache.env dosyasında REDIS_TAG=8 vardı. Birleşik çıktıda cache servisi image: redis:8 ve yalnızca host_ip: 127.0.0.1 olan tek port girdisiyle geldi. Belgelerin belirttiği sınırlama, her include için ayrı bir override dosyası tutmanın karmaşık projelerde çok sayıda dosyaya yol açmasıdır. Diğer seçenek compose.override.yaml kullanmaktır: include sonucu oluşan birleşik model, genel override dosyasıyla yine değiştirilebilir.
Ad çakışmaları konusunda dikkatli olun. Belirtim, içe alınan bir kaynakla aynı adı taşıyan yerel bir tanım olduğunda Compose'un bunları birleştirmeye çalışmayıp uyarı verdiğini, how-to sayfası ise bu durumu hata olarak bildirdiğini söyler. Bizim Compose v5.5.1 denememizde içe alınan dosyada ve yerel dosyada aynı adlı redis servisi varken docker compose config hata ya da uyarı vermedi ve iki tanımı birleştirerek yerel dosyadaki imajı kullandı. Bu davranışa güvenmeyin; servis adlarını benzersiz tutun ve sonucu config ile kontrol edin. Belgeler include'un OCI artifact veya Git deposu gibi uzak kaynaklardan dosya alabildiğini de belirtir; böyle bir kaynağı kullanmadan önce içeriğini incelemeniz iyi olur.
Fragment ve extension alanları: dosya içinde tekrarı azaltmak
Aynı dosyada tekrar eden blokları YAML anchor ve alias'larıyla tek yerde tanımlayabilirsiniz. Anchor &ad ile oluşturulur, *ad ile kullanılır; işaret ile ad arasında boşluk olmamalıdır. Bu blokları servislerin dışında tutmak için x- ile başlayan extension alanları kullanılır; Compose bu alanları yok sayar. YAML merge anahtarı << ile bir anchor'ı kısmen ezebilir veya ona yeni anahtarlar ekleyebilirsiniz.
x-ortak: &ortak
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
x-env: &varsayilan-env
TZ: Europe/Istanbul
LOG_LEVEL: info
services:
api:
<<: *ortak
image: example/api:1.4
environment:
<<: *varsayilan-env
LOG_LEVEL: debug
worker:
<<: *ortak
image: example/worker:1.4
environment: *varsayilan-envÇözülmüş modelde iki servis de restart: unless-stopped ve aynı log ayarlarını aldı; api için LOG_LEVEL: debug, worker için LOG_LEVEL: info geldi. Log sürücüsü seçenekleri Docker log boyutu sınırlama yazısında anlatılıyor. YAML merge yalnızca eşlemelerde çalışır, dizilerde çalışmaz. Bu yüzden ortam değişkenlerini fragment ile paylaşacaksanız FOO: BAR eşleme biçimini kullanmalısınız; - FOO=BAR liste biçimindeki bir anchor'ı << ile birleştirmeye çalıştığımızda Compose dosyayı map merge requires map or sequence of maps as the value hatasıyla reddetti. Anchor çözümlemesi interpolasyondan önce yapıldığı için anchor adlarını değişkenle de oluşturamazsınız (bkz. Compose değişken interpolasyonu).
Sık yapılan hatalar

- Override dosyasındaki yolu kendi konumuna göre yazmak. Merge'de tüm yollar temel dosyaya göredir.
- Port listesinin değiştiğini sanmak.
portsbirleşir; eski portu kaldırmak için!overrideveya!resetgerekir. - command listesinin eklendiğini sanmak.
command,entrypointvehealthcheck.testher zaman son dosyadakiyle değişir. - extends ile volume ve network'lerin geleceğini varsaymak. Başvurulan kaynakları devralan dosyada da tanımlayın.
- include ile aynı adlı servis tanımlamak. Belgeler bunu çakışma sayar; sürüm davranışına güvenmek yerine adları ayırın.
- Liste biçimli anchor'ı birleştirmek.
<<yalnızca eşlemelerle çalışır. - Swarm'da extends kullanmak.
docker stack deployextends desteklemez.
Sık Sorulan Sorular
compose.override.yaml her zaman okunur mu?
-f vermediğinizde Compose, compose.yaml ile aynı düzeyde bulunan compose.override.yaml dosyasını kendiliğinden birleştirir. -f compose.yaml -f compose.prod.yaml gibi açıkça dosya verdiğinizde yalnızca verdiğiniz dosyalar kullanılır.
include mı extends mi kullanmalıyım?
Bir servisin ayarlarını başka servislerle paylaşmak istiyorsanız extends; başka bir ekibin veya bileşenin bütün Compose uygulamasını, kendi yollarını ve değişkenlerini koruyarak kullanmak istiyorsanız include uygundur.
Birleşik sonucu nasıl görürüm?
Aynı -f bayraklarıyla docker compose config çalıştırın. Yalnızca servis adları için --services, imajlar için --images bayrakları kısa ve okunaklı çıktı verir.
x- alanları container'a bir şey ekler mi?
Hayır. Compose x- ile başlayan alanları yok sayar; bu alanlar yalnızca anchor ile paylaşılacak blokları tutmak için kullanılır.
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 değişken interpolasyonu · Compose secrets ve configs · Compose deploy ve kaynak limitleri