رفع مشکل 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 webdocker 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 1interval فاصله تست، 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.
پرسشهای متداول
نه؛ کانتینر ممکن است Running باشد.
خیر؛ Docker Engine خودکار Restart نمیکند.