Temel Kümeleme: Docker Swarm Kurulumu ve Servis Yönetimi

Tek bir Docker host’unuzda her şey yolunda gidiyorken, bir gün trafik patlaması yaşanıyor ve o tek makine artık yük altında ezilmeye başlıyor. Ya da daha kötüsü, o makine çöküyor ve tüm servisleriniz birden erişilemez hale geliyor. İşte bu noktada Docker Swarm devreye giriyor. Swarm, birden fazla Docker host’unu bir araya getirip tek bir mantıksal küme olarak yönetmenizi sağlıyor. Kubernetes kadar karmaşık değil, ama production ortamları için gayet yeterli. Bu yazıda sıfırdan Swarm kurulumu yapacak, servis yönetimini öğrenecek ve gerçek dünya senaryolarıyla konuyu pekiştireceğiz.

Docker Swarm Nedir, Ne Değildir?

Docker Swarm, Docker’ın kendi bünyesinde gelen orkestrasyon çözümüdür. Ek bir araç kurmanıza gerek yok, Docker kuruluysa Swarm da kullanıma hazırdır. Kubernetes ile karşılaştırıldığında öğrenme eğrisi çok daha düzdür, küçük ve orta ölçekli altyapılar için mükemmel bir seçimdir.

Swarm dünyasında iki tür node vardır:

  • Manager node: Kümenin beynidur. Servis tanımlarını saklar, görevleri dağıtır, küme durumunu izler.
  • Worker node: Asıl işi yapan makinelerdir. Konteynerları çalıştırır, manager’dan gelen görevleri yerine getirir.

Manager node’lar aynı zamanda worker olarak da çalışabilir, ama production’da manager’ları sadece orkestrasyon için ayırmak daha sağlıklıdır.

Swarm’ın temel kavramlarına bakalım:

  • Service: Swarm üzerinde çalıştırmak istediğiniz uygulamanın tanımıdur. “Nginx’in 3 kopyasını çalıştır” gibi bir direktif.
  • Task: Bir servisin her bir konteyner örneğidir. 3 replika demek 3 task demektir.
  • Stack: Birden fazla servisin bir arada tanımlandığı compose dosyasının Swarm üzerindeki karşılığıdır.
  • Overlay Network: Farklı node’lardaki konteynerların birbiriyle iletişim kurmasını sağlayan sanal ağdur.

Lab Ortamının Hazırlanması

Ben bu yazıda 3 node’luk bir küme kuracağım. Gerçek sunucularınız olabilir, cloud VM’ler olabilir, hatta aynı makinede birden fazla VM çalıştırabilirsiniz. Önemli olan şu:

  • Her node’da Docker kurulu olmalı
  • Node’lar birbirinin IP adreslerine ulaşabilmeli
  • Gerekli portlar açık olmalı

Açılması gereken portlar:

  • 2377/tcp: Swarm yönetim trafiği için
  • 7946/tcp ve 7946/udp: Node’lar arası iletişim için
  • 4789/udp: Overlay network trafiği için

Node IP adreslerim şu şekilde:

  • manager1: 192.168.1.10
  • worker1: 192.168.1.11
  • worker2: 192.168.1.12

Firewall kurallarını ayarlayalım (UFW kullanıyorsanız):

# Manager ve worker node'ların hepsinde çalıştırın
ufw allow 2377/tcp
ufw allow 7946/tcp
ufw allow 7946/udp
ufw allow 4789/udp
ufw reload

Swarm Kümesini Oluşturmak

Manager node üzerinde başlatma işlemini yapalım:

# manager1 üzerinde çalıştırın
docker swarm init --advertise-addr 192.168.1.10

Bu komutun çıktısı şuna benzer bir şey olacak:

Swarm initialized: current node (abc123xyz) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-abc123...xyz789 192.168.1.10:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Çıktıdaki join token’ı saklayın. Worker node’ları eklemek için kullanacaksınız.

Eğer token’ı kaybettiyseniz panik yapmayın, her zaman tekrar alabilirsiniz:

# Worker token'ı görüntüle
docker swarm join-token worker

# Manager token'ı görüntüle
docker swarm join-token manager

Şimdi worker node’ları kümeye ekleyelim. worker1 ve worker2 üzerinde çalıştırın:

docker swarm join 
  --token SWMTKN-1-abc123...xyz789 
  192.168.1.10:2377

Manager node üzerinde küme durumunu kontrol edelim:

docker node ls

Çıktı şuna benzer görünmeli:

