Docker Compose Nedir Ve Nasıl Kullanılır ?


Docker Compose Nedir? docker-compose.yml Dosyası ve Temel Key'ler

Docker ile çalışmaya başladığımda container'ları tek tek docker run komutlarıyla oluşturmak ve çalıştırmak bir noktadan sonra oldukça zahmetli hale gelebiliyor. Özellikle bir uygulamanın birden fazla container'a ihtiyacı varsa, her container için kullandığım komutları tek tek hatırlamak ve tekrar çalıştırmak yerine bunları bir dosyada tanımlamak çok daha pratik oluyor.

Docker Compose tam olarak bu noktada devreye giriyor. Docker Compose ile container oluşturma, image kullanma veya build etme, port mapping, volume mapping, environment variable tanımlama ve container'lar arasındaki bağlantıları tek bir yapı üzerinden yönetebiliyorum.

Kısacası daha önce terminal üzerinden yazdığım birçok Docker komutunu bir YAML dosyasında tanımlayıp, daha sonra tek bir komutla uygulayabiliyorum.


Docker Compose Ne İşe Yarar?

Docker Compose'u, Docker üzerinde çalıştıracağım uygulamanın bütün yapılandırmasını tek bir yerde toplamak için kullanıyorum.

Örneğin bir uygulamamın;

  • Bir frontend container'ına,
  • Bir backend container'ına,
  • Bir MongoDB veya MySQL container'ına

ihtiyacı varsa, bunların her birini ayrı ayrı docker run komutlarıyla çalıştırmak yerine Docker Compose dosyasında tanımlayabiliyorum.

Daha sonra aşağıdaki komutla bütün yapıyı çalıştırmak mümkün:

docker compose up -d

Böylece daha önce yazdığım uzun komut zincirlerini tekrar tekrar yazmak zorunda kalmıyorum.


docker-compose.yml Dosyası

Docker Compose kullanmak için öncelikle genellikle docker-compose.yml isimli bir YAML dosyası oluşturuyorum.

Yeni Docker Compose sürümlerinde dosya adı yine bu şekilde kullanılabilmekle birlikte, Compose Specification nedeniyle artık version alanını kullanmak çoğu durumda zorunlu değildir.

Dosyanın temel yapısı key : value şeklindedir. YAML kullandığımız için girintilere de dikkat etmek gerekiyor.

Eğer bir key'in değeri liste (array) şeklindeyse, alt satırlarda - işareti kullanarak değerleri belirtiyoruz.

Örneğin:

ports:
  - "3000:3000"
  - "8080:8080"

Buradaki ports bir liste olduğu için her port mapping işlemini ayrı bir satırda - işaretiyle belirtiyoruz.


Docker Compose Temel Yapısı

Basit bir Docker Compose dosyasının yapısı genel olarak şu şekilde düşünülebilir:

services:
  todo-app:
    build: .
    container_name: todo-app
    ports:
      - "3000:3000"

mongodb:
image: mongo
container_name: mongodb
ports:
- "27017:27017"

Burada iki farklı servis tanımladık: todo-app ve mongodb. Docker Compose bu servisleri ayrı container'lar olarak oluşturup yönetebilir.


Bazı Önemli Docker Compose Key'leri

version

Docker Compose'un geçmiş sürümlerinde kullanılan version alanı, Compose dosyasının hangi format/sürüm şemasına göre değerlendirileceğini belirtmek için kullanılıyordu.

Docker Compose'un güncel kullanımında ise Compose Specification ön plana çıktığı için version alanı çoğu durumda gerekli değildir. Eski kaynaklarda örneğin aşağıdaki gibi bir kullanım görebiliriz:

version: "3.8"

Dolayısıyla internette farklı Docker Compose örneklerinde farklı version değerleriyle karşılaşmam normal. Özellikle eski Docker Compose içeriklerini incelerken bu alanın neden kullanıldığını bilmek faydalı oluyor.


services

Docker Compose dosyasının en önemli bölümlerinden biri services alanıdır.

