SSD Nodes Learn Hosting plans →
मार्गदर्शक Matt Connorद्वारे Matt Connor · अपडेटेड 2026-10-24

Docker Compose healthcheck कसे योग्य लिहावे

Docker Compose healthcheck exit code कसा तपासते, depends_on readiness का थांबवत नाही, आणि Postgres व app साठी विश्वासार्ह readiness checks कसे लिहायचे ते जाणून घ्या.

Docker Compose healthcheck प्रत्यक्षात काय करते

Docker Compose healthcheck ही एक command आहे, जी Docker ठरावीक कालांतराने container मध्ये चालवते. Docker तुमचे logs वाचत नाही, तुमचा port monitor करत नाही किंवा तुमची process list तपासत नाही. ते command चालवते, exit code वाचते आणि container वर एकच state साठवते: starting, healthy किंवा unhealthy. Exit code 0 म्हणजे healthy. इतर कोणताही exit code म्हणजे unhealthy. Exit code 2 हा Docker साठी राखीव आहे, त्यामुळे तो जाणीवपूर्वक कधीही return करू नका.

हीच संपूर्ण कार्यपद्धती आहे. जवळपास प्रत्येक healthcheck समस्या एकाच कारणामुळे निर्माण होते: तुम्ही लिहिलेली command तुम्हाला तपासायचे असलेले वेगळेच उत्तर देते. या मार्गदर्शकात तुम्हाला VPS वर compose file कशी लिहायची हे आधीच माहीत आहे असे गृहीत धरले आहे. Stack चुकीच्या क्रमाने सुरू होतो त्या टप्प्यापासून हा मार्गदर्शक पुढे जातो.

services:
  api:
    image: ghcr.io/example/api:1.4.0
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8080/healthz"]
      interval: 10s
      timeout: 3s
      retries: 5
      start_period: 30s

test value चे दोन उपयुक्त प्रकार आहेत. CMD ने सुरू होणारी list command थेट चालवते, shell न वापरता. त्यामुळे pipes, && आणि variable expansion कार्य करत नाहीत. CMD-SHELL ने सुरू होणारी list उर्वरित भाग एकाच string म्हणून container मधील /bin/sh -c कडे पाठवते. Check साठी shell syntax आवश्यक असेल तेव्हा हा प्रकार वापरावा. साध्या string ला CMD-SHELL म्हणून हाताळले जाते. नेमक्या ["NONE"] घटकांची list वापरल्यास image च्या Dockerfile मधून आधीच जोडलेला healthcheck काढला जातो.

Check container मध्ये चालते. त्यामुळे त्यात नमूद केलेली प्रत्येक binary त्या image मध्ये उपलब्ध असणे आवश्यक आहे. हे आधी तपासा. कारण curl नसलेली slim image application log मध्ये कधीही न दिसणाऱ्या कारणामुळे container कायमचा unhealthy ठेवते. हे स्वतः चालवून तपासा:

docker compose exec api curl --version

Binary उपलब्ध नसल्यास OCI runtime exec failed: exec: "curl": executable file not found in $PATH: unknown मिळते. Alpine आधारित images मध्ये त्याऐवजी सहसा BusyBox wget उपलब्ध असते. त्यामुळे check असे होते: ["CMD", "wget", "-q", "-O", "-", "http://localhost:8080/healthz"].

interval, retries आणि start_period एकत्र कसे कार्य करतात

वेळेचे नियंत्रण करणाऱ्या पाच सेटिंग्ज आहेत. त्यांची डीफॉल्ट मूल्ये Compose कडून नव्हे, तर Docker Engine कडून येतात.

  • interval: कंटेनरचा start period संपल्यानंतर दोन तपासण्यांमधील अंतर. डीफॉल्ट 30s.
  • timeout: तपासणीची एक फेरी पूर्ण होण्यासाठी अनुमत कमाल वेळ. ही वेळ संपल्यास Docker ती फेरी बंद करून अपयशी फेरी म्हणून मोजते. डीफॉल्ट 30s.
  • retries: स्थिती unhealthy होण्यासाठी आवश्यक सलग अपयशांची संख्या. डीफॉल्ट 3.
  • start_period: कंटेनर सुरू झाल्यानंतरचा सवलतीचा कालावधी. डीफॉल्ट 0s.
  • start_interval: start period दरम्यान तपासणी किती वेळाने चालवायची. डीफॉल्ट 5s. यासाठी Docker Engine 25.0 किंवा त्यानंतरची आवृत्ती आवश्यक आहे.