ID                HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS
abc123 *          manager1   Ready     Active         Leader
def456            worker1    Ready     Active
ghi789            worker2    Ready     Active

Artık 3 node’luk bir Swarm kümemiz var. Şimdi asıl işe girelim.

İlk Servisinizi Oluşturmak

Swarm’da servis oluşturmak, docker run komutuna benzer ama çok daha güçlüdür. Bir Nginx servisi oluşturalım:

docker service create 
  --name web-server 
  --replicas 3 
  --publish published=80,target=80 
  nginx:alpine

Bu komutla ne yaptık:

  • –name web-server: Servise bir isim verdik
  • –replicas 3: 3 kopya çalıştırmasını istedik
  • –publish published=80,target=80: Port mapping yaptık
  • nginx:alpine: Kullanacağımız image

Servis durumunu kontrol edelim:

# Genel servis listesi
docker service ls

# Belirli bir servisin detayları
docker service ps web-server

docker service ps komutu size her task’ın hangi node üzerinde çalıştığını gösterir. 3 task’ın 3 farklı node’a dağıtıldığını göreceksiniz.

Servis Ölçeklendirme ve Güncelleme

Gerçek dünyada en sık yapacağınız işlemlerden biri servisi ölçeklendirmektir. Trafik arttı, daha fazla replica lazım:

# Replica sayısını 5'e çıkar
docker service scale web-server=5

# Birden fazla servisi aynı anda ölçeklendir
docker service scale web-server=5 api-server=3

Peki uygulama güncellemesi nasıl yapılır? Zero-downtime deployment Swarm’ın en güçlü özelliklerinden biridir:

docker service update 
  --image nginx:1.25-alpine 
  --update-parallelism 2 
  --update-delay 10s 
  web-server

Buradaki parametreler kritiktir:

  • –update-parallelism 2: Aynı anda kaç task’ın güncelleneceği
  • –update-delay 10s: Her batch güncellemesi arasında kaç saniye bekleyeceği

Bu sayede tüm replica’lar aynı anda kapanmaz, servis kesintisiz çalışmaya devam eder.

Güncelleme sırasında bir sorun çıkarsa geri almak çok kolay:

docker service rollback web-server

Overlay Network ve Servisler Arası İletişim

Gerçek uygulamalarda servisler birbiriyle konuşmak zorundadır. Bir web uygulaması veritabanıyla, API gateway mikroservislerle iletişim kurar. Swarm’da bu overlay network ile sağlanır.

Önce özel bir overlay network oluşturalım:

docker network create 
  --driver overlay 
  --attachable 
  app-network

Şimdi bu network üzerinde birbirleriyle konuşabilen servisler oluşturalım:

# Veritabanı servisi
docker service create 
  --name postgres-db 
  --network app-network 
  --env POSTGRES_PASSWORD=gizli123 
  --env POSTGRES_DB=myapp 
  --replicas 1 
  postgres:15-alpine

# API servisi
docker service create 
  --name api-server 
  --network app-network 
  --publish published=8080,target=8080 
  --replicas 3 
  --env DATABASE_URL=postgresql://postgres:gizli123@postgres-db:5432/myapp 
  myapp/api:latest

Dikkat edin, API servisi veritabanına postgres-db ismiyle bağlanıyor. Swarm’ın dahili DNS’i bu ismi otomatik olarak çözümler. Node değişse bile, task yeniden başlasa bile servis ismi her zaman erişilebilir olur. Bu çok büyük bir kolaylık.

Stack ile Çoklu Servis Yönetimi

Tek tek servis oluşturmak küçük testler için işe yarar ama production’da onlarca servisiniz olacak. İşte bu noktada Stack devreye girer. Bir docker-compose.yml benzeri dosyayla tüm uygulamanızı tek komutla yönetirsiniz.

Bir e-ticaret uygulaması için stack dosyası yazalım:

# docker-stack.yml
version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    networks:
      - frontend
      - backend
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro

  api:
    image: myapp/api:2.1.0
    networks:
      - backend
    environment:
      - NODE_ENV=production
      - DB_HOST=db
    deploy:
      replicas: 4
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

  db:
    image: postgres:15-alpine
    networks:
      - backend
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
      POSTGRES_DB: ecommerce
    volumes:
      - db-data:/var/lib/postgresql/data
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == worker
          - node.labels.disk == ssd

volumes:
  db-data:

networks:
  frontend:
    driver: overlay
  backend:
    driver: overlay
    internal: true

secrets:
  db_password:
    external: true

Stack’i deploy edelim:

docker stack deploy -c docker-stack.yml ecommerce