Burada çalıştırmak istediğimiz uygulamaları, yani servislerimizi tanımlıyoruz. Her servis genellikle ayrı bir container olarak çalıştırılır.

Örneğin:

services:
  todo-app:
    build: .

mongodb:
image: mongo

Burada todo-app ve mongodb olmak üzere iki servis tanımladık.

Docker Compose servisler için kendi network yapısını oluşturduğu için servisler birbirleriyle servis adı üzerinden iletişim kurabilir.

Örneğin todo-app içerisinden MongoDB'ye bağlanırken genellikle localhost yerine servis adını kullanırım:

mongodb:27017

Burada mongodb, Compose dosyasında tanımladığımız servis adıdır. Bu nedenle servis adlarını belirlerken uygulamanın diğer servisleri tarafından nasıl kullanılacağını da düşünmek gerekiyor.

Not: MongoDB'nin varsayılan portu 27017'dir. Bu nedenle 21017 yerine 27017 kullanılması gerekir.


build

build key'ini, kendi Docker image'ımızı bir Dockerfile üzerinden oluşturmak istediğimizde kullanıyoruz.

Örneğin Dockerfile dosyamız ile docker-compose.yml aynı klasördeyse:

services:
  todo-app:
    build: .

Buradaki ., Dockerfile'ın bulunduğu mevcut klasörü build context olarak kullanacağımızı ifade eder.

Böylece Compose'u çalıştırdığımda Dockerfile kullanılarak image build edilebilir.

Örneğin:

docker compose up -d --build

Bu komutla gerekli durumda image'ın yeniden build edilmesini de sağlayabiliyorum.


image

Eğer elimizde zaten bulunan veya Docker Registry üzerinden çekilebilecek hazır bir image'ı kullanmak istiyorsak image key'ini kullanıyoruz.

Örneğin MongoDB için:

services:
  mongodb:
    image: mongo

Belirli bir image tag'i kullanmak istersem onu da belirtebilirim:

services:
  redis:
    image: redis:7

Burada Docker, redis image'ının 7 tag'ini kullanacaktır.

Kısaca build kendi Dockerfile'ımdan image oluşturmak için, image ise hazır bir image kullanmak için tercih ediliyor.


ports

ports key'i ile container'ın port mapping ayarlarını yapabiliyoruz.

Daha önce Docker'da port mapping için kullandığımız:

docker run -p 3000:3000 ...

işlemini Compose içerisinde şu şekilde tanımlayabiliriz:

services:
  todo-app:
    ports:
      - "3000:3000"

Burada ilk port Docker Host üzerinde erişilecek portu, ikinci port ise container içerisindeki portu ifade eder.

Birden fazla port mapping yapmamız gerekiyorsa her birini ayrı satırda tanımlayabiliriz:

ports:
  - "3000:3000"
  - "8080:8080"

container_name

container_name key'i ile oluşturulacak container'a kendimiz bir isim verebiliriz.

Örneğin:

services:
  mongodb:
    image: mongo
    container_name: my-mongodb

Bu durumda oluşturulan container'ın adı my-mongodb olacaktır.

Böylece container'ı yönetirken bu ismi kullanabilirim:

docker stop my-mongodb
docker start my-mongodb
docker logs my-mongodb

Burada küçük bir not olarak, Compose projelerinde container_name kullanmak her zaman gerekli değildir. Compose zaten container'ları kendisi isimlendirir. Ancak özellikle container adına doğrudan erişmek istediğim durumlarda kullanışlı olabiliyor.


volumes

volumes key'i ile container'ın kalıcı veri ihtiyacını ve volume mapping işlemlerini yönetebiliriz.

Örneğin daha önce Docker'da:

docker run -v /opt/data:/data/db mongo

şeklinde yaptığımız volume mapping işlemini Compose içerisinde şu şekilde tanımlayabiliriz:

services:
  mongodb:
    image: mongo
    volumes:
      - /opt/data:/data/db

