Docker Swarm — Temel Cluster Yönetimi
Bir önceki derste orchestration'ın neden gerekli olduğunu, temel kavramları ve Swarm ile Kubernetes arasındaki farkları gördük. Şimdi Docker Swarm'ı uygulamalı olarak öğrenme zamanı. Bu derste bir Swarm cluster'ı kuracağız, servisler oluşturacağız, ölçekleyeceğiz ve zero-downtime güncelleme yapacağız.
Restoran Zinciri Analojisi
Tek şubeli bir restoran düşün. Her şeyi sen yönetirsin — sipariş al, pişir, servis yap. Ama zincir büyüdüğünde merkezi bir yönetim lazım: hangi şubeye kaç aşçı atanacak, biri hastalanırsa yerine kim gelecek, yeni menü tüm şubelere nasıl dağıtılacak?
Docker Swarm, Docker'ın kendi bünyesindeki bu "restoran zinciri yönetimi" aracı. Birden fazla sunucuyu tek bir cluster gibi yönetir. Ve en güzel tarafı? Zaten bildiğin Docker komutlarının üzerine inşa edilmiş — yepyeni bir dünya öğrenmiyorsun, mevcut bilgini genişletiyorsun.
Swarm Mode Nedir?
Docker Engine'in içinde gömülü gelen orchestration özelliği. Ek kurulum gerekmez — docker swarm init dediğin anda aktif olur. Bu, Swarm'ın en büyük avantajı: sıfır kurulum karmaşıklığı.
Temel kavramları hızlıca tanıyalım:
Node: Swarm cluster'ına katılmış bir Docker host (sunucu). İki rolü var — Manager ve Worker.
Manager Node: Cluster'ı yöneten, kararları alan node. API isteklerini karşılar, scheduling yapar, cluster durumunu saklar.
Worker Node: Container'ları çalıştıran node. Manager'dan aldığı görevleri yerine getirir.
Service: Çalıştırmak istediğin uygulamanın tanımı. "3 tane Nginx çalıştır, 80 portunda" gibi.
Task: Bir service'in tek bir container instance'ı.
Cluster Kurulumu: Adım Adım
Hadi bir Swarm cluster'ı kuralım. Üç sunucumuz olduğunu varsayalım:
192.168.1.10→ Manager192.168.1.11→ Worker 1192.168.1.12→ Worker 2
Adım 1: İlk Manager'ı Başlat
İlk sunucuda Swarm'ı başlat:
docker swarm init --advertise-addr 192.168.1.10Bu komut çalıştığında çıktıda bir join komutu göreceksin — bunu kopyala, çünkü diğer sunucularda kullanacaksın:
Swarm initialized: current node (dxn1zf6l61qsb1josjja6e8pz) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-49nj1cmql0... 192.168.1.10:2377Tebrikler — artık bir Swarm cluster'ın var! Şu anda tek node'lu ama yine de çalışan bir cluster.
Adım 2: Worker Node'ları Ekle
Diğer sunuculara git ve join komutunu çalıştır:
# Worker 1'de
docker swarm join --token SWMTKN-1-49nj1cmql0... 192.168.1.10:2377
# This node joined a swarm as a worker.
# Worker 2'de
docker swarm join --token SWMTKN-1-49nj1cmql0... 192.168.1.10:2377
# This node joined a swarm as a worker.Bu kadar! Şimdi manager node'da cluster'ı kontrol edelim:
docker node lsÇıktı şöyle bir şey olacak:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
dxn1zf6l61qsb * manager1 Ready Active Leader
j8a4f3h2k5n7... worker1 Ready Active
k9b5g4i3l6o8... worker2 Ready ActiveÜç node'lu bir cluster'ın hazır. * işareti şu anda hangi node'da olduğunu gösteriyor. "Leader" ise aktif manager'ı belirtiyor.
Yüksek Erişilebilirlik: Birden Fazla Manager
Production'da tek manager tehlikeli — çökerse cluster yönetilemez hale gelir. Bu yüzden birden fazla manager kullanırsın. Manager'lar kendi aralarında Raft consensus algoritması ile çalışır — çoğunluk (quorum) sağlandığı sürece cluster çalışmaya devam eder.
Manager sayısı her zaman tek olmalı — 1, 3, 5 veya 7. Neden? Çünkü quorum hesabı (n/2 + 1) çift sayılarda avantaj sağlamaz:
3 manager → 1 çökebilir (quorum: 2)
5 manager → 2 çökebilir (quorum: 3)
7 manager → 3 çökebilir (quorum: 4)
Production için 3 veya 5 manager önerilir.
# Ek manager eklemek için önce token'ı al
docker swarm join-token manager
# Yeni sunucuda bu token ile join et
docker swarm join --token SWMTKN-1-...-manager-token 192.168.1.10:2377İlk Servisimizi Oluşturalım
Swarm'da docker run yerine docker service create kullanırsın. Aralarındaki fark çok önemli: docker run tek bir container başlatır ve o kadar. docker service create ise istenen durumu tanımlar — Swarm bu durumu sürdürür.
docker service create \
--name web \
--replicas 3 \
--publish 80:80 \
nginx:alpineBu komut ne yaptı? Swarm'a "web adında bir servis oluştur, 3 replica olsun, dış dünyaya 80 portunda aç" dedin. Swarm bu 3 container'ı cluster'daki node'lara dağıttı.
Kontrol edelim:
docker service lsID NAME MODE REPLICAS IMAGE PORTS
r3k2... web replicated 3/3 nginx:alpine *:80->80/tcp3/3 demek 3 container'dan 3'ü de çalışıyor. Hangi node'da çalıştıklarını görmek için:
docker service ps webID NAME IMAGE NODE DESIRED STATE CURRENT STATE
abc... web.1 nginx:alpine manager1 Running Running 2 min ago
def... web.2 nginx:alpine worker1 Running Running 2 min ago
ghi... web.3 nginx:alpine worker2 Running Running 2 min agoGördüğün gibi, Swarm her node'a bir container dağıtmış. Şimdi worker1'i kapat ve neler olduğunu gör:
# Worker1'de
sudo systemctl stop docker
# Manager'da kontrol et
docker service ps webSwarm, worker1'deki container'ın çöktüğünü algılar ve otomatik olarak başka bir node'da yeni bir container başlatır. Bu self-healing — kendi kendini iyileştirme.
Scaling: Ölçeklendirme
Trafik arttı ve 3 replica yetmiyor? Bir komutla ölçekle:
docker service scale web=5İki yeni container otomatik olarak uygun node'lara dağıtılır. Trafik azaldığında geri küçült:
docker service scale web=2Birden fazla servisi aynı anda ölçekleyebilirsin:
docker service scale web=5 api=3 worker=10Rolling Update: Sıfır Kesinti Güncelleme
Bu, Swarm'ın en güçlü özelliklerinden biri. Diyelim ki Nginx'in yeni versiyonuna geçmek istiyorsun:
docker service update \
--image nginx:1.26-alpine \
--update-parallelism 1 \
--update-delay 10s \
--update-failure-action rollback \
--update-order start-first \
webBu parametreleri açıklayalım:
--image nginx:1.26-alpine— yeni image--update-parallelism 1— aynı anda 1 container güncelle--update-delay 10s— her güncelleme arasında 10 saniye bekle--update-failure-action rollback— hata olursa otomatik geri al--update-order start-first— önce yenisini başlat, sonra eskisini kaldır
start-first özellikle önemli. Bu ayarla, yeni container başlatılır ve sağlıklı olduğu kontrol edilir, ancak ondan sonra eski container durdurulur. Böylece her an en az istenen sayıda container aktif kalır — kullanıcılar hiçbir kesinti yaşamaz.
Bir sorun olursa? Manuel rollback:
docker service rollback webBir komutla önceki versiyona geri dönersin.
Overlay Network: Node'lar Arası İletişim
Tek sunucuda bridge network kullanıyorduk. Ama farklı sunuculardaki container'lar nasıl konuşacak? İşte burada overlay network devreye giriyor.
Overlay network, farklı node'lardaki container'ları sanki aynı ağdaymış gibi birbirine bağlar:
# Overlay network oluştur
docker network create --driver overlay my-network
# Backend için internal overlay (dış erişim yok)
docker network create --driver overlay --internal backendServisler bu network'ler üzerinden birbirleriyle konuşur:
docker service create \
--name api \
--network frontend \
--network backend \
myapp:v1.0
docker service create \
--name db \
--network backend \
postgres:16API servisi hem frontend hem backend network'üne bağlı — dışarıdan erişilebilir ve veritabanıyla konuşabilir. Veritabanı ise sadece backend network'ünde — dışarıdan erişilemez, sadece API ile konuşabilir.
Swarm ayrıca routing mesh (ingress network) sağlar. Bu, herhangi bir node'un IP'sine gelen trafiği doğru container'a yönlendirir:
Client → herhangi bir node:80 → Routing Mesh → doğru containerYani 3 node'un var ve web servisi sadece worker1'de çalışıyor olsa bile, worker2'nin IP'sine 80 portuna istek yapsan, routing mesh bu isteği worker1'deki container'a yönlendirir. Kullanıcının hangi node'a bağlandığı önemli değil.
Swarm Secrets: Güvenli Konfigürasyon
Bir önceki bölümde secret management'ı öğrenmiştik. Swarm'ın kendi dahili secret mekanizması var ve oldukça güçlü — secret'ları şifreli olarak Raft store'da saklar:
# Secret oluştur
echo "supersecretpassword" | docker secret create db_password -
# Servis oluştururken secret'ı bağla
docker service create \
--name api \
--secret db_password \
myapp:v1.0Container içinde secret /run/secrets/db_password dosyası olarak görünür. docker inspect ile görünmez — güvenli.
Stack Deploy: Compose Benzeri Tanımlama
Tek tek servis oluşturmak zahmetli. Stack, Docker Compose benzeri YAML dosyasıyla tüm uygulamanı tek komutla deploy etmeni sağlar:
# docker-stack.yml
version: "3.8"
services:
web:
image: nginx:alpine
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
resources:
limits:
cpus: "0.5"
memory: 256M
ports:
- "80:80"
networks:
- frontend
api:
image: myapp:v1.0
deploy:
replicas: 2
resources:
limits:
memory: 512M
secrets:
- db_password
networks:
- frontend
- backend
db:
image: postgres:16-alpine
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
volumes:
- pgdata:/var/lib/postgresql/data
secrets:
- db_password
networks:
- backend
secrets:
db_password:
external: true
volumes:
pgdata:
networks:
frontend:
backend:
driver: overlay
internal: trueDeploy etmek tek komut:
docker stack deploy -c docker-stack.yml myappStack durumunu kontrol etmek:
docker stack ls
docker stack services myapp
docker stack ps myappGüncellemek? YAML dosyasını değiştir ve aynı komutu tekrar çalıştır — Swarm sadece değişen kısımları günceller.
Node Yönetimi
Bakım Modu (Drain)
Bir node'u bakıma almak istiyorsun — donanım güncellemesi, işletim sistemi yaması... Önce üzerindeki tüm container'ları başka node'lara taşıman gerekir:
# Node'u drain moduna al
docker node update --availability drain worker1Bu komut, worker1 üzerindeki tüm task'ları diğer node'lara taşır. Bakımı bitirdiğinde:
docker node update --availability active worker1Node Etiketleri (Labels)
Bazı servislerin belirli node'larda çalışmasını isteyebilirsin — mesela veritabanı sadece SSD disk olan sunucuda çalışsın:
# Node'a etiket ekle
docker node update --label-add disk=ssd worker1
docker node update --label-add disk=hdd worker2
# Servisi sadece SSD node'lara yerleştir
docker service create \
--name db \
--constraint 'node.labels.disk == ssd' \
postgres:16Yaygın Sorunlar ve Çözümleri
"No suitable node" hatası: Service'in bir constraint'i karşılanamıyor veya node'larda yeterli kaynak yok. docker service inspect ile constraint'leri, docker node ls ile node durumlarını kontrol et.
Container sürekli restart ediyor: docker service logs web --tail 100 ile logları incele. Genellikle uygulama hatası, eksik environment variable veya bağımlı servis henüz hazır değil.
Stack update çalışmıyor: Image tag değişmediyse Swarm güncelleme yapmaz. Tag'ı değiştir veya --resolve-image always kullan.
Docker Swarm vs Docker Compose: Ne Zaman Hangisi?
Kafan karışmasın: Compose geliştirme için, Swarm production için. Ama bazı durumlar:
Geliştirme ortamı → Docker Compose
Tek sunucu production → Docker Compose (basit uygulamalar için yeterli)
2-10 sunucu, basit mimari → Docker Swarm
10+ sunucu, karmaşık mimari → Kubernetes
Monitoring ve Health Check
Swarm'da servislerin sağlığını izlemek çok önemli. Health check tanımlayarak, Swarm'ın sağlıksız container'ları otomatik yeniden başlatmasını sağlarsın:
services:
api:
image: myapp:v1.0
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s # Her 30 saniyede kontrol
timeout: 5s # 5 saniye cevap vermezse unhealthy
retries: 3 # 3 kez başarısız olursa unhealthy
start_period: 40s # İlk 40 saniye kontrol etmestart_period özellikle önemli — uygulamanın başlaması zaman alabilir (veritabanı bağlantısı, cache ısınması vs). Bu süre dolmadan health check başarısız olsa bile container yeniden başlatılmaz.
Health check'i CLI'dan da izleyebilirsin:
docker service ps web --format "table {{.Name}}\t{{.CurrentState}}\t{{.Error}}"Gerçek Zamanlı Event İzleme
Swarm'da neler olduğunu canlı olarak izlemek istersen:
# Service event'leri
docker events --filter type=service
# Container event'leri (ölüm, restart vs)
docker events --filter type=container --filter event=die
# Son 1 saatin event'leri
docker events --since 1h --filter type=serviceBu komutlar özellikle sorun giderme sırasında çok işe yarıyor. Bir container neden çöktü, ne zaman yeniden başlatıldı, hangi node'a taşındı — hepsini görebilirsin.
Private Registry ile Çalışmak
Production'da Docker Hub'dan değil, kendi private registry'nden image çekersin. Swarm'da bunun bir inceliği var — tüm node'ların registry'ye erişimi olmalı:
# Tüm node'larda registry'ye login
docker login registry.example.com
# Service oluştururken --with-registry-auth flag'i
docker service create \
--name api \
--with-registry-auth \
registry.example.com/myapp:v1.0--with-registry-auth çok önemli — bu flag olmadan, worker node'lar private registry'den image çekemez. Bu flag, manager'ın registry credential'larını worker'lara güvenli bir şekilde iletmesini sağlar.
Stack deploy'da da aynı şekilde:
docker stack deploy --with-registry-auth -c docker-stack.yml myappProduction-Ready Stack: Tam Örnek
Şimdi öğrendiğimiz her şeyi bir araya getiren production-ready bir stack tanımı yapalım:
# docker-stack.yml — Production Ready
version: "3.8"
services:
traefik:
image: traefik:v3.0
command:
- "--providers.docker.swarmMode=true"
- "--providers.docker.exposedByDefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik-public
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
restart_policy:
condition: on-failure
api:
image: registry.example.com/myapp:v1.0
environment:
NODE_ENV: production
DB_HOST: db
REDIS_URL: redis://redis:6379
secrets:
- db_password
- jwt_secret
networks:
- traefik-public
- backend
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 15s
failure_action: rollback
order: start-first
rollback_config:
parallelism: 0
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
cpus: "0.25"
memory: 128M
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.services.api.loadbalancer.server.port=3000"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myapp
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- backend
deploy:
replicas: 1
placement:
constraints:
- node.labels.db == true
resources:
limits:
cpus: "2.0"
memory: 1G
redis:
image: redis:7-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis-data:/data
networks:
- backend
deploy:
replicas: 1
resources:
limits:
memory: 384M
secrets:
db_password:
external: true
jwt_secret:
external: true
volumes:
pgdata:
redis-data:
networks:
traefik-public:
driver: overlay
backend:
driver: overlay
internal: trueBu stack'te neler var? Traefik reverse proxy, 3 replica API servisi, PostgreSQL veritabanı, Redis cache. Secret'lar güvenli, network'ler izole, resource limit'ler tanımlı, health check'ler aktif, rolling update konfigüre edilmiş. Production'a hazır!
Deploy etmek:
# Önce secret'ları oluştur
echo "db-password-here" | docker secret create db_password -
echo "jwt-secret-here" | docker secret create jwt_secret -
# DB node'unu etiketle
docker node update --label-add db=true worker1
# Stack'i deploy et
docker stack deploy --with-registry-auth -c docker-stack.yml myappGüncellemek istediğinde YAML'ı değiştir ve aynı komutu tekrar çalıştır. Swarm sadece değişen kısımları günceller.
Bu Derste Ne Öğrendik?
Docker Swarm, Docker Engine'e dahil gelen, kurulumu kolay orchestration aracı
Manager node'lar karar alır, worker node'lar container çalıştırır
Service istenen durumu tanımlar, Swarm bu durumu sürdürür (self-healing)
Rolling update ile sıfır kesinti güncelleme, rollback ile geri alma
Overlay network ile farklı sunuculardaki container'lar iletişim kurar
Routing mesh ile herhangi bir node'a gelen trafik doğru container'a yönlenir
Stack deploy ile tüm uygulamayı tek YAML dosyasıyla yönetirsin
Production'da 3-5 manager, resource limits, healthcheck ve private registry kullan
Sonraki derste Kubernetes'e giriş yapacağız — Pod, Service, Deployment kavramlarını öğreneceğiz.
AI Asistan
Sorularını yanıtlamaya hazır