महत्त्वाचा नियम असा आहे: start period दरम्यान तपासणी अपयशी झाली तरी ती retries मध्ये मोजली जात नाही आणि कंटेनर starting स्थितीत राहतो. तपासणी पहिल्यांदा यशस्वी होताच कंटेनर healthy होतो आणि वापरायचा वेळ शिल्लक असला तरी start period तत्काळ संपतो. तपासणी अद्याप अपयशी असताना start period संपल्यास नेहमीची गणना सुरू होते. त्यानंतर कंटेनरला retries सलग अपयशे झाल्यावरच त्याला unhealthy म्हणून चिन्हांकित केले जाते.

त्यामुळे कंटेनर सुरू झाल्यापासून unhealthy होईपर्यंत लागणारा कमाल वेळ start_period अधिक retries गुणिले interval अधिक timeout इतका असतो. वरील फाइलमधील मूल्यांनुसार तो 30 अधिक 5 गुणिले 13, म्हणजे 95 सेकंद आहे. deploy timeout सेट करण्यापूर्वी ही संख्या लिहून ठेवा. 60 सेकंदांनंतर थांबणाऱ्या rollout ला हा कंटेनर अंतिम स्थितीपर्यंत पोहोचलेला कधीही दिसणार नाही.

येथे होणारी सामान्य चूक म्हणजे संथ सुरुवात भरून काढण्यासाठी retries वाढवणे. यामुळे एकदा समस्या सुटते, पण पुढे कायम त्रास होतो: सुरू होण्यासाठी 8 retries लागणारी सेवा उत्पादन वातावरणात काहीही लक्षात येण्यापूर्वी 8 सलग अपयशे सहन करते. त्याऐवजी start_period वापरा, कारण ते फक्त पहिल्या यशस्वी तपासणीपूर्वी लागू होते.

depends_on स्वतः काहीही हमी देत नाही

depends_on चे संक्षिप्त स्वरूप हा बहुतेक गोंधळाचा स्रोत आहे.

  api:
    depends_on:
      - db

याचा एकच अर्थ आहे: db container, api container च्या आधी सुरू करा. Compose container तयार होईपर्यंत आणि सुरू होईपर्यंत प्रतीक्षा करते. PostgreSQL चे प्रथमच होणारे प्रारंभिकीकरण पूर्ण होईपर्यंत ती प्रतीक्षा करत नाही. तसेच port 5432 वर connection स्वीकारले जाईपर्यंतही ती प्रतीक्षा करत नाही. तुमचे app सुमारे एक सेकंदानंतर सुरू होते, त्या वेळी अद्याप कोणीही ऐकत नसलेल्या port शी connect करण्याचा प्रयत्न करते आणि बंद होते. log मध्ये तुम्हाला Connection refused दिसते. Server सुरू झाला असेल पण अजून recovering अवस्थेत असेल, तर FATAL: the database system is starting up दिसते.

लोकांना प्रत्यक्षात हवे असलेले स्वरूप दीर्घ स्वरूप आहे:

  api:
    depends_on:
      db:
        condition: service_healthy
        restart: true
      migrate:
        condition: service_completed_successfully

condition ला तीन values असतात. service_started हे संक्षिप्त स्वरूपासारखेच आहे. service_healthy dependent service ला dependency healthy असल्याचे कळवेपर्यंत थांबवते. हे तेव्हाच अर्थपूर्ण असते, जेव्हा त्या dependency मध्ये healthcheck परिभाषित केलेले असते. ते compose file मध्ये किंवा तिच्या image मध्ये असू शकते. service_completed_successfully one shot container साठी प्रतीक्षा करते, उदाहरणार्थ database migration साठी, आणि तो status 0 सह बंद होईपर्यंत थांबते.

condition च्या शेजारी आणखी दोन fields असतात. restart: true dependency service update केल्यानंतर या service ला restart करण्यास Compose ला सांगते. required: false उपलब्ध नसलेल्या dependency ला error ऐवजी warning म्हणून हाताळते.

