
نویسنده مقاله در تجربهای واقعی توضیح میدهد که چرا بالا بودن یک کانتینر (Container) در داکر (Docker) به معنای سالم بودن سرویس نیست. او پس از بروز خطای پایگاه داده در سرویس Nextcloud، تصمیم گرفت به همه کانتینرهای هوملب (Homelab) خود بررسی سلامت (Health Check) اضافه کند و سپس با یک ناظر خودکار، سرویسهای ناسالم را ریاستارت کند.
چرا «در حال اجرا» به معنای «سالم» نیست؟
داکر تنها چرخه عمر کانتینر (Container Lifecycle) را رصد میکند؛ یعنی بررسی میکند که فرایند اصلی (Main Process) زنده است یا نه. اما این موضوع لزوماً به معنای پاسخدهی صحیح اپلیکیشن داخل کانتینر نیست. نویسنده برای اثبات این ادعا یک کانتینر آزمایشی Nginx ساخت و سپس فایل پیکربندی پیشفرض آن را از داخل حذف کرد. در این حالت، دستور curl نشان میداد سرویس خراب است، اما docker ps همچنان کانتینر را در وضعیت Up نشان میداد.
تجربه Nextcloud و Watchtower
چند هفته پیش، نویسنده از Watchtower برای بهروزرسانی خودکار ایمیجهای داکر استفاده میکرد. Watchtower یک ایمیج جدید از Nextcloud را دریافت کرد، اما کد جدید جلوتر از شِمای پایگاه داده (Database Schema) بود و خطای نسخهشکننده ایجاد کرد. راهحل فوری اجرای دستور docker exec nextcloud php occ upgrade بود. با این حال، چون کانتینر در داکر همچنان Up نمایش داده میشد، سرویسهای مانیتورینگ متوجه خرابی اپلیکیشن نشدند.
بررسی سلامت موجود در کانتینرها
نویسنده ابتدا بررسی کرد کدام کانتینرها از قبل Health Check داخلی دارند. از میان ۲۸ کانتینر در حال اجرا، ۱۰ کانتینر بررسی سلامت داشتند و ۱۸ کانتینر دیگر فاقد آن بودند. Nextcloud نیز در دسته بدون بررسی سلامت قرار داشت. او با دستورهای docker inspect و docker exec جزئیات بررسیها را استخراج کرد:
- بیشتر کانتینرهای دارای Health Check پس از حدود ۹۰ ثانیه (۳ تلاش ۳۰ ثانیهای) خرابی را نشان میدادند.
- سرویس Immich دیرتر عمل میکرد و حدود ۱۵ دقیقه طول میکشید تا خرابی را گزارش کند.
- در ۱۸ کانتینر دیگر، وجود curl یا wget بررسی شد؛ بیشتر آنها حداقل یکی از این ابزارها را داشتند، اما چند کانتینر از جمله nextcloud_db هیچکدام را نداشتند.
- Portainer و beszel-agent حتی شل (Shell) در دسترس ندارند.
افزودن Health Check در Docker Compose
پس از این بررسیها، نویسنده به فایلهای Docker Compose خود Health Check اضافه کرد و سرویسها را دوباره مستقر کرد. برای نمونه، در فایل Compose مربوط به Stirling PDF خطوطی مانند برچسب autoheal=true و یک healthcheck با دستور CMD-SHELL اضافه شد که با curl وضعیت http://localhost:8080/api/v1/info/status را بررسی میکند. تنظیمات این بررسی شامل interval برابر ۳۰ ثانیه، timeout برابر ۵ ثانیه، retries برابر ۳ و start_period برابر ۹۰ ثانیه بود.
ناظر خودکار و ریاستارت سرویسهای ناسالم
در مرحله بعد، یک اسکریپت ناظر (Watcher) زیر systemd راهاندازی شد. این اسکریپت به جریان رویدادهای وضعیت سلامت داکر (Docker Health-Status Event Stream) گوش میدهد و هر زمان وضعیت کانتینری unhealthy شود، آن را ریاستارت میکند. تعداد ریاستارتها در حافظه ذخیره میشود و حداکثر سه بار در ۳۰ دقیقه محدود شده است تا از حلقه بیپایان جلوگیری شود. این ناظر فقط روی کانتینرهایی عمل میکند که برچسب autoheal=true داشته باشند. هر ریاستارت و همچنین توقف محافظ حلقه، از طریق کانال ntfy به نویسنده اطلاع داده میشود.
برای آزمایش، نویسنده فرایند Java داخل کانتینر Stirling PDF را فریز کرد. حدود ۹۰ ثانیه بعد کانتینر unhealthy شد، ناظر در حدود ۱۰ ثانیه آن را ریاستارت کرد و حدود ۳۰ ثانیه بعد کانتینر دوباره healthy شد. در مجموع، بازیابی سرویس حدود دو دقیقه طول کشید.
خودریاستارت شدن با خودترمیمی متفاوت است
نویسنده تأکید میکند که این اسکریپت پیکربندی خراب را تشخیص نمیدهد و آن را اصلاح نمیکند. برای مثال در مورد Nextcloud، اگر اسکریپت در آن زمان فعال بود، فقط میتوانست کانتینر را ریاستارت کند؛ اما ریاستارت بهتنهایی مهاجرت (Migration) موردنیاز پایگاه داده را اجرا نمیکند. به گفته او، خودریاستارت شدن (Self-Restarting) با خودترمیمی (Self-Healing) یکسان نیست. او احتمال میدهد در آینده با افزودن یک مدل زبانی محلی (Local LLM) اسکریپت را ارتقا دهد، اما فعلاً همین وضعیت نیمهکاره را قابل نگهداشتن میداند.
جمعبندی
به باور نویسنده، اسکریپت ناظر بخش خستهکننده بررسی سلامت کانتینرهای برچسبخورده و ریاستارت آنها را خودکار میکند، اما هنوز کامل نیست. با این حال، اگر چند سرویس را بهصورت خودمیزبان (Self-Hosted) اجرا میکنید، داشتن یک Health Check مناسب ضروری است.