depends_on va healthcheck — ishga tushish tartibi

~12 daq · Docker · Docker Compose

Muammodan boshlaylik

services:
  api:
    build: .
    depends_on:
      - baza
  baza:
    image: mysql:8.4

docker compose up — va API yiqiladi:

api-1   | Error: connect ECONNREFUSED 172.18.0.2:3306
api-1 exited with code 1

depends_on bor-ku! Nega API baza tayyor bo'lmasdan ishga tushdi?


depends_on aslida nima qiladi

Oddiy depends_on — faqat ishga tushish tartibini belgilaydi: avval baza konteyneri ishga tushadi, keyin api. Lekin:

0.0s  baza konteyneri ishga tushdi   ← depends_on shuni kutadi
0.1s  api konteyneri ishga tushdi    ← API bazaga ulanmoqchi...
...   MySQL init: fayllar, init skriptlar (10-30 soniya)
25s   MySQL ulanishlarni qabul qilishga TAYYOR

Konteyner ishga tushgani ≠ ilova tayyor (22-dars).


Yechim: healthcheck + condition

1. Baza uchun sog'liqni tekshirish:

services:
  baza:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: root123
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "--silent"]
      interval: 5s
      timeout: 5s
      retries: 20
      start_period: 30s
Parametr Ma'nosi
test Tekshiruv buyrug'i; 0 — sog'lom, boshqa — yo'q
interval Qanchalik tez-tez
timeout Bitta tekshiruv uchun maksimal vaqt
retries Necha marta ketma-ket muvaffaqiyatsiz — unhealthy
start_period Boshlang'ich vaqt — bu davrdagi muvaffaqiyatsizliklar hisoblanmaydi

2. API — sog'lom bo'lishini kutsin:

  api:
    build: .
    depends_on:
      baza:
        condition: service_healthy

Endi:

 ✔ Container dokon-baza-1   Healthy       ← 25 soniya kutildi
 ✔ Container dokon-api-1    Started

condition turlari

condition Kutadi
service_started Konteyner ishga tushishini (oddiy depends_on kabi)
service_healthy healthcheck sog'lom deyishini
service_completed_successfully Konteyner 0 kodi bilan tugashini — migratsiyalar uchun

Har xil xizmatlar uchun healthcheck

# PostgreSQL
healthcheck:
  test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
  interval: 5s
  retries: 10

# Redis
healthcheck:
  test: ["CMD", "redis-cli", "ping"]
  interval: 5s

# MongoDB
healthcheck:
  test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"]

# O'z API ingiz (HTTP endpoint)
healthcheck:
  test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
  interval: 15s
  start_period: 10s
  • CMD — buyruq to'g'ridan-to'g'ri; CMD-SHELL — shell orqali (o'zgaruvchilar, || kabi)
  • $ — Compose dagi $ ni qochirish: ${POSTGRES_USER} — konteyner ichidagi o'zgaruvchi, Compose .env niki emas

Healthcheck buyrug'i image ichida mavjud bo'lishi kerak: Alpine da curl yo'q — wget; distroless da hech narsa yo'q — ilovaning o'zi bilan (13-dars).


Migratsiyalarni bir marta bajarish

services:
  migrate:
    build: .
    command: ["npx", "prisma", "migrate", "deploy"]
    depends_on:
      baza:
        condition: service_healthy
    restart: "no"

  api:
    build: .
    depends_on:
      migrate:
        condition: service_completed_successfully

Tartib: baza sog'lom → migratsiyalar bajariladi va tugaydi → API ishga tushadi. Migratsiya xato bersa — API umuman ishga tushmaydi.


Ilova ham chidamli bo'lsin

depends_on — faqat ishga tushish paytida. Keyin baza qayta ishga tushsa yoki tarmoq uzilsa — Compose hech narsa qilmaydi. Ilovaning o'zi:

  • Baza ulanishini qayta urinish bilan qilsin (ko'p ORM va pool lar buni qiladi)
  • Ulanish uzilsa — yiqilmasdan qayta ulansin
  • restart: unless-stopped — yiqilsa ham qayta ko'tarilsin

depends_on + healthcheck — qulaylik; ilovaning chidamliligi — zarurat.


Holatni ko'rish

docker compose ps
NAME           SERVICE   STATUS                    PORTS
dokon-api-1    api       Up 2 minutes (healthy)    0.0.0.0:3000->3000/tcp
dokon-baza-1   baza      Up 3 minutes (healthy)    3306/tcp
docker inspect --format '{{json .State.Health}}' dokon-baza-1

Oxirgi tekshiruvlar natijasi va xato matni — healthcheck nega muvaffaqiyatsiz ekanini ko'rish uchun.


Nima uchun shunday?

Nima uchun depends_on standart holatda faqat konteyner ishga tushishini kutadi, ilova tayyorligini emas?

Chunki Docker ilova qachon "tayyor" ekanini bilmaydi. MySQL uchun — ulanish qabul qilganda; API uchun — /health 200 qaytarganda; worker uchun — navbatga ulanganda. Har bir xizmat uchun "tayyorlik" ta'rifi boshqacha. Docker taxmin qilmaydi — siz healthcheck orqali aniq aytasiz. Taxmin qilingan "tayyorlik" ba'zan ishlardi, ba'zan yo'q — va bunday xatolar eng qiyin topiladiganlari.


Xulosa

Eslab qoling:

  • Oddiy depends_on — faqat konteyner tartibi, tayyorlik emas
  • healthcheck + condition: service_healthy — haqiqiy kutish
  • MySQL: mysqladmin ping; PostgreSQL: pg_isready; Redis: redis-cli ping; API: /health
  • CMD va CMD-SHELL; $ — konteyner o'zgaruvchisi
  • service_completed_successfully — migratsiyalar oldin
  • Ilovaning o'zi ham qayta ulanishi kerak; restart: unless-stopped

Keyingi dars

29-dars: Compose da o'zgaruvchilar — .env, env_file, secrets