Docker Compose ile Çoklu Konteyner Geliştirme Ortamı Kurulumu: Adım Adım Rehber
Modern yazılım projelerinde uygulamalar artık tek başına çalışan monolitler değil; birbirleriyle konuşan, veri paylaşan ve birlikte çalışan servislerden oluşuyor. Bir web uygulamasını düşünün: arka planda bir veritabanı, oturumları yöneten bir cache mekanizması, belki asenkron işleri işleyen bir kuyruk sistemi… Her birini ayrı ayrı Docker container'ları ile çalıştırmak mümkün, peki ya bu parçaları tek bir komutla, tanımlı bir düzen içinde ayağa kaldırmak istersek? İşte tam bu noktada Docker Compose devreye giriyor. Bu Docker Compose kurulum rehberi, size çoklu konteynerli geliştirme ortamlarını nasıl kolayca yönetebileceğinizi, adım adım ve uygulamalı bir örnekle gösterecek.
Docker temellerine hakimseniz, yani image, container ve Dockerfile kavramlarını biliyorsanız, bu yazı sizin için doğal bir sonraki adım olacak. Signalique’in daha önce yayınladığı "Docker ile Konteynerleştirme" başlangıç rehberini okuduysanız, şimdi öğrendiklerinizi çoklu konteyner dünyasına taşımanın tam zamanı.
Docker Compose Nedir ve Neden Kullanmalısınız?
Docker Compose, Docker ile birlikte gelen resmi bir araçtır. Temel amacı, birden fazla container’dan oluşan uygulamaları tanımlamak ve yönetmek için gereken konfigürasyonu tek bir YAML dosyasında (compose.yml ya da eski adıyla docker-compose.yml) toplamaktır. V2 sürümüyle birlikte artık docker compose komutu (tire işareti olmadan) standart hale gelmiştir ve bu yazıda da V2 sözdizimini kullanacağız.
Peki neden tek tek docker run komutları vermek yerine Compose kullanalım?
- Tutarlılık: Tüm servislerin nasıl başlayacağı, hangi portları kullanacağı, hangi çevre değişkenlerine sahip olacağı bir dosyada tanımlanır. Ekibinizdeki herkes aynı dosyayı kullanarak birebir aynı ortamı ayağa kaldırabilir.
- Bağımlılık Yönetimi: Hangi servisin hangi sırayla başlayacağını tanımlayabilirsiniz. Örneğin, uygulamanızın veritabanı hazır olmadan çalışmaya başlamasını istemezsiniz.
- Tek Komutla Yönetim:
docker compose updiyerek tüm sistemi başlatabilir,docker compose downile tamamen durdurabilirsiniz. - Geliştirme Hızı: Lokal geliştirme ortamlarını saniyeler içinde ayağa kaldırabilir, yeni katılan ekip arkadaşlarının onboarding süresini ciddi ölçüde kısaltabilirsiniz.
Özetle: Tek bir container’la çalışırken Docker komutları yeterli olabilir. Ancak sisteminiz büyüdükçe, konteynerleri bir orkestra şefi gibi yönetecek bir araca ihtiyacınız olur. İşte Compose tam olarak bunu yapar.
Compose Dosyasının Anatomisi: compose.yml
Bir Compose dosyası üç ana yapı taşından oluşur: services, networks ve volumes. Gelin her birini yakından inceleyelim.
- services: Sisteminizi oluşturan her bir container bir servis olarak tanımlanır. Hangi imajın kullanılacağı, hangi portların eşleneceği, çevre değişkenleri gibi tüm ayarlar bu bölümde yer alır.
- networks: Servisler arasındaki iletişimi sağlayan sanal ağları tanımlar. Varsayılan olarak Compose, tüm servislerin birbiriyle servis adları üzerinden haberleşebileceği ortak bir ağ oluşturur. Özel ağ ihtiyaçlarınız varsa burada tanımlayabilirsiniz.
- volumes: Verilerin kalıcı olması gereken durumlar için kullanılır. Örneğin bir veritabanı container’ını yeniden başlattığınızda verilerin kaybolmaması için bir volume’e ihtiyacınız olur.
Basit bir compose.yml dosyası şu şekilde görünebilir:
services:
web:
image: nginx:latest
ports:
- "8080:80"
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: sifre123
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Adım Adım Örnek Senaryo: Node.js + PostgreSQL + Redis
Şimdi teoriden pratiğe geçelim. Gerçek bir senaryo üzerinden ilerleyelim: Bir Node.js uygulaması, arka planda PostgreSQL veritabanı ve oturum/önbellek yönetimi için Redis kullanan üçlü bir mimariyi Docker Compose ile ayağa kaldıracağız.
1. Proje Yapısını Oluşturun
Öncelikle basit bir proje dizini oluşturalım:
myapp/
├── app/
│ ├── package.json
│ └── server.js
├── Dockerfile
└── compose.yml
app/server.js – Express ile basit bir API:
const express = require('express');
const { Pool } = require('pg');
const redis = require('redis');
const app = express();
const port = 3000;
const pool = new Pool({
host: process.env.DB_HOST || 'db',
user: process.env.DB_USER || 'postgres',
password: process.env.DB_PASSWORD || 'postgres',
database: process.env.DB_NAME || 'myapp',
});
const redisClient = redis.createClient({
url: `redis://${process.env.REDIS_HOST || 'cache'}:6379`,
});
redisClient.connect();
app.get('/', async (req, res) => {
const visits = await redisClient.incr('visits');
res.send(`Merhaba Dünya! Bu sayfa ${visits} kez ziyaret edildi.`);
});
app.listen(port, () => {
console.log(`Uygulama http://localhost:${port} adresinde çalışıyor`);
});
package.json içinde express, pg ve redis bağımlılıklarını ekleyin.
2. Dockerfile Hazırlayın
Dockerfile uygulamamızın imajını oluşturacak:
FROM node:18-alpine
WORKDIR /app
COPY app/package*.json ./
RUN npm install
COPY app/ .
CMD ["node", "server.js"]
EXPOSE 3000
3. compose.yml Dosyasını Yazın
Gelelim işin kalbine. Üç servisi tanımlayalım:
services:
web:
build: .
ports:
- "3000:3000"
environment:
DB_HOST: db
DB_USER: postgres
DB_PASSWORD: postgres
DB_NAME: myapp
REDIS_HOST: cache
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
pgdata:
Burada dikkat etmeniz gereken birkaç önemli nokta var:
depends_onileconditionkullanımı: Servis bağımlılıklarını tanımlarkendepends_ontek başına container’ın başladığını garanti etse de, uygulamanın hazır olduğunu garanti etmez.condition: service_healthykullanarak, web servisimizin ancak PostgreSQL servisi healthcheck’ten başarıyla geçtikten sonra başlamasını sağlıyoruz. Bu, “veritabanı bağlantısı reddedildi” gibi hataların önüne geçer.- Servis isimleri ağ adresi olur: Uygulama kodunda veritabanına
dbhost adıyla, Redis’e isecachehost adıyla bağlanıyoruz. Compose, her servis adını otomatik olarak DNS’e ekler, böylece IP adresiyle uğraşmanıza gerek kalmaz.
4. Sistemi Başlatın ve Test Edin
Artık her şey hazır. Tek bir komutla tüm sistemi başlatabilirsiniz:
docker compose up -d
Bu komut, önce imajları oluşturacak (ya da hazır imajları indirecek), ardından tüm servisleri doğru sırayla başlatacak ve container’lar arası ağ iletişimini otomatik olarak kuracaktır. Tarayıcınızdan http://localhost:3000 adresine gittiğinizde ziyaret sayacının her yenilemede arttığını göreceksiniz. Redis sayesinde bu sayaç container’ı yeniden başlatsanız bile sıfırlanmaz (volume kullanırsanız).
Sık Kullanılan Docker Compose Komutları
Compose ile çalışırken en sık ihtiyaç duyacağınız komutları bilmek, iş akışınızı hızlandırır. İşte elinizin altında bulunması gerekenler:
| Komut | Görevi |
|---|---|
docker compose up -d |
Tüm servisleri arka planda başlatır. |
docker compose down |
Tüm container’ları durdurur ve siler. Varsayılan olarak volume’leri silmez; silmek için -v ekleyin. |
docker compose build |
Servislerin imajlarını yeniden oluşturur. Kod değişikliğinden sonra --build bayrağı ile birlikte kullanılır. |
docker compose logs -f |
Tüm servislerin loglarını canlı olarak takip eder. Belirli bir servis için docker compose logs -f web kullanabilirsiniz. |
docker compose exec web sh |
Belirtilen servis container’ı içinde interaktif bir kabuk açar. Hata ayıklama için idealdir. |
docker compose ps |
Çalışan container’ların durumunu listeler. |
docker compose restart cache |
Sadece belirtilen servisi yeniden başlatır. |
docker compose stop |
Servisleri durdurur ancak container’ları silmez. start ile tekrar başlatabilirsiniz. |
Docker Compose V2 Özellikleri ve İpuçları
Compose V2, klasik docker-compose (Python ile yazılmış) yerine Go ile yazılmış ve Docker CLI’a tam entegre olmuş yeni nesildir. Bu geçişin getirdiği bazı avantajlar şunlardır:
docker composekomutu: Artık tire işareti olmadan, doğrudan Docker komutunun bir alt komutu olarak çalışır. Eskidocker-composehala desteklenir, ancak yeni projelerde V2 kullanmanız önerilir.watchmodu (deneysel): Compose V2.22 ile gelen bu özellik, dosya değişikliklerini izleyerek container içinde otomatik güncelleme yapmanıza olanak tanır. Örneğin bir Node.js projesinde kaynak kodu değiştiğinde container’ı yeniden başlatmadan değişiklikleri senkronize edebilirsiniz.compose.ymliçinde şu şekilde tanımlanır:
services:
web:
build: .
develop:
watch:
- action: sync
path: ./app
target: /app
- action: rebuild
path: package.json
Bu yapılandırma ile docker compose watch komutunu çalıştırdığınızda, ./app dizinindeki değişiklikler container içine anında yansır, package.json değişirse container yeniden build edilir. Neredeyse hot-reload benzeri bir deneyim sunar.
Sonuç
Docker Compose ile çoklu konteyner geliştirme ortamı kurmak, başlangıçta karmaşık görünse de bir kez kavrandığında yazılım geliştirme sürecinizi kökten değiştirecek bir beceridir. Geliştirme ortamlarının ekip içinde tutarlı olması, yeni katılan geliştiricilerin dakikalar içinde kod yazmaya başlayabilmesi ve "benim bilgisayarımda çalışıyordu" problemine kesin çözüm getirmesi, Compose'u vazgeçilmez kılar.
Bu yazıda öğrendikleriniz, Docker yolculuğunuzda önemli bir kilometre taşıdır. Eğer Docker temellerini henüz tazelemek isterseniz, Signalique’in "Docker ile Konteynerleştirme: Adım Adım Başlangıç Rehberi" başlıklı yazısına göz atabilir, oradan kaldığınız yerden bu anlatılanları daha da pekiştirebilirsiniz.
Şimdi sıra sizde: İlk compose.yml dosyanızı oluşturun, docker compose up deyin ve çoklu konteyner dünyasının kapılarını aralayın!