Klasik bir Compose hatası: web uygulaması başlar, ama veritabanı henüz bağlantı kabul etmediği için çöker. depends_on kullanıyorsunuz, yine de oluyor — çünkü varsayılan depends_on yalnızca başlatma sırasını belirler, servisin hazır olmasını beklemez. Bu yazıda healthcheck, depends_on koşulları ve .env değişkenleriyle bunu doğru kurmayı görüyoruz.
Sorun: “çalışıyor” ile “hazır” aynı şey değil
Bir veritabanı container’ı saniyeler içinde “running” olur ama veriyi yükleyip bağlantı kabul etmeye başlaması on-yirmi saniye sürebilir. Compose’un resmi dokümantasyonu da bunu açıkça vurgular: depends_on yalnızca servislerin başlama sırasını kontrol eder, servisin gerçekten hazır olduğunu garanti etmez. Çözüm iki parçalıdır: servise bir healthcheck tanımlamak ve diğer servisin bunu condition: service_healthy ile beklemesini sağlamak.
Healthcheck tanımlamak
db:
image: postgres:18
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
timeout: 10s
retries: 5
start_period: 30s
| Alan | Anlamı |
|---|---|
test |
Çalıştırılacak komut; çıkış kodu 0 = sağlıklı. CMD-SHELL komutu bir kabukta çalıştırır |
interval |
Kontroller arası süre |
timeout |
Bir kontrolün tamamlanması için süre sınırı |
retries |
Kaç ardışık başarısızlıktan sonra “unhealthy” sayılacağı |
start_period |
Açılış süresi — bu süre boyunca başarısız kontroller “unhealthy” sayılmaz |
depends_on koşulları
| Koşul | Ne zaman başlar? |
|---|---|
service_started |
Bağımlı container çalışmaya başlayınca (varsayılan davranış) |
service_healthy |
Bağımlı servisin healthcheck’i başarılı olunca |
service_completed_successfully |
Bağımlı servis çıkış kodu 0 ile bitince — migrasyon gibi tek seferlik işler için |
Uçtan uca örnek (denenmiş)
Aşağıdaki Compose dosyası gerçek bir senaryoyu özetler: veritabanı hazır olana kadar önce migrasyon, sonra web uygulaması beklesin. Denemede veritabanını, bir dosyanın oluşmasını bekleyen basit bir healthcheck’le taklit ettik; mantık bir PostgreSQL ile birebir aynıdır.
services:
web:
image: uygulama:1
depends_on:
db:
condition: service_healthy
restart: true
migrate:
condition: service_completed_successfully
migrate:
image: uygulama:1
command: ["./migrate.sh"]
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
environment:
DB_NAME: ${DB_NAME:?DB_NAME tanimli degil}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 2s
timeout: 3s
retries: 10
start_period: 3s
docker compose up -d çıktısında başlatma sırası açıkça görünür:
Container proje-db-1 Started
Container proje-db-1 Waiting
Container proje-db-1 Healthy
Container proje-migrate-1 Started
Container proje-migrate-1 Exited
Container proje-web-1 Started
$ docker compose ps
SERVICE STATUS
db Up 9 seconds (healthy)
web Up 1 second
Sıra beklendiği gibi: db sağlıklı olana kadar beklendi, ardından migrate çalışıp başarıyla bitti, en son web başladı. restart: true ise veritabanı güncellenip yeniden başlatıldığında web‘in de yeniden başlatılmasını sağlar, böylece bağlantılar tazelenir.
.env dosyası ve zorunlu değişkenler
Compose, çalıştığı dizindeki .env dosyasını otomatik okur ve ${DEGISKEN} yazımlarını doldurur. Varsayılan değer ve zorunluluk için iki kullanışlı biçim vardır:
${STARTUP_DELAY:-5} # tanımlı değilse 5 kullan
${DB_NAME:?DB_NAME tanimli degil} # tanımlı değilse hata ver ve dur
.env dosyası yokken docker compose config çalıştırdığımızda zorunlu değişken şu hatayı verdi:
error while interpolating services.db.environment.DB_NAME:
required variable DB_NAME is missing a value: DB_NAME tanimli degil
Bu davranış, eksik yapılandırmayı sessizce boş değerle çalıştırmak yerine başlamadan önce yakalamanızı sağlar. docker compose config komutunu dosyayı çalıştırmadan doğrulamak ve değişkenlerin doldurulmuş halini görmek için de kullanabilirsiniz.
.env dosyasını Git’e eklemeyin ve gerçek parolaları orada tutmayın; üretimde Compose secrets kullanın. .env‘yi .dockerignore ile imajın dışında tutmayı da unutmayın.
Hızlı kontrol listesi
- Başka servislerin bağlandığı her servisin (veritabanı, kuyruk, önbellek) bir healthcheck’i var mı?
- Bağımlı servisler
condition: service_healthykullanıyor mu? - Migrasyon gibi tek seferlik işler
service_completed_successfullyile sıralanmış mı? - Zorunlu değişkenler
${DEGISKEN:?mesaj}ile korunuyor mu?
Compose’un temellerini hatırlamak için Docker Compose ile Çoklu Servis Yönetimi yazısına, tek makineden orkestrasyona geçişi tartışan Docker Compose vs Kubernetes karşılaştırmasına göz atın.