Merhaba arkadaşlar, bugün sizlere Docker Compose projelerinizi çok daha sağlam hale getirecek, servislerinizin sağlığını otomatik olarak kontrol eden ve bağımlılıkları akıllıca yönetmenizi sağlayan `healthcheck` özelliğini anlatacağım. Özellikle web, veritabanı ve cache servislerinin bir arada olduğu ortamlarda, bir servis hazır olmadan diğerinin başlamasını engellemek hayat kurtarır. Benim sunucularda genelde kullandığım bu yöntem, uygulamanın ilk açılışında ve sonrasında oluşan geçici hatalarda bile stabilite sağlıyor.
Healthcheck Nedir ve Neden Önemli?
Basitçe anlatmak gerekirse, healthcheck (sağlık kontrolü), Docker konteynerinin içindeki servisin gerçekten çalışıp çalışmadığını, istekleri karşılayabilecek durumda olup olmadığını anlamak için periyodik olarak çalıştırılan bir komut veya HTTP isteğidir. Docker, bu kontrollerin sonucuna göre konteynerin durumunu `healthy` (sağlıklı), `unhealthy` (sağlıksız) veya `starting` (başlatılıyor) olarak işaretler.
En büyük faydası, `depends_on` direktifi ile birlikte kullanıldığında ortaya çıkar. Klasik `depends_on` sadece konteynerin `running` durumda olmasını bekler. Oysa bir MySQL konteyneri çalıştı (`running`) ama henüz bağlantı kabul etmeye hazır değilse, ona bağlı olan web uygulamanız hemen başlayıp bağlantı hatası alacaktır. Healthcheck ile, MySQL'in bağlantı portunu açıp, hatta basit bir sorguyu çalıştırabilecek duruma gelmesini bekletebilirsiniz. Böylece bağımlılıklar gerçekten "hazır" olduğunda ana servisiniz başlar.
Temel Healthcheck Yapılandırması
Healthcheck, Dockerfile içinde veya daha pratik ve yaygın olarak `docker-compose.yml` dosyasında tanımlanabilir. Size Compose üzerinden göstereceğim çünkü konfigürasyonu değiştirmek ve yönetmek çok daha kolay.
İşte basit bir web servisi (Nginx) ve bir veritabanı (PostgreSQL) için örnek bir compose dosyası:
Şimdi buradaki healthcheck parametrelerini açıklayayım:
- `test`: Sağlık kontrolünü yapacak komut. `CMD`, `CMD-SHELL` veya `curl` gibi araçlar kullanılabilir. PostgreSQL için `pg_isready` aracı mükemmel çalışır.
- `interval`: Her bir sağlık kontrolü arasında beklenecek süre (varsayılan: 30s).
- `timeout`: Kontrol komutunun cevap vermesi için beklenen maksimum süre (varsayılan: 30s). Bu süre aşılırsa kontrol başarısız sayılır.
- `retries`: Konteyneri `unhealthy` olarak işaretlemeden önceki başarısız deneme sayısı (varsayılan: 3).
- `start_period`: Konteyner başladıktan sonraki ilk bu süre boyunca, başarısız kontroller `retries` sayısına dahil edilmez. Uzun başlangıç süresi olan uygulamalar (örn: Java) için çok kritiktir.
Bağımlılık Yönetimini Akıllıca Kurmak
Yukarıdaki örnekte dikkat ettiyseniz, `webapp` servisinin `depends_on` kısmında basit bir bağımlılık yerine `condition: service_healthy` kullandık. İşte sihir burada! Bu satır, Docker Compose'a "postgres servisi `healthy` durumuna geçmeden webapp'ı başlatma" talimatını verir.
Bu yapıyı kurduktan sonra `docker-compose up` komutunu çalıştırdığınızda olanları şöyle izleyebilirsiniz:
Çıktıda postgres konteynerinin önce `starting` ardından `healthy` durumuna geçtiğini, ancak ondan sonra webapp konteynerinin başlatıldığını göreceksiniz. Ayrıca konteynerlerin mevcut durumunu her zaman şu komutla kontrol edebilirsiniz:
Bu komut, her servisin durumunu (`Up`, `Exit`) ve healthcheck sonucunu (`healthy`, `unhealthy`) gösterecektir.
Dikkat Edilmesi Gerekenler ve İpuçları
1. `curl`'ün Konteynerde Bulunması: `test: ["CMD", "curl", "-f", "
"]` gibi bir kontrol yapacaksanız, kullandığınız base imajın içinde `curl` aracının yüklü olduğundan emin olun. Alpine imajlarda genelde yoktur, Dockerfile'ınıza `RUN apk add --no-cache curl` eklemeniz gerekebilir. Alternatif olarak `wget` veya imajın kendi araçlarını kullanın.
2. Basit ve Hızlı Kontroller Yazın: Healthcheck komutunuz çok uzun süren veya ağır işlemler yapmamalı. Amacı servisin "yaşıyor ve cevap veriyor" olduğunu hızlıca doğrulamaktır.
3. Start Period Kullanımı: Özellikle veritabanları veya büyük uygulamalar başlarken hazır olmaları onlarca saniye sürebilir. Bu süre içinde yapılan başarısız kontrollerin `unhealthy` sayılmaması için `start_period` değerini akıllıca (örn: 60s) ayarlayın.
4. Gelişmiş Senaryolar: Sadece bir portun açık olması yetmeyebilir. Örneğin bir API servisi için, belirli bir endpoint'e (`/health` veya `/status`) HTTP GET isteği atıp, dönen JSON cevabındaki bir alanı kontrol eden özel bir script de yazabilirsiniz.
Sonuç
Docker Compose'da healthcheck kullanmak, özellikle production benzeri ortamlar geliştirirken veya CI/CD pipeline'larında konteynerleri test ederken karşılaştığımız "race condition" ve başlangıç hatalarını neredeyse sıfıra indirir. Servislerinizin birbiriyle olan ilişkisini gerçek anlamda yönetmenizi sağlar.
Ben genelde tüm veritabanı, cache (Redis), mesaj kuyruğu (RabbitMQ) ve ana uygulama servislerim için mutlaka uygun bir healthcheck tanımlarım. Siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Farklı kullandığınız yöntemler veya sorularınız varsa aşağıya yazmaktan çekinmeyin. Sağlıcakla kalın!
Basitçe anlatmak gerekirse, healthcheck (sağlık kontrolü), Docker konteynerinin içindeki servisin gerçekten çalışıp çalışmadığını, istekleri karşılayabilecek durumda olup olmadığını anlamak için periyodik olarak çalıştırılan bir komut veya HTTP isteğidir. Docker, bu kontrollerin sonucuna göre konteynerin durumunu `healthy` (sağlıklı), `unhealthy` (sağlıksız) veya `starting` (başlatılıyor) olarak işaretler.
En büyük faydası, `depends_on` direktifi ile birlikte kullanıldığında ortaya çıkar. Klasik `depends_on` sadece konteynerin `running` durumda olmasını bekler. Oysa bir MySQL konteyneri çalıştı (`running`) ama henüz bağlantı kabul etmeye hazır değilse, ona bağlı olan web uygulamanız hemen başlayıp bağlantı hatası alacaktır. Healthcheck ile, MySQL'in bağlantı portunu açıp, hatta basit bir sorguyu çalıştırabilecek duruma gelmesini bekletebilirsiniz. Böylece bağımlılıklar gerçekten "hazır" olduğunda ana servisiniz başlar.
Healthcheck, Dockerfile içinde veya daha pratik ve yaygın olarak `docker-compose.yml` dosyasında tanımlanabilir. Size Compose üzerinden göstereceğim çünkü konfigürasyonu değiştirmek ve yönetmek çok daha kolay.
İşte basit bir web servisi (Nginx) ve bir veritabanı (PostgreSQL) için örnek bir compose dosyası:
YAML:
version: '3.8'
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: mydb
POSTGRES_USER: admin
POSTGRES_PASSWORD: sifre123
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d mydb"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
volumes:
- postgres_data:/var/lib/postgresql/data
webapp:
image: nginx:alpine
ports:
- "8080:80"
depends_on:
postgres:
condition: service_healthy
volumes:
- ./html:/usr/share/nginx/html
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
volumes:
postgres_data:
Şimdi buradaki healthcheck parametrelerini açıklayayım:
- `test`: Sağlık kontrolünü yapacak komut. `CMD`, `CMD-SHELL` veya `curl` gibi araçlar kullanılabilir. PostgreSQL için `pg_isready` aracı mükemmel çalışır.
- `interval`: Her bir sağlık kontrolü arasında beklenecek süre (varsayılan: 30s).
- `timeout`: Kontrol komutunun cevap vermesi için beklenen maksimum süre (varsayılan: 30s). Bu süre aşılırsa kontrol başarısız sayılır.
- `retries`: Konteyneri `unhealthy` olarak işaretlemeden önceki başarısız deneme sayısı (varsayılan: 3).
- `start_period`: Konteyner başladıktan sonraki ilk bu süre boyunca, başarısız kontroller `retries` sayısına dahil edilmez. Uzun başlangıç süresi olan uygulamalar (örn: Java) için çok kritiktir.
Yukarıdaki örnekte dikkat ettiyseniz, `webapp` servisinin `depends_on` kısmında basit bir bağımlılık yerine `condition: service_healthy` kullandık. İşte sihir burada! Bu satır, Docker Compose'a "postgres servisi `healthy` durumuna geçmeden webapp'ı başlatma" talimatını verir.
Bu yapıyı kurduktan sonra `docker-compose up` komutunu çalıştırdığınızda olanları şöyle izleyebilirsiniz:
Bash:
docker-compose up
Çıktıda postgres konteynerinin önce `starting` ardından `healthy` durumuna geçtiğini, ancak ondan sonra webapp konteynerinin başlatıldığını göreceksiniz. Ayrıca konteynerlerin mevcut durumunu her zaman şu komutla kontrol edebilirsiniz:
Bash:
docker-compose ps
Bu komut, her servisin durumunu (`Up`, `Exit`) ve healthcheck sonucunu (`healthy`, `unhealthy`) gösterecektir.
1. `curl`'ün Konteynerde Bulunması: `test: ["CMD", "curl", "-f", "
Bu bağlantı ziyaretçiler için gizlenmiştir. Görmek için lütfen giriş yapın veya üye olun.
2. Basit ve Hızlı Kontroller Yazın: Healthcheck komutunuz çok uzun süren veya ağır işlemler yapmamalı. Amacı servisin "yaşıyor ve cevap veriyor" olduğunu hızlıca doğrulamaktır.
3. Start Period Kullanımı: Özellikle veritabanları veya büyük uygulamalar başlarken hazır olmaları onlarca saniye sürebilir. Bu süre içinde yapılan başarısız kontrollerin `unhealthy` sayılmaması için `start_period` değerini akıllıca (örn: 60s) ayarlayın.
4. Gelişmiş Senaryolar: Sadece bir portun açık olması yetmeyebilir. Örneğin bir API servisi için, belirli bir endpoint'e (`/health` veya `/status`) HTTP GET isteği atıp, dönen JSON cevabındaki bir alanı kontrol eden özel bir script de yazabilirsiniz.
Docker Compose'da healthcheck kullanmak, özellikle production benzeri ortamlar geliştirirken veya CI/CD pipeline'larında konteynerleri test ederken karşılaştığımız "race condition" ve başlangıç hatalarını neredeyse sıfıra indirir. Servislerinizin birbiriyle olan ilişkisini gerçek anlamda yönetmenizi sağlar.
Ben genelde tüm veritabanı, cache (Redis), mesaj kuyruğu (RabbitMQ) ve ana uygulama servislerim için mutlaka uygun bir healthcheck tanımlarım. Siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Farklı kullandığınız yöntemler veya sorularınız varsa aşağıya yazmaktan çekinmeyin. Sağlıcakla kalın!