وبلاگ نت‌آرامآموزش، تجربه و راهکارهای زیرساخت

کانتینر Docker روشن است اما unhealthy می‌شود؛ چطور مشکل را پیدا کنیم؟

راهنمای خواندن خروجی healthcheck، تشخیص ابزار یا آدرس اشتباه و تنظیم آزمون سلامت Docker Compose.

انتشار:
توسط تیم فنی نت‌آرام
۸ دقیقه زمان مطالعه
۰ دیدگاه
محتوای تخصصی، ساده و کاربردی
هماهنگ با هویت حرفه‌ای نت‌آرام
بازگشت به لیست مقالات
تصویر شاخص مقاله کانتینر Docker روشن است اما unhealthy می‌شود؛ چطور مشکل را پیدا کنیم؟ در وبلاگ نت‌آرام
محتوای آموزشی وبلاگ نت‌آرام
در docker ps می‌بینید کانتینر Up است، اما کنار نام آن وضعیت unhealthy نوشته شده است. این دو عبارت متناقض نیستند: پردازش اصلی کانتینر هنوز اجرا می‌شود، ولی آزمون سلامت آن چند بار موفق نشده است. ممکن است خود برنامه پاسخ ندهد، اما ممکن است آدرس یا ابزار آزمون هم اشتباه باشد.
برای رفع مشکل، اول خروجی همان آزمون را می‌خوانیم، سپس پاسخ برنامه و علت‌های معمول مثل پورت نادرست، نبودن ابزار و کندی راه‌اندازی را جدا می‌کنیم. در پایان، تنظیم اصلاح‌شده را با درخواست واقعی آزمایش می‌کنیم.
به SSH و دسترسی مجاز به Docker نیاز دارید. نام myapp، سرویس web، پورت ۸۰۸۰ و مسیر /health در این مقاله نمونه‌اند؛ نام و پورت واقعی برنامه شما ممکن است متفاوت باشد. فرمان‌های Docker را با کاربری اجرا کنید که مجوز لازم دارد؛ در بعضی سیستم‌ها به sudo نیاز است. دسترسی به Docker می‌تواند بسیار قدرتمند باشد، پس آن را به حساب نامطمئن ندهید.

۱. وضعیت کانتینر و خود healthcheck را ببینید

کد / دستورdocker ps -a --filter 'name=myapp'
نام کانتینر و ستون STATUS را بررسی کنید. Up (unhealthy) یعنی کانتینر در حال اجراست اما آزمون سلامت شکست خورده است. اگر کانتینر Exited یا در حال restart است، اول باید علت خروج پردازش را از گزارش آن پیدا کنید.
پیکربندی healthcheck مؤثر را ببینید:
کد / دستورdocker inspect --format '{{json .Config.Healthcheck}}' myapp
اگر خروجی null است، برای این کانتینر healthcheck تعریف نشده یا وضعیت دیگری باید بررسی شود. در غیر این صورت، فرمان، فاصله، timeout و تعداد تلاش‌ها نمایش داده می‌شوند. این تنظیم ممکن است از Dockerfile یا فایل Compose آمده باشد. خروجی می‌تواند نشانی یا اطلاعات خصوصی داشته باشد؛ پیش از ارسال برای دیگران آن‌ها را حذف کنید.
اکنون نتیجه‌های اخیر آزمون را بخوانید:
کد / دستورdocker inspect --format '{{json .State.Health}}' myapp
در بخش Log، زمان، ExitCode و Output هر آزمون را ببینید. کد صفر نشان‌دهنده موفقیت آزمون است و کد غیرصفر به شکست آن اشاره می‌کند. Docker فقط بخشی از متن خروجی آزمون را نگه می‌دارد؛ بنابراین بهتر است پیام بررسی سلامت کوتاه و بدون رمز باشد. اگر سلامت هنوز در حالت starting است، مدت راه‌اندازی و فاصله آزمون را در نظر بگیرید.

۲. پیام آزمون به کدام علت اشاره می‌کند؟

چند پیام متداول و قدم بعدی:
  • curl: not found یا کد ۱۲۷: ابزار مورد استفاده در image وجود ندارد یا مسیر آن اشتباه است.
  • Connection refused: در آدرس و پورت آزمون، برنامه اتصال را نمی‌پذیرد؛ شاید برنامه هنوز بالا نیامده یا پورت دیگری دارد.
  • خطای HTTP مثل ۴۰۴ یا ۵۰۰: مسیر آزمون وجود ندارد، یا برنامه در پاسخ واقعی خود خطا می‌دهد.
  • timeout: برنامه، وابستگی آن یا سقف زمان آزمون باید بررسی شود؛ افزایش timeout بدون شناخت علت کافی نیست.