आता लोकांना अडचणीत आणणारी मर्यादा पाहू. या conditions stack सुरू होताना तपासल्या जातात. त्या start ordering साठी आहेत; supervision rule नाहीत. Database पहाटे 3 वाजता restart झाला, तरी service_healthy पुन्हा तपासले जात नाही आणि ते पुन्हा पूर्ण करण्यासाठी तुमचे app restart केले जात नाही. तुमच्या application code ने स्वतःहून पुन्हा connect केले पाहिजे. docker compose up --no-deps api हे संपूर्ण mechanism जाणीवपूर्वक वगळते. docker start वापरून container थेट सुरू केल्यासही तेच होते.

अॅप्लिकेशन तयार आहे का हे तपासा; प्रक्रिया अस्तित्वात आहे का हे नाही

pgrep nginx सारखी तपासणी प्रक्रिया table मध्ये entry आहे हे सिद्ध करते. सेवा request ला उत्तर देऊ शकते का, हे त्यातून सिद्ध होत नाही. एखादे web application त्याचा listening socket database pool बंद पडल्यानंतरही बराच वेळ उघडा ठेवू शकते. त्यामुळे संपूर्ण outage दरम्यान process check यशस्वी दिसत राहतो.

Container कडून त्याचे अपेक्षित काम करून घ्या:

  • HTTP सेवेसाठी प्रत्यक्ष endpoint ला request पाठवा. -f मुळे server ने 400 किंवा त्यापेक्षा मोठा status दिल्यास curl -fsS code 22 सह बंद होते. त्यामुळे बिघडलेल्या अॅपकडून आलेला 500 हा failed check ठरतो. curl च्या documentation मध्ये -f हे fail-safe नसल्याचे नमूद केले आहे, विशेषतः 401 आणि 407 authentication responses साठी. त्यामुळे login आवश्यक नसलेल्या endpoint वर तपासणी करा.
  • PostgreSQL साठी pg_isready वापरा. Server connections स्वीकारत असल्यास ते 0 सह, connections नाकारत असल्यास 1 सह, अजिबात उत्तर देत नसल्यास 2 सह आणि दिलेले parameters चुकीचे असल्यास 3 सह बंद होते.
  • Redis साठी redis-cli ping वापरा. ते PONG छापते आणि 0 सह बंद होते.
  • MariaDB साठी official image मध्ये healthcheck.sh script उपलब्ध आहे. त्याच्या maintainers च्या documentation मध्ये healthcheck.sh --connect --innodb_initialized हा प्रकार दिला आहे.

pg_isready मध्ये एक महत्त्वाचा अपवाद आहे. रिकाम्या data directory वर पहिल्यांदा सुरू होताना official postgres image तात्पुरत्या server विरुद्ध initialisation चालवते. हा server फक्त Unix socket वर listening करतो. Host argument न देता pg_isready वापरल्यास तो socket वापरतो. त्यामुळे application साठी TCP port 5432 अद्याप बंद असतानाही तो "accepting connections" असे उत्तर देऊ शकतो. तपासणीसाठी TCP स्पष्टपणे निर्दिष्ट करा. तात्पुरता server TCP वर उत्तर देत नसल्यामुळे ही समस्या दूर होते.

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

दुप्पट dollar signs ही चूक नाही. File वाचताना Compose स्वतः $VAR expand करते. त्यामुळे तुमच्या host environment मधील value check मध्ये कायमची साठवली जाऊ शकते. $$ ती value एका $ पर्यंत escape करते. त्यामुळे container मधील shell ती value container च्या स्वतःच्या environment विरुद्ध expand करते.

योग्य क्रमाने सुरू होणारा postgres आणि app stack

services:
  db:
    image: postgres:17.5
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env}
      POSTGRES_DB: appdb
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 5432 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 10
      start_period: 30s
    restart: unless-stopped

  api:
    image: ghcr.io/example/api:1.4.0
    environment:
      DATABASE_URL: postgres://appuser:${DB_PASSWORD}@db:5432/appdb
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8080/healthz"]
      interval: 10s
      timeout: 3s
      retries: 5
      start_period: 30s
    ports:
      - "127.0.0.1:8080:8080"
    restart: unless-stopped

