ممکن است process داخل container هنوز اجرا شود، اما برنامه connection نپذیرد، threadهایش گیر کرده باشند یا initialization کامل نشده باشد. Healthcheck یک فرمان دورهای است که Docker داخل context کانتینر اجرا میکند و با exit code مشخص میگوید سرویس سالم است یا نه. این وضعیت به عیبیابی و ترتیب شروع کمک میکند، اما بهتنهایی ترافیک را جابهجا یا container را restart نمیکند.
پاسخ سریع: یک probe سریع، کمهزینه و محلی بسازید که قابلیت اصلی سرویس را بسنجد؛ timeout، interval، start period و retries را از زمان واقعی startup و خطای قابلتحمل تعیین کنید. خروجی کوتاه و بدون secret باشد. نتیجه را در deployment و monitoring مصرف کنید و تصور نکنید وضعیت unhealthy همان exit یا restart است.
وضعیت Process با Health چه فرقی دارد؟
Docker بدون Healthcheck عمدتاً میداند PID اصلی اجراست یا خارج شده. یک وبسرور میتواند PID داشته باشد ولی پاسخ ندهد. Healthcheck بعد دیگری با وضعیتهای starting، healthy و unhealthy اضافه میکند. اگر PID اصلی خارج شود، container stopped/exited است؛ اگر probe شکست بخورد اما PID زنده باشد، container معمولاً همچنان running و unhealthy میماند.
Liveness، Readiness و Startup را قاطی نکنید
در Docker Engine یک Healthcheck عمومی دارید، برخلاف بعضی orchestratorها که probeهای جدا دارند. باید بدانید نتیجه را برای چه تصمیمی مصرف میکنید. check آمادهبودن برای ترافیک میتواند وابستگی ضروری را بسنجد؛ check زندهبودن نباید با اختلال کوتاه سرویس بیرونی باعث restart آبشاری شود. start_period به برنامه زمان initialization میدهد، ولی طراحی startup سالم همچنان لازم است.
یک Probe خوب چه ویژگی دارد؟
- در چند ثانیه و با منابع کم تمام میشود.
- به قابلیت واقعی نزدیک است، نه فقط وجود process.
- داده یا تراکنش دائمی ایجاد نمیکند.
- برای اجرا به secret گسترده نیاز ندارد.
- خروجی کوتاه، قابلفهم و بدون اطلاعات حساس دارد.
- در صورت failure exit code غیرصفر برمیگرداند.
endpoint سلامت نباید سفارش، ایمیل یا job واقعی بسازد. اگر فقط صفحه static را میخواند، ممکن است خرابی runtime را نبیند؛ اگر تمام dependencyهای جهان را میسنجد، false negative و cascade ایجاد میکند.
گزینههای زمانبندی
interval فاصله checkها، timeout سقف اجرای هر check، retries تعداد failure متوالی برای unhealthy شدن و start_period مهلت startup است. نسخههای جدید Engine همچنین start_interval دارند. پیشفرضها را کورکورانه نپذیرید؛ startup سرد، load اوج و latency داخلی را اندازه بگیرید. timeout باید از پاسخ معمول بزرگتر اما برای کشف failure بهاندازه کافی کوتاه باشد.
رفتار Start Period را درست بفهمید
failureهای داخل start period معمولاً در شمارش retries نهایی وارد نمیشوند، اما اگر probe در همان دوره یکبار موفق شود، container شروعشده محسوب میشود و failureهای بعدی حساب میشوند. بنابراین probeای که پیش از آمادهبودن کامل گاهی 200 میدهد، میتواند وضعیت ناپایدار بسازد. endpoint readiness را تا تکمیل initialization صادق نگه دارید.
نمونه Compose برای سرویس HTTP
services:
app:
image: registry.example/app@sha256:...
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8080/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 20s
این نمونه فقط وقتی معتبر است که image واقعاً curl داشته باشد و برنامه داخل container روی 127.0.0.1:8080 گوش دهد. برای image مینیمال، binary یا script کوچک خود برنامه بهتر از افزودن ابزار بزرگ فقط برای probe است. زمانها نمونهاند و باید با برنامه تنظیم شوند. digest نیز باید artifact واقعی باشد.
CMD یا CMD-SHELL؟
فرم exec آرایهای مستقیماً فرمان را اجرا میکند و به shell expansion متکی نیست. CMD-SHELL برای pipe، متغیر و شرط shell لازم میشود، اما quoting و وجود shell داخل image را باید در نظر گرفت. اگر credential را در command یا خروجی قرار دهید، inspect و health log میتواند آن را افشا کند. exit code صفر موفق، یک failure و دو رزروشده است؛ از معنای مبهم پرهیز کنید.
آیا Healthcheck باید دیتابیس را بسنجد؟
اگر بدون دیتابیس هیچ درخواست معناداری ممکن نیست، readiness ممکن است اتصال سبک را بررسی کند. اما restart کردن همه appها در اختلال دیتابیس میتواند فشار reconnect را بیشتر کند. اتصال، query بسیار سبک و pool saturation اهداف متفاوتاند. سلامت دیتابیس را جدا مانیتور کنید و برنامه retry با backoff داشته باشد. probe نباید schema migration یا write انجام دهد.
Healthcheck و Compose depends_on
با شرط service_healthy، Compose میتواند شروع سرویس وابسته را تا سلامت dependency عقب بیندازد. این کار startup race را کم میکند، اما اگر dependency ساعت بعد unhealthy شود، recovery کامل سرویسها خودکار تضمین نمیشود. برنامه باید قطع و بازگشت dependency را تحمل کند. ترتیب start جایگزین timeout، retry و circuit breaker نیست.
Unhealthy به معنی Restart نیست
Restart Policy معمول Docker به exit container واکنش دارد، نه صرفاً health status. اگر قرار است unhealthy شدن باعث جابهجایی ترافیک یا restart شود، orchestrator یا automation جدا باید آن را با guard و backoff انجام دهد. اتصال ساده «هر unhealthy را فوراً restart کن» میتواند شواهد را پاک و outage dependency را به restart storm تبدیل کند. راهنمای Restart Policy این مرز را توضیح میدهد.
عیبیابی Probe شکستخورده
- health status و خروجی آخرین checkها را با inspect بخوانید.
- همان فرمان را با user و environment واقعی داخل container اجرا کنید.
- وجود binary، DNS، پورت و مسیر endpoint را بررسی کنید.
- زمان اجرای probe را با timeout مقایسه کنید.
- log برنامه و dependency را در همان timestamp ببینید.
- مشخص کنید failure واقعی است یا خود probe معیوب.
خروجی health محدود است؛ آن را کوتاه نگه دارید و جزئیات را با correlation مناسب در log برنامه پیدا کنید. تغییر check به true یا غیرفعالکردن آن برای سبزشدن داشبورد، مشکل را فقط پنهان میکند.
هزینه و Thundering Herd
اگر صدها container دقیقاً هر پنج ثانیه query سنگین بزنند، خود healthcheck load میسازد. interval و jitter در لایه مانیتورینگ، endpoint cacheشده کوتاهمدت و check محلی میتواند اثر را کم کند. check نباید connection تازه پرهزینه یا process بزرگ ایجاد کند. مصرف CPU و latency probe را در بار واقعی بسنجید.
خروجی Probe و Eventهای سلامت
Docker بخشی محدود از stdout/stderr آخرین اجراهای healthcheck را در State نگه میدارد و هنگام تغییر وضعیت event تولید میکند. پیام probe را مانند یک تشخیص کوتاه بنویسید: نام check، مدت و دلیل عمومی؛ نه body کامل پاسخ یا credential. collector میتواند event healthy/unhealthy را به metric تبدیل کند، اما flapping باید با duration و deduplication کنترل شود. timestamp کانتینر و host را هماهنگ نگه دارید تا نتیجه probe با log برنامه قابلمقایسه باشد.
امنیت Endpoint سلامت
مسیر health اگر عمومی باشد نباید نسخه دقیق dependency، hostname داخلی، stack trace یا secret را افشا کند. برای check عمیقتر میتوان endpoint داخلی روی network محدود یا فرمان محلی داشت. افزودن authentication سنگین به هر probe ممکن است dependency تازه بسازد؛ دسترسی شبکه و پاسخ حداقلی را ترجیح دهید. نتیجه بیرونی میتواند فقط success/failure باشد و جزئیات در telemetry محافظتشده ذخیره شود.
Healthcheck داخلی کافی نیست
check داخل container خرابی DNS عمومی، TLS، reverse proxy، firewall یا مسیر کاربر را نمیبیند. مانیتور بیرونی HTTP و journey حیاتی را کنار آن داشته باشید. راهنمای مانیتورینگ سرور تفاوت دید داخلی و تجربه کاربر را باز میکند. healthy بودن app بدون سلامت پرداخت یا queue هنوز میتواند outage کسبوکار باشد.
اشتباههای رایج
- بررسی فقط PID یا صفحه static نامرتبط
- probe دارای write یا اثر جانبی
- وابستهکردن liveness به چند API بیرونی
- timeout کمتر از رفتار عادی startup
- استفاده از ابزاری که در image وجود ندارد
- چاپ token و جزئیات حساس در خروجی health
- انتظار restart خودکار از وضعیت unhealthy
چه زمانی طراحی حرفهای لازم است؟
اگر rollout بهعلت probe ناپایدار متوقف میشود یا restartهای آبشاری دارید، contract سلامت باید از dependency و SLO جدا شود. داکرایز اپلیکیشن میتواند endpoint، Compose، proxy و pipeline را با معیارهای واقعی readiness هماهنگ کند.
پرسشهای متداول
آیا Docker container unhealthy را خودکار restart میکند؟
Restart Policy معمول به exit واکنش دارد، نه صرفاً unhealthy شدن.
چرا Healthcheck همیشه starting میماند؟
زمانبندی، اجرای طولانی probe، startup یا config check را با inspect و log بررسی کنید.
آیا curl را فقط برای health نصب کنیم؟
الزامی نیست؛ probe بومی سبک یا binary موجود میتواند سطح و حجم image را کمتر نگه دارد.
چند dependency را در health بررسی کنیم؟
فقط آنچه برای تصمیم مصرفکننده ضروری است؛ سلامت هر dependency را جدا نیز مانیتور کنید.