Stack durumunu kontrol etmek:

# Stack listesi
docker stack ls

# Stack içindeki servisler
docker stack services ecommerce

# Tüm task'ların durumu
docker stack ps ecommerce

Swarm Secret Yönetimi

Production ortamında şifreleri environment variable olarak geçmek güvenlik açığıdır. Swarm’ın secret yönetimi bu sorunu çözer. Secret’lar şifreli olarak saklanır ve sadece ihtiyacı olan servislere açılır.

# Komut satırından secret oluştur
echo "super_gizli_sifre_123" | docker secret create db_password -

# Dosyadan secret oluştur
docker secret create ssl_certificate ./cert.pem

# Secret listesi
docker secret ls

Secret kullanan bir servis oluşturalım:

docker service create 
  --name secure-db 
  --secret db_password 
  --env POSTGRES_PASSWORD_FILE=/run/secrets/db_password 
  postgres:15-alpine

Secret, konteyner içinde /run/secrets/secret_ismi yolunda dosya olarak belirir. Uygulama bu dosyayı okur, şifre asla environment variable’da görünmez.

Node Yönetimi ve Placement Constraints

Production’da tüm servisler tüm node’larda çalışmamalıdır. Veritabanını SSD diskli node’larda, ağır hesaplama işlerini yüksek CPU’lu node’larda çalıştırmak istersiniz. Bunun için node label’ları kullanırsınız.

# Node'a label ekle
docker node update --label-add disk=ssd worker1
docker node update --label-add disk=hdd worker2
docker node update --label-add role=compute worker2

# Node detaylarını görüntüle
docker node inspect worker1 --pretty

Placement constraint ile servislerinizi belirli node’lara yönlendirin:

docker service create 
  --name high-perf-db 
  --constraint 'node.labels.disk == ssd' 
  --constraint 'node.role == worker' 
  postgres:15-alpine

Bir node’u bakıma almak istediğinizde availability’yi değiştirin. Bu sayede o node üzerindeki task’lar diğer node’lara taşınır:

# Node'u bakım moduna al
docker node update --availability drain worker1

# Bakım tamamlandı, node'u aktif et
docker node update --availability active worker1

Global Servisler

Bazı servisler her node’da tam olarak bir kez çalışmalıdır. Log toplayıcılar, monitoring agent’lar bunun en iyi örneğidir. Bunun için global mod kullanılır:

docker service create 
  --name node-exporter 
  --mode global 
  --publish published=9100,target=9100 
  --mount type=bind,source=/proc,target=/host/proc,readonly 
  --mount type=bind,source=/sys,target=/host/sys,readonly 
  prom/node-exporter:latest

Global modda kaç node varsa o kadar task oluşturulur. Yeni bir node eklendiğinde otomatik olarak o node’a da deploy edilir. Kümeye 5. node eklediğinizde node-exporter oraya da otomatik gelir.

Health Check ve Otomatik Yeniden Başlatma

Swarm, başarısız task’ları otomatik olarak yeniden başlatır. Ama bunu doğru yapabilmesi için uygulamanızın sağlık durumunu bilmesi gerekir.

Health check tanımlı bir servis oluşturalım:

docker service create 
  --name api-with-health 
  --replicas 3 
  --health-cmd "curl -f http://localhost:8080/health || exit 1" 
  --health-interval 30s 
  --health-timeout 10s 
  --health-retries 3 
  --health-start-period 60s 
  myapp/api:latest

Bu parametreler ne anlama gelir:

  • –health-cmd: Sağlık kontrolü için çalıştırılacak komut
  • –health-interval 30s: Her 30 saniyede bir kontrol et
  • –health-timeout 10s: 10 saniye içinde cevap gelmezse başarısız say
  • –health-retries 3: 3 başarısız denemeden sonra unhealthy işaretle
  • –health-start-period 60s: Konteyner başladıktan sonra 60 saniye bekle, bu sürede başarısızlıkları sayma

Bir task sürekli başarısız olursa Swarm onu yeniden başlatır. Restart policy stack dosyasında şöyle tanımlanır:

  • condition: on-failure: Sadece başarısız olduğunda yeniden başlat
  • delay: 5s: Yeniden başlatmadan önce 5 saniye bekle
  • max_attempts: 3: En fazla 3 kez dene
  • window: 120s: 120 saniyelik pencerede dene

Gerçek Dünya Senaryosu: Rolling Update Stratejisi