volumes:
  pgdata:

Stack सुरू करा आणि states मधील बदल पाहा:

docker compose up -d
docker compose ps

STATUS column brackets मध्ये health state दाखवतो. दोन्ही rows मध्ये Up 41 seconds (healthy) दिसल्यास pair healthy आहे. Database अजून initialising असताना db मध्ये Up 4 seconds (health: starting) दिसते आणि list मध्ये api नसते. Compose ने api container आधीच तयार केलेला असतो. db healthy असल्याचे report करेपर्यंत त्याचा start रोखला जातो. docker compose ps default स्वरूपात फक्त running containers दाखवते, म्हणून तो list मध्ये नसतो. त्या वेळी docker compose ps -a चालवा. त्यानंतर api created state मध्ये दिसेल.

Check यशस्वी किंवा अयशस्वी का झाला हे पाहण्यासाठी health log वाचा:

docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q db)"

Docker शेवटचे काही results जतन करते. प्रत्येक result मध्ये start time, end time, ExitCode आणि command चे Output असते. जतन केलेले output truncate केले जाते. त्यामुळे मोठ्या page body ची छपाई करणाऱ्या check मुळे निरुपयोगी log entry तयार होते. Checks शांत ठेवा.

कंटेनर unhealthy झाल्यावर Docker काय करते

काहीही नाही. हेच उत्तर बहुतेक लोकांना सर्वाधिक आश्चर्यचकित करते.

एकाच host वरील Docker Engine unhealthy कंटेनर पुन्हा सुरू करत नाही. restart: unless-stopped policy मुख्य process बंद झाल्यावर प्रतिसाद देते, परंतु unhealthy कंटेनर बंद झालेला नसतो. Compose त्याच्याकडे दुर्लक्ष करत असताना तो unhealthy स्थितीत आठवडाभर राहू शकतो. Swarm mode unhealthy tasks बदलते, परंतु एका server वरील साधा Compose stack तसे करत नाही.

यामुळे दोन व्यवहार्य पर्याय उरतात. Process बिघडल्याचे कळल्यावर तो बंद होईल अशी रचना करा, म्हणजे restart policy कडे कार्य करण्यासाठी काहीतरी असेल. किंवा बाहेरून स्थितीवर लक्ष ठेवा आणि त्यावर alert द्या. तुमचे healthcheck ज्या endpoint ला call करते त्याच endpoint वर Uptime Kuma monitor ठेवले, तर बिघडलेली dependency दोन्ही ठिकाणी दिसते आणि वापरकर्त्याकडून कळण्याऐवजी monitor कडून तिची माहिती मिळते. App पर्यंतचा traffic Traefik reverse proxy द्वारे पोहोचत असल्यास, proxy चे backend विषयीचे स्वतःचे निरीक्षण Docker health state पासून स्वतंत्र असते, हे लक्षात ठेवा. त्यामुळे एकाची माहिती दुसऱ्याची जागा घेत नाही.

कधीही healthy न होणारी तपासणी डीबग करणे

अगदी तीच कमांड, त्याच container मध्ये स्वतः चालवा आणि exit code पाहा:

docker compose exec api curl -fsS http://localhost:8080/healthz; echo "exit=$?"

container अजूनही unhealthy असल्याचे दाखवत असताना येथे exit=0 दिसत असल्यास, तुमचे compose test तुम्ही नुकतेच टाइप केलेल्या मजकुरापेक्षा वेगळे आहे. सामान्यतः shell syntax आवश्यक असताना CMD वापरल्यामुळे असे होते.

उरलेल्या बहुतेक समस्यांचे कारण दोन चुका असतात. पहिली म्हणजे चुकीचा port. healthcheck container च्या आत चालते. त्यामुळे त्यात container port वापरला पाहिजे; प्रकाशित host port कधीही वापरू नका. ports: - "8080:3000" सह application 3000 वर ऐकते. अशावेळी http://localhost:8080 विरुद्ध केलेली तपासणी कायम अपयशी ठरते, जरी site browser मध्ये व्यवस्थित उघडत असली तरी. दुसरी म्हणजे चुकीचा host. तपासणीच्या आत localhost म्हणजे तोच container असतो. स्वतःची तपासणी करण्यासाठी हे योग्य आहे, पण शेजारील container तपासण्यासाठी चुकीचे आहे. त्यासाठी service name आवश्यक असते, उदाहरणार्थ db.

