deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

Docker Compose depends_on Postgres'i Hazır Olmayı Garanti Etmiyor ve Bariz Çözüm de Yetmiyor

Bir dev.to yazısı, Compose'un depends_on'u uygulama başlatmayı Postgres'e bağladığında %22'lik bir hata oranı ölçtü ve standart healthcheck düzeltmesinin bile bir socket-TCP farkı bıraktığını gösterdi.

Docker Compose depends_on Postgres'i Hazır Olmayı Garanti Etmiyor ve Bariz Çözüm de Yetmiyor

Bir dev.to yazısı, tanıdık bir tür tutarsızlığı ele alıyor — entegrasyon testlerinin ilk veritabanı bağlantısında ECONNREFUSED hatasıyla başarısız olup yeniden çalıştırıldığında geçmesi — ve bunu Docker Compose'taki belirli bir boşluğa bağlıyor: depends_on, Postgres'in bağlantıları kabul etmesini beklemez. Şansı dışlamak için yazar, stack'i temiz bir volume ile aşağı indirdi ve 50 kez başlattı; 11 çalışma ilk bağlantı denemesinde başarısız oldu, yani %22'lik bir hata oranı.

depends_on gerçekte neyi bekliyor

Yazıya göre depends_on'un kısa biçimi yalnızca bağımlılık container'ı oluşturulana ve başlatılana kadar bekler — yani içindeki process'in başlatılmış olduğu, bir portu dinlediği veya başlatmayı bitirdiği anlamına gelmez. Compose, veritabanı container'ını çalışıyor görür ve bağımlı servisi hemen başlatır; oysa Postgres hâlâ initdb çalıştırıyor, init script'lerini uyguluyor veya ilk kurulumdan sonra yeniden başlıyor olabilir.

Bu, hatanın neden aralıklı ve ortama bağımlı olduğunu açıklıyor. Geliştirici dizüstü bilgisayarında isimli volume zaten mevcuttur, bu yüzden Postgres başlatmayı atlar ve bir saniyenin çok altında hazır olur. CI'da ise her çalıştırma temiz bir volume alır ve tüm başlatma maliyetini öder; yarış durumu tam olarak burada ortaya çıkar. Yazarın yeniden üretim döngüsü docker compose down -v komutuna dayanıyordu; -v bayrağı olmadan volume hayatta kalır, başlatma atlanır ve hata var olmamış gibi görünür.

İlk düzeltme ve yetmediği yer

Standart çözüm, veritabanı servisindeki bir healthcheck tarafından desteklenen, condition: service_healthy ile depends_on'un uzun biçimidir. Compose böylece bağımlı servisleri healthcheck geçene kadar bekletir. Yazı, insanların burada takıldığı üç ayrıntıya dikkat çekiyor: Compose'un ayrıştırma sırasında ${POSTGRES_USER} değişkenini host ortamından dönüştürmemesi için $$ gerekir, shell değişkenleri açabilsin diye CMD yerine CMD-SHELL kullanılmalı ve varsayılan healthcheck aralığı 30 saniye olduğu için, Postgres hazır olsa bile stack'i yarım dakika boş bekletebileceğinden açık bir interval: 2s belirtilmelidir.

Bunu uyguladıktan sonra yazarın hata sayısı 50'de 11'den 2'ye düştü — daha iyi, ama sıfır değil.

Kalan yarış durumu: pg_isready bir socket'i kontrol ediyor, uygulama TCP kullanıyor

Yazarın neredeyse hiç kimsenin yazmadığını söylediği kalan hata, resmi Postgres imajının içindedir. Temiz bir volume üzerinde entrypoint'i initdb'yi çalıştırır, TCP devre dışıyken geçici bir sunucu başlatır — yalnızca bir Unix socket'ini dinler — yapılandırılmış kullanıcı ve veritabanını oluşturur, /docker-entrypoint-initdb.d içindeki her şeyi çalıştırır, o sunucuyu durdurur ve ancak o zaman gerçek TCP dinleyicisini başlatır.

Düz bir pg_isready Unix socket'i üzerinden bağlanır, bu yüzden geçici sunucu aşamasında başarı bildirebilir. Docker container'ı sağlıklı olarak işaretler, Compose uygulamayı serbest bırakır ve uygulamanın 5432 portuna yaptığı TCP bağlantısı reddedilir, çünkü gerçek sunucu henüz başlamamıştır. Bu pencere, boş bir init diziniyle küçüktür ve seed script'leriyle büyür. Çözüm tek bir bayrak: healthcheck'i istemcinin kullandığı yola zorlamak:

yaml healthcheck: test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 2s timeout: 3s retries: 30 start_period: 10s

Geçici sunucu asla TCP'yi dinlemez, bu yüzden kontrol gerçek sunucu ayağa kalkana kadar geçemez ve start_period, denemelere sayılmayan bir başlatma tahsis süresi verir. Bu yerdeyken yazar 50 açılışta 0 hata ölçtü ve ikinci 50'lik grupta yine 0.

Tek seferlik işlerin sıralaması

Uygulama başlamadan önce bitmesi gereken migration'lar için yazı, bağımlılık container'ı 0 koduyla çıkana kadar bekleyen condition: service_completed_successfully kullanımını öneriyor; sıfır olmayan bir çıkış kodu, uygulamanın yarısı migrate edilmiş bir şemaya karşı açılmasını engeller. Compose toplamda üç koşul sunar: service_started (kısa biçime eşdeğer), service_healthy ve service_completed_successfully.

Neden önemli

Bu hata modu olasılıksaldır ve tam olarak hata ayıkladığınız yerde görünmezdir: sıcak volume'lere sahip dizüstü bilgisayarlar onu neredeyse hiç görmezken, temiz volume'lü CI onu sürekli görür ve altyapı gürültüsü olarak görmezden gelinir. Yazıdaki daha geniş ders şudur: bir healthcheck, istemcinin kullandığı yolu tam olarak test etmelidir — socket'e karşı TCP, doğru host, doğru veritabanı — çünkü yakındaki bir şeyi doğrulayan bir kontrol tam en kötü anda geçecektir. Healthcheck'ler yalnızca başlatma sırasını kontrol eder, bu yüzden yazar, açılıştan sonra gerçekleşen her şey için yeniden deneme mantığını uygulamada tutar.

  • #docker
  • #docker-compose
  • #postgresql
  • #devops
  • #continuous-integration

İlgili yazılar