گزارش خود برنامه را جداگانه بخوانید:
کد / دستورdocker logs --since 15m --tail 100 myapp
docker logs خروجی اصلی برنامه را نشان می‌دهد؛ متن healthcheck معمولاً در نتیجه docker inspect است. ساعت دو گزارش را تطبیق دهید. اگر لاگ خطای دیتابیس یا تنظیمات برنامه دارد، آن علت را هم‌زمان با آزمون سلامت بررسی کنید.

۳. آدرس را از داخل همان کانتینر امتحان کنید

اگر image ابزار curl دارد و برنامه واقعاً روی پورت ۸۰۸۰ و مسیر /health گوش می‌دهد:
کد / دستورdocker exec myapp curl -fsS --max-time 3 http://127.0.0.1:8080/health
این فرمان داخل کانتینر اجرا می‌شود. -f باعث می‌شود خطاهای HTTP مانند ۴۰۴ و ۵۰۰ به شکل شکست برگردند، -sS خروجی را ساده‌تر می‌کند و --max-time 3 سقف انتظار است. اگر مسیر سلامت شما جواب دیگری دارد، آدرس را مطابق مستند برنامه تغییر دهید. خروجی موفق معمولاً پاسخ همان endpoint است؛ بلافاصله echo $? باید صفر نشان دهد.
اگر می‌گوید curl وجود ندارد، این الزاماً خرابی برنامه نیست. بعضی imageهای سبک حتی shell هم ندارند. از ابزار سلامت موجود در خود برنامه یا image استفاده کنید، یا نسخه image را با ابزار لازم به‌صورت کنترل‌شده بسازید. نصب دستی و موقت ابزار داخل کانتینر در حال اجرا بعد از بازسازی آن از بین می‌رود و روش پایدار اصلاح تنظیم نیست.
برای دیدن پورت‌های منتشرشده به میزبان:
کد / دستورdocker port myapp
پورت میزبان و پورت داخلی کانتینر می‌توانند متفاوت باشند. مثلاً نگاشت 8088:8080 یعنی از میزبان به ۸۰۸۸ وصل می‌شوید، ولی healthcheck داخل کانتینر معمولاً باید پورت داخلی ۸۰۸۰ را هدف بگیرد. 127.0.0.1 داخل کانتینر به همان کانتینر اشاره دارد، نه به لپ‌تاپ شما یا یک کانتینر دیگر. اگر چند سرویس جدا دارید، از نام سرویس و شبکه درست Compose استفاده کنید.

۴. اگر برنامه واقعاً پاسخ نمی‌دهد

پیام Connection refused را با لاگ برنامه و پورت واقعی کنار هم بگذارید. اگر برنامه روی پورت دیگری راه افتاده، healthcheck را به همان پورت اصلاح کنید. اگر برنامه به علت نرسیدن به دیتابیس آماده نمی‌شود، وضعیت وابستگی را جداگانه ببینید:
کد / دستورdocker ps -a کد / دستورdocker logs --since 15m --tail 100 database
نام database را با نام واقعی کانتینر دیتابیس جایگزین کنید. رمز، اطلاعات اتصال و داده مشتریان را از گزارش حذف کنید. نام سرویس دیتابیس در شبکه، پورت داخلی و حساب دسترسی را با تنظیمات برنامه تطبیق دهید. اگر دیتابیس سالم نیست، تغییر پیام healthcheck برنامه علت اصلی را حل نمی‌کند.
در محیط Compose، depends_on ساده ترتیب شروع را مشخص می‌کند، اما به‌تنهایی آماده بودن دیتابیس را تضمین نمی‌کند. در صورت پشتیبانی نسخه و وجود آزمون سلامت معتبر برای وابستگی، condition: service_healthy می‌تواند در شروع منتظر سالم شدن آن بماند. این تنظیم جای رسیدگی به قطعی‌های بعدی و تلاش مجدد خود برنامه را نمی‌گیرد.
اگر پاسخ فقط زیر بار کند می‌شود، مصرف لحظه‌ای را ببینید:
کد / دستورdocker stats --no-stream myapp
CPU و حافظه را با محدودیت کانتینر، زمان پاسخ و لاگ هم‌زمان مقایسه کنید. یک عکس لحظه‌ای به‌تنهایی علت قطعی کندی نیست. افزایش منابع ممکن است لازم باشد، اما خطای پورت، مسیر یا کد برنامه را به‌تنهایی درست نمی‌کند.