शेवटच्या एका प्रकरणाला स्वतंत्रपणे लक्षात घ्या: healthcheck यशस्वी होते, पण users ना errors दिसतात. endpoint कोणत्याही वास्तविक घटकाशी संपर्क न साधता static 200 परतवतो तेव्हा असे होते. database ची चौकशी न करणारा readiness endpoint database उपलब्ध नाही हे सांगू शकत नाही. त्यात एक स्वस्त, वास्तविक query चालवा.

FAQ

अवलंबित्वामध्ये डेटाबेस healthy असल्याचे नमूद केले असतानाही माझे app connect करण्यात अपयशी का ठरते?

कारण condition: service_healthy चे मूल्यमापन stack सुरू होताना एकदाच केले जाते. त्यानंतर ते कोणत्याही गोष्टीचे निरीक्षण करत नाही. डेटाबेस container नंतर पुन्हा सुरू झाल्यास, अट पुन्हा पूर्ण करण्यासाठी Compose तुमचे application restart करत नाही. त्यामुळे तुमच्या application code मध्ये स्वतःची reconnect आणि retry logic असणे आवश्यक आहे. docker start किंवा docker compose up --no-deps वापरून एकच container सुरू केल्यास ही अट काहीही करत नाही.

image मध्ये healthcheck आधीच परिभाषित असल्यास मला आणखी healthcheck आवश्यक आहे का?

सामान्यतः नाही. तो बदलणे अनेकदा मागे जाण्यासारखे ठरते, कारण त्या software साठी readiness चा अर्थ काय आहे हे image maintainer ला माहीत असते. तुमच्या setup साठी image मधील check चुकीचा असेल, तेव्हाच स्वतःचा check जोडा. उदाहरणार्थ, check ने तुम्ही बदललेल्या port ची तपासणी केली असल्यास. Image healthcheck बंद करण्यासाठी service वर test: ["NONE"] किंवा disable: true सेट करा.

healthcheck मध्ये curl वापरावे की wget?

image मध्ये आधीपासून उपलब्ध असलेले वापरा. त्यावर अवलंबून राहण्यापूर्वी docker compose exec <service> curl --version वापरून ते उपलब्ध असल्याची खात्री करा. अनेक Debian based images मध्ये दोन्हीपैकी एकही उपलब्ध नसतो. Alpine based images मध्ये BusyBox wget असतो. Software स्वतःचा client पुरवत असल्यास, केवळ healthcheck चालवण्यासाठी image मध्ये package जोडू नका. उदाहरणार्थ, pg_isready किंवा redis-cli उपलब्ध असल्यास ते वापरा.

unhealthy container आपोआप restart होतो का?

एकाच host वरील Docker Engine कडून नाही. Restart policies health state वर नव्हे, तर process बंद झाल्यावर प्रतिक्रिया देतात. त्यामुळे unhealthy container सुरूच राहतो आणि काहीतरी दुसरी कृती करेपर्यंत त्याची समस्या कायम राहते. Failure आढळल्यावर process बंद होईल अशी रचना करा किंवा state वर alert देणारा external monitor चालवा.

start_period किती असावा?

तुम्ही मोजलेल्या सर्वांत धीम्या वैध first start साठी पुरेसा, तसेच त्यावर काही अतिरिक्त margin असलेला असावा. रिकाम्या volume वर docker compose up वापरून वेळ मोजा, कारण database चा first start त्यानंतरच्या प्रत्येक start पेक्षा खूप धीमा असतो. start period खूप मोठा असल्यास पहिला unhealthy verdict फक्त उशिरा मिळतो. Retries ची संख्या खूप मोठी असल्यास container च्या संपूर्ण आयुष्यात check कमकुवत राहतो. ही अधिक गंभीर समस्या आहे.

हा लेख उपयुक्त होता का?

#docker-compose#healthcheck#depends-on#docker#reliability