Bir e-ticaret sitesi yönettiğinizi düşünün. Cuma akşamı 23:00’da yeni bir sürüm deploy etmeniz gerekiyor. Aşağıdaki strateji ile sıfır kesinti sağlarsınız:

# Önce mevcut durumu not edin
docker service ps ecommerce_api --no-trunc

# Yeni image'ı deploy et, dikkatli bir stratejiyle
docker service update 
  --image myapp/api:2.2.0 
  --update-parallelism 1 
  --update-delay 30s 
  --update-failure-action rollback 
  --update-monitor 60s 
  --update-max-failure-ratio 0.3 
  ecommerce_api

Kritik parametreler:

  • –update-failure-action rollback: Güncelleme başarısız olursa otomatik geri al
  • –update-monitor 60s: Her task güncellendikten sonra 60 saniye izle
  • –update-max-failure-ratio 0.3: Task’ların yüzde 30’u başarısız olursa güncellemeyi durdur

Bu parametrelerle güncelleme sırasında bir sorun çıkarsa Swarm müdahale beklemeden geri alır. Pazar sabahı işe geldiğinizde sistemi sağlam bulursunuz.

Monitoring ve Loglar

Swarm kümesini izlemek için birkaç temel komut:

# Küme genelinde çalışan tüm servisleri listele
docker service ls

# Belirli bir servisin loglarını takip et
docker service logs -f web-server

# Son 100 satır log
docker service logs --tail 100 api-server

# Tüm stack logları
docker stack ps ecommerce --no-trunc

# Node kaynak kullanımı
docker node ls
docker system df

Uyarı: docker service logs komutu tüm node’lardan logları toplar. Büyük bir kümede bu çok fazla çıktı üretebilir. Gerçek production’da Elasticsearch, Loki veya benzeri bir merkezi log sistemi kullanmanızı kesinlikle tavsiye ederim.

Görsel bir dashboard istiyorsanız Portainer kullanabilirsiniz:

docker service create 
  --name portainer 
  --publish 9000:9000 
  --constraint 'node.role == manager' 
  --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock 
  --mount type=volume,source=portainer_data,target=/data 
  portainer/portainer-ce:latest

Portainer, Swarm kümesini tarayıcıdan yönetmenizi sağlar. Servis oluşturma, ölçeklendirme, log görüntüleme gibi işlemleri GUI üzerinden yapabilirsiniz.

Yaygın Sorunlar ve Çözümleri

Sorun: Task pending durumunda kalıyor

Bir task başlamıyorsa önce şunu kontrol edin:

docker service ps --no-trunc web-server

Çıktıdaki hata mesajına bakın. Genellikle image bulunamadı, yetersiz kaynak veya placement constraint uyumsuzluğu gibi nedenleri vardır.

Sorun: Node ulaşılamıyor

# Node durumunu kontrol et
docker node inspect worker1 --pretty

# Node'u kümeden güvenli çıkar
docker node update --availability drain worker1
docker node rm worker1

Sorun: Overlay network sorunları

# Network listesi
docker network ls

# Network detayları
docker network inspect app-network

Overlay network sorunlarının büyük çoğunluğu firewall kurallarından kaynaklanır. 4789/udp portunu her node’da kontrol edin.

Sonuç

Docker Swarm, özellikle Kubernetes’e geçmeye henüz hazır olmayan ya da geçmeyi düşünmeyen ekipler için mükemmel bir çözümdür. Kurulumu basit, yönetimi anlaşılır ve Docker ekosistemiyle mükemmel entegre olur.

Bu yazıda ele aldıklarımızın özeti:

  • Swarm kümesini sıfırdan nasıl kuracağınızı ve node’ları nasıl ekleyeceğinizi gördünüz
  • Temel servis oluşturma, ölçeklendirme ve güncelleme işlemlerini öğrendiniz
  • Overlay network ile servisler arası iletişimi kurguladınız
  • Stack dosyalarıyla çoklu servis yönetimini öğrendiniz
  • Secret yönetimiyle güvenli konfigürasyon saklamayı gördünüz
  • Node label’ları ve placement constraint’ler ile akıllı dağıtım yaptınız
  • Sıfır kesintili rolling update stratejisi uyguladınız

Bir sonraki adım olarak Swarm üzerinde Traefik gibi bir reverse proxy kurarak SSL termination ve otomatik servis keşfini eklemenizi öneririm. Ayrıca Prometheus ve Grafana ile metrik toplamanızı da planınıza ekleyin. Sağlam bir Swarm kurulumu, takımınıza deployment güveni ve altyapınıza esneklik kazandırır.

Yorum yapın