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_healthy kullanıyor mu?
  • Migrasyon gibi tek seferlik işler service_completed_successfully ile 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.