ESC را فشار دهید تا بسته شود

چرا Docker Container در وضعیت unhealthy می‌ماند؟ عیب‌یابی HEALTHCHECK و Docker Compose

فهرست

رفع مشکل unhealthy در Docker از خواندن نتیجه HEALTHCHECK شروع می‌شود، نه Restart کورکورانه. وقتی فرایند اصلی کانتینر Running است اما healthcheck شکست می‌خورد، Docker عبارت unhealthy را نشان می‌دهد. با docker inspect خطای probe را بخوانید، دستور را داخل کانتینر تست کنید و سپس پورت، endpoint، ابزارهای موجود و زمان راه‌اندازی را اصلاح کنید.

unhealthy یعنی چه؟

Docker برای کانتینر دارای HEALTHCHECK سه وضعیت starting، healthy و unhealthy ثبت می‌کند. کد خروج 0 موفقیت و 1 شکست است؛ کد 2 رزرو شده است. unhealthy شدن به‌تنهایی کانتینر را Restart نمی‌کند. فرایند اصلی ممکن است همچنان Up باشد.

پیش‌نیاز و سناریو

نام نمونه web و پورت داخلی 8080 است؛ قبل از recreate بکاپ بگیرید.

docker version
docker compose version
docker ps --all

گام اول: Health.Log را بررسی کنید

docker inspect --format '{{.State.Status}}' web
docker inspect --format '{{.State.Health.Status}}' web
docker inspect --format '{{json .State.Health}}' web
docker inspect --format '{{json .Config.Healthcheck}}' web

در JSON، FailingStreak، ExitCode و Output را ببینید. curl: not found یعنی ابزار غایب؛ Connection refused نشانه پورت/سرویس و 401/404 نشانه مسیر اشتباه است. نبود State.Health یعنی probe تعریف نشده.

گام دوم: لاگ برنامه را جداگانه بخوانید

docker logs --tail 100 --timestamps web
docker compose ps --all
docker compose logs --tail 100 web

docker logs خروجی فرایند اصلی را نشان می‌دهد و لزوماً شامل Health.Log نیست. اگر DNS کانتینر مشکل دارد، راهنمای رفع مشکل DNS در Docker را ببینید.

گام سوم: دستور HEALTHCHECK را داخل کانتینر اجرا کنید

دستور زیر برای ایمیجی است که shell و curl دارد. توجه کنید localhost در کانتینر به خود کانتینر اشاره می‌کند، نه به سرور میزبان. اگر برنامه روی پورت دیگری اجرا می‌شود، عدد 8080 را عوض کنید.

docker exec web sh -c 'command -v curl || command -v wget || true'
docker exec web sh -c 'curl -fsS http://127.0.0.1:8080/health; echo exit:$?'

انتظار exit:0 داریم. در ایمیج distroless ممکن است shell نباشد؛ از باینری موجود استفاده کنید و TLS verification را غیرفعال نکنید.

گام چهارم: مسیر و پورت را اصلاح کنید

اگر برنامه /ready دارد، مسیر /health را اصلاح کنید. endpoint باید HTTP 200 بدهد نه 401؛ localhost فقط خود کانتینر است.

گام پنجم: نمونه صحیح HEALTHCHECK در Dockerfile

این دستور تنها زمانی معتبر است که curl و shell در ایمیج نصب باشند و برنامه درون کانتینر روی 8080 گوش دهد:

HEALTHCHECK --interval=20s --timeout=5s --start-period=45s --retries=3 CMD curl -fsS http://127.0.0.1:8080/health || exit 1

interval فاصله تست، timeout سقف زمان، retries شکست متوالی و start-period دوره راه‌اندازی است؛ پس از نخستین موفقیت حتی در start-period شکست‌ها شمرده می‌شوند.

گام ششم: رفع unhealthy در Docker Compose

در فایل compose.yaml بخش healthcheck می‌تواند دستور پیش‌فرض ایمیج را override کند. این نمونه فقط برای سرویس HTTP با curl نصب‌شده معتبر است؛ نام ایمیج را با ایمیج واقعی جایگزین کنید:

services:
  web:
    image: example/web:stable
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8080/health"]
      interval: 20s
      timeout: 5s
      retries: 3
      start_period: 45s

فرم CMD مستقیماً curl را اجرا می‌کند. اگر به عملگر shell نیاز دارید، CMD-SHELL و shell موجود در ایمیج لازم است. قبل از اعمال تغییر، فایل را با docker compose config بررسی کنید.

برای آشنایی با شبکه و وابستگی سرویس‌ها، آموزش Docker Compose روی سرور لینوکس را بخوانید.

گام هفتم: وابستگی دیتابیس و service_healthy

اگر وب‌اپلیکیشن پیش از آماده‌شدن دیتابیس شروع شود، probe ممکن است شکست بخورد. برای سرویس db که خودش healthcheck معتبر دارد، می‌توان از depends_on با شرط service_healthy استفاده کرد:

services:
  web:
    depends_on:
      db:
        condition: service_healthy

این تنظیم به ترتیب راه‌اندازی اولیه کمک می‌کند، اما جایگزین Retry در برنامه نیست. restart: true در depends_on با Restart Policy کانتینر متفاوت است.

گام هشتم: اعمال تغییر و Verify

force-recreate ممکن است قطعی ایجاد کند؛ از Compose و داده‌ها بکاپ بگیرید.

cp compose.yaml compose.yaml.bak
docker compose config
docker compose up -d --no-deps --force-recreate web
docker compose ps
docker compose ps -q web

برای بررسی Health.Status از شناسه واقعی کانتینر که docker compose ps -q web می‌دهد استفاده کنید؛ نام کانتینر لزوماً web نیست:

docker inspect --format '{{json .State.Health}}' web

پس از چند probe موفق، Status=healthy و FailingStreak=0 انتظار می‌رود. مسیر کاربر را هم تست کنید.

Rollback امن در صورت خراب‌شدن سرویس

اگر تغییر خراب شد، Compose قبلی را برگردانید؛ Rollback ایمیج و دیتابیس جداست.

cp compose.yaml.bak compose.yaml
docker compose config
docker compose up -d --no-deps --force-recreate web

اگر دیسک یا لاگ‌ها پر شده‌اند، ابتدا فضای ذخیره‌سازی را بررسی کنید. حذف Volume و داده‌های پایدار برای رفع unhealthy راهکار امنی نیست.

برای مدیریت دیسک کنترل لاگ Docker را ببینید. VPS وان‌سرور برای میزبانی کانتینر مناسب است.

مرجع: Docker HEALTHCHECK.

پرسش‌های متداول

آیا unhealthy یعنی کانتینر خاموش است؟

نه؛ کانتینر ممکن است Running باشد.

آیا unhealthy باعث Restart می‌شود؟

خیر؛ Docker Engine خودکار Restart نمی‌کند.

Rate this post
اشتراک گذاری نوشته در:

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *