Health Check Docker yang Benar-Benar Berguna
Kenapa "container jalan" beda dengan "aplikasi siap"
Salah satu kesalahan paling umum yang saya lihat waktu menata stack Docker adalah menganggap container yang statusnya Up berarti aplikasinya siap menerima trafik. Padahal Docker secara default cuma memantau proses utama (PID 1) di dalam container. Selama proses itu belum crash, status container akan tetap "running" — walaupun di dalamnya PHP-FPM baru setengah jalan, koneksi ke database belum terbentuk, atau migrasi belum selesai.
Ini jadi masalah nyata kalau ada orkestrasi di baliknya: load balancer yang mulai mengirim request sebelum aplikasi benar-benar siap, atau service lain yang depends_on container tersebut tapi langsung jalan begitu container "hidup", bukan begitu container "siap". Health check yang benar itu fungsinya menjawab pertanyaan yang lebih tepat: bisakah aplikasi ini melayani request sekarang juga?
Menulis health check yang mengecek kesiapan, bukan sekadar proses
Prinsip yang saya pegang: health check idealnya memanggil jalur yang benar-benar merepresentasikan kesiapan aplikasi, bukan sekadar cek port terbuka. Untuk aplikasi web berbasis Laravel misalnya, saya biasa membuat endpoint khusus, semacam /healthz, yang melakukan pengecekan ringan tapi bermakna: koneksi database bisa dibuka, cache driver merespons, dan storage bisa diakses. Contoh sederhana di docker-compose.yml:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/healthz"]
interval: 10s
timeout: 3s
retries: 5
start_period: 30s
start_period ini penting dan sering dilewatkan. Ini adalah masa toleransi di awal container hidup di mana kegagalan health check belum dihitung sebagai "unhealthy" — cocok untuk aplikasi yang butuh waktu warm-up, misalnya menunggu migrasi database atau membangun cache konfigurasi. Tanpa start_period yang wajar, container bisa berulang kali ditandai gagal padahal cuma butuh waktu lebih untuk boot.
Satu hal yang perlu diingat: endpoint health check sebaiknya ringan dan cepat. Jangan taruh query berat atau pemanggilan ke layanan LLM eksternal di dalamnya — itu tugas endpoint lain, bukan health check yang dipanggil setiap beberapa detik.
Memanfaatkan health check untuk orkestrasi, bukan cuma monitoring
Nilai sebenarnya dari health check yang baik terasa waktu dipakai untuk mengatur urutan start antar service. Docker Compose punya depends_on dengan kondisi service_healthy, yang jauh lebih andal dibanding sekadar menunggu container lain "up":
depends_on:
db:
condition: service_healthy
Dengan pola ini, container aplikasi baru akan benar-benar mulai setelah database dinyatakan sehat oleh health check-nya sendiri — bukan cuma setelah proses mysqld atau postgres tereksekusi. Ini menghilangkan satu kelas bug klasik: aplikasi yang crash di detik-detik awal karena mencoba konek ke database yang masih dalam proses inisialisasi.
Untuk sistem yang lebih besar, misalnya stack dengan beberapa service backend dan reverse proxy seperti yang saya jalankan di pujamalca.my.id, kombinasi health check yang tepat plus depends_on bertingkat membuat proses docker compose up jauh lebih dapat diprediksi — tidak perlu lagi restart manual berkali-kali cuma karena urutan start yang berantakan.
Kesalahan yang sering saya temui
- Health check yang cuma
CMD-SHELLmengecek port terbuka (misalnya lewatnc), tanpa mengecek dependency internal seperti koneksi database. - Interval terlalu agresif sehingga membebani aplikasi, atau terlalu longgar sehingga status "unhealthy" baru terdeteksi lama setelah masalah terjadi.
- Endpoint health check yang justru memicu efek samping, misalnya menulis log berat setiap kali dipanggil.
- Lupa membedakan liveness (proses masih hidup) dan readiness (siap melayani) — keduanya bisa butuh mekanisme dan respons berbeda tergantung kompleksitas aplikasinya.
Intinya: health check yang berguna adalah yang mencerminkan kesiapan nyata aplikasi, punya toleransi waktu warm-up yang wajar, dan dimanfaatkan aktif untuk mengatur urutan start antar service — bukan sekadar checklist yang ditempel di docker-compose.yml lalu dilupakan.