Burada /opt/data Docker Host üzerindeki klasör, /data/db ise container içerisindeki klasördür.

Birden fazla volume mapping yapacaksak yine liste yapısını kullanıyoruz:

volumes:
  - /opt/data:/data/db
  - /opt/logs:/var/log/app

Named Volume Kullanımı

Docker Compose içerisinde host üzerindeki belirli bir klasörü doğrudan göstermek yerine named volume da kullanabiliriz.

Bu durumda volume'ü Compose dosyasının en dış seviyesinde tanımlıyoruz:

services:
  mongodb:
    image: mongo
    volumes:
      - mongo-data:/data/db

volumes:
mongo-data:

Burada mongo-data Docker tarafından yönetilen named volume'dür. Container silinse bile volume ayrıca silinmediği sürece veriler korunabilir.

Yani burada iki farklı kullanım görebiliriz:

Yöntem Örnek Kullanım
Bind Mount /opt/data:/data/db Host üzerindeki belirli bir klasörü container'a bağlamak
Named Volume mongo-data:/data/db Docker tarafından yönetilen kalıcı volume kullanmak

Docker Compose ile Servisleri Birlikte Çalıştırmak

Docker Compose'un benim için en önemli avantajlarından biri, birden fazla container'ın birlikte çalışmasını kolaylaştırması.

Örneğin bir backend uygulamam ve MongoDB database'im olduğunu düşünelim:

services:
  todo-app:
    build: .
    ports:
      - "3000:3000"

mongodb:
image: mongo
volumes:
- mongo-data:/data/db

volumes:
mongo-data:

Bu yapıda todo-app kendi Dockerfile'ından build edilirken, mongodb hazır MongoDB image'ını kullanıyor.

Ayrıca iki servis aynı Compose ağı içerisinde çalıştığı için backend tarafından MongoDB'ye servis adı üzerinden ulaşılabilir:

mongodb:27017

Burada önemli nokta şu: container'lar birbirleriyle iletişim kurarken host üzerinde yaptığımız port mapping'e ihtiyaç duymaz. Port mapping daha çok host dışından container'a erişmek istediğimiz durumlarda kullanılır.


Docker Compose ile Çalıştırma

docker-compose.yml dosyamızı hazırladıktan sonra artık container'ları tek tek çalıştırmak yerine Compose üzerinden yönetebiliriz.

Container'ları oluşturup arka planda çalıştırmak için:

docker compose up -d

Dockerfile'da yaptığım değişikliklerin image'a yansıması için build işlemini de zorlamak istersem:

docker compose up -d --build

Çalışan Compose servislerini durdurmak için:

docker compose down

Böylece daha önce ayrı ayrı yazmam gereken birçok Docker komutunu tek bir Compose dosyası üzerinden yönetebiliyorum.


Özet

Docker Compose kullanırken en sık karşılaşacağımız key'leri kısaca şöyle özetleyebiliriz:

Key Görevi
services Çalıştırılacak servisleri/container'ları tanımlar.
build Dockerfile kullanılarak image oluşturulmasını sağlar.
image Hazır bir Docker image'ının kullanılmasını sağlar.
ports Host ile container arasındaki port mapping işlemini tanımlar.
container_name Container'a özel bir isim verilmesini sağlar.
volumes Bind mount veya named volume kullanarak kalıcı veri yönetimini sağlar.
version Eski Compose dosya formatlarında sürüm belirtmek için kullanılır; güncel Compose Specification'da çoğu durumda gerekli değildir.

Benim açımdan Docker Compose'un en büyük avantajı, Docker ile ilgili birçok ayarı tek bir dosyada tutabilmek. Özellikle birden fazla container'ın birlikte çalıştığı projelerde build, image, ports, volumes ve servisler arası bağlantıları tek bir docker-compose.yml dosyasından yönetmek, projeyi hem tekrar çalıştırmayı hem de başka bir makinede kurmayı oldukça kolaylaştırıyor.

Daha yeni Daha eski