۵. یک نمونه اصلاح healthcheck در Compose

فرض کنید مستند برنامه شما تأیید می‌کند داخل کانتینر curl و shell وجود دارند، endpoint /health روی پورت داخلی ۸۰۸۰ پاسخ معتبر می‌دهد و برنامه برای راه‌اندازی حدود یک دقیقه زمان می‌خواهد. در فایل Compose مربوط به سرویس واقعی، می‌توانید تنظیمی مشابه زیر داشته باشید:
کد / دستورservices: web: healthcheck: test: ["CMD-SHELL", "curl -fsS --max-time 3 http://127.0.0.1:8080/health >/dev/null || exit 1"] interval: 30s timeout: 5s retries: 3 start_period: 60s
این نمونه فقط بخش healthcheck است؛ سایر تنظیمات سرویس را حذف نکنید. interval فاصله میان آزمون‌ها، timeout بیشترین زمان هر آزمون و retries تعداد شکست‌های پیاپی برای unhealthy شدن است. start_period فرصت آماده‌شدن اولیه می‌دهد؛ آزمون‌ها در این مدت ممکن است اجرا شوند، اما شکست‌های شروع معمولاً شمارش نمی‌شوند. اگر در همان دوره یک آزمون موفق شود، شکست‌های بعدی شمارش می‌شوند.
آدرس، مدت‌ها و خود آزمون را بر اساس برنامه خودتان انتخاب کنید. اگر endpoint نیاز به احراز هویت دارد، رمز را در دستور و لاگ healthcheck قرار ندهید. بهتر است برنامه یک آزمون داخلی و کم‌اطلاعات برای وضعیت خود فراهم کند و دسترسی آن مطابق معماری سرویس محدود شود.
از پوشه پروژه Compose، قبل از اعمال تغییر، اعتبار فایل را بررسی کنید:
کد / دستورdocker compose config --quiet
اگر خطا داد، تورفتگی YAML، نام فایل و متغیرهای لازم را اصلاح کنید. این دستور صحت واقعی endpoint را آزمایش نمی‌کند. از فایل قبلی و داده برنامه نسخه پشتیبان داشته باشید. در زمان مجاز، پس از بررسی اثر بازسازی کانتینر:
کد / دستورdocker compose up -d --no-deps web
این عملیات ممکن است کانتینر سرویس web را بازسازی کند و قطع کوتاه ایجاد کند؛ داده‌ها و محل volumeها را پیش از آن بشناسید. از دستورهای حذف volume برای رفع خطای سلامت استفاده نکنید.

۶. تأیید کنید مشکل واقعاً رفع شده است

چند نوبت healthcheck صبر کنید و دوباره وضعیت را ببینید:
کد / دستورdocker inspect --format '{{json .State.Health}}' myapp
نام کانتینر پس از بازسازی ممکن است عوض شده باشد؛ با docker ps نام جدید را پیدا کنید. باید آزمون‌ها موفق شوند و وضعیت به healthy برسد. سپس یک درخواست واقعی از مسیر کاربر بفرستید و وابستگی‌ها را هم امتحان کنید. سالم بودن یک endpoint ساده همیشه تضمین نمی‌کند همه امکانات برنامه درست کار می‌کنند.
خود Docker صرفاً به دلیل وضعیت unhealthy الزاماً کانتینر را restart نمی‌کند؛ رفتار orchestration یا ابزارهای دیگر ممکن است متفاوت باشد. اگر می‌خواهید علت آماده نبودن وابستگی در شروع را عمیق‌تر بررسی کنید، مستند ترتیب شروع سرویس‌ها در Compose را بخوانید.
این مراحل روی سرور مجازی ایران و سرور اختصاصی ایران با Docker یکسان‌اند. جزئیات کد خروج و زمان‌بندی آزمون در مرجع HEALTHCHECK داکر آمده است.
اشتراک‌گذاری:
لینکدینتلگرامایکس

دیدگاه‌ها (۰)

دیدگاه‌های تاییدشده و پاسخ‌های تیم نت‌آرام