Baris health_status: healthy yang menutup Chapter Docker Events lahir dari sumber yang unik: bukan proses yang hidup atau mati, melainkan probe — perintah kecil yang daemon jalankan berkala di dalam container untuk menanyakan langsung ke aplikasi. Kita telah dua kali menjumpai konsep ini: probe ditanam ke image lewat HEALTHCHECK pada Chapter HEALTHCHECK, lalu dideklarasikan per service di compose.yaml pada Chapter Healthcheck dan Service Readiness — dan keduanya bekerja diam-diam di belakang gerbang service_healthy yang menjaga urutan start stack toko. Chapter ini membalik posisi kita dari perancang probe menjadi pembaca statusnya: apa yang dikatakan healthy, unhealthy, dan starting, bagaimana membaca laporan lengkapnya, dan — pertanyaan yang paling sering mengejutkan operator baru — apa yang Docker lakukan ketika container-nya sakit berat.
Probe yang Menilai Kesehatan #
Recap singkat untuk menyamankan pijakan: HEALTHCHECK pada Dockerfile menanam probe ke dalam image, sedangkan kunci healthcheck di compose.yaml menimbangnya kembali per service tanpa menyentuh Dockerfile pihak ketiga. Backend toko memakai bentuk kedua — probe yang mengetuk endpoint /healthz, jalur yang di dalamnya mengeksekusi SELECT 1 sungguhan ke database:
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/healthz"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s
start_interval: 5sProbe itu menjalankan dua tugas sekaligus di stack toko: menjaga kejujuran kolom STATUS — operator melihat kesehatan, bukan sekadar napas proses — dan membuka gerbang depends_on dengan kondisi service_healthy, sehingga proxy hanya menyala setelah backend benar-benar menjawab; keduanya sudah kita rancang tuntas pada Chapter Startup dan Dependency. Nilai start_period adalah masa grasi: selama lima detik pertama kegagalan probe tidak dihitung, memberi Node waktu membaca environment dan membuka pool koneksi sebelum dinilai.
Siklus statusnya ringkas dan bisa diprediksi. Container yang baru menyala berstatus health: starting; begitu probe pertama lulus, status naik menjadi healthy. Setiap kegagalan probe menambah penghitung kegagalan beruntun — FailingStreak — dan begitu penghitung menyamai retries (tiga untuk backend), status jatuh menjadi unhealthy. Probe tidak pernah berhenti setelah kegagalan: bila kelak probe lulus kembali, penghitung direset dan status pulih ke healthy dengan sendirinya.
Backend Demam Saat Proses Tetap Hidup #
Skenario chapter ini datang dari pagi yang sibuk. Siti menarik laporan rekapnya dan perubahan kecil pada konfigurasi service db, lalu menjalankan docker compose up -d seperti biasa. Sejam kemudian Budi membuka daftar stack dan menemukan pemandangan yang membingungkan pendatang baru:
$ docker compose psOutput yang Dihasilkan:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
toko-proxy-1 nginx:1.29-alpine "/docker-entrypoint.…" proxy 2 hours ago Up 2 hours 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
toko-frontend-1 nginx:1.29-alpine "/docker-entrypoint.…" frontend 2 hours ago Up 2 hours 80/tcp
toko-backend-1 toko-api:dev "docker-entrypoint.s…" backend About an hour ago Up 70 minutes (unhealthy) 3000/tcp
toko-cache-1 redis:7-alpine "docker-entrypoint.s…" cache 2 hours ago Up 2 hours (healthy)
toko-db-1 postgres:18-alpine "docker-entrypoint.s…" db About a minute ago Up 36 seconds (healthy) 5432/tcpMari kita telaah kejanggalan pada tabel itu:
- Backend demam, tetapi prosesnya tetap hidup —
Up 70 minutes (unhealthy)adalah paradoks yang justru inti healthcheck: proses node tidak pernah mati,docker psversi lama akan menyebutnya sehat, tetapi probe menilai sebaliknya. Kolom STATUS akhirnya jujur. - Angka
(unhealthy)bukan hiasan — status itu dijaga oleh probe/healthz; frontend yang tidak punya healthcheck hanya menampilkanUp 2 hourspolos, dan bandingannya membuat makna tanda kurung terlihat jelas. - Baris db menyimpan petunjuk penyebab —
toko-db-1jauh lebih muda dari seluruh tetangganya: diciptakanAbout a minute ago, berjalan baru36 seconds, padahal stack berumur dua jam lebih. Container db yang baru diciptakan sesaat lalu adalah kabar besar bagi siapa pun yang menggantungkan koneksi padanya.
Kronologi Sehat ke Sakit dari Aliran Events #
Kosakata Chapter Docker Events terpakai langsung untuk membangun garis waktu backend — penyaring per objek, mode historis, dan jendela dua jam ke belakang:
$ docker events --since 2h --until 0s --filter container=toko-backend-1Output yang Dihasilkan (baris attach dan kawan-kawannya dipotong):
2026-10-13T08:31:33.613547882+07:00 container create 20269502f039d2d914b5845a97033f9a7ab8bbaf7ab58440affe76c390453a9c (image=toko-api:dev, name=toko-backend-1)
2026-10-13T08:31:34.104891245+07:00 container start 20269502f039d2d914b58440affe76c390453a9c (image=toko-api:dev, name=toko-backend-1)
2026-10-13T08:31:40.712401337+07:00 container health_status: healthy 20269502f039d2d914b58440affe76c390453a9c (image=toko-api:dev, name=toko-backend-1)
2026-10-13T09:41:30.402119845+07:00 container health_status: unhealthy 20269502f039d2d914b5845a97033f9a7ab8bbaf7ab58440affe76c390453a9c (image=toko-api:dev, name=toko-backend-1)Mari kita telaah garis waktu tersebut:
- Container backend lahir pukul 08:31:33 — hasil
docker compose up -d --buildyang Siti jalankan setelah menarik perubahan pagi ini; enam detik kemudianhealth_status: healthytercatat — masa grasistart_periodlima detik berlalu, probestart_intervalmengetuk,/healthzmenjawab 200. - Status jatuh pukul 09:41:30 — tujuh puluh menit berstatus sehat, lalu
health_status: unhealthy; tiga kegagalan beruntun padaintervalsepuluh detik berujung pada momen ini. - Tidak ada satu pun kejadian
die,kill, ataurestartuntuk backend — kronik daemon membuktikan secara eksplisit bahwa proses di dalamnya tidak pernah mati; yang berubah hanyalah putusan probe.health_statusmemang kejadian satu-satunya yang bisa lahir saat container “hidup tapi sakit”.
Laporan Lengkap di State Health #
Kata dalam tanda kurung adalah ringkasan; berita lengkapnya hidup di field .State.Health — pola pipa yang kita kenal dari Chapter Docker Inspect:
$ docker inspect --format '{{json .State.Health}}' toko-backend-1 | python3 -m json.toolOutput yang Dihasilkan:
{
"Status": "unhealthy",
"FailingStreak": 4,
"Log": [
{
"Start": "2026-10-13T02:41:00.104512312Z",
"End": "2026-10-13T02:41:00.118044293Z",
"ExitCode": 0,
"Output": ""
},
{
"Start": "2026-10-13T02:41:10.209871453Z",
"End": "2026-10-13T02:41:10.224193852Z",
"ExitCode": 1,
"Output": "wget: server returned error: HTTP/1.1 500 Internal Server Error"
},
{
"Start": "2026-10-13T02:41:20.310294716Z",
"End": "2026-10-13T02:41:20.318044293Z",
"ExitCode": 1,
"Output": "wget: server returned error: HTTP/1.1 500 Internal Server Error"
},
{
"Start": "2026-10-13T02:41:30.402119845Z",
"End": "2026-10-13T02:41:30.415712221Z",
"ExitCode": 1,
"Output": "wget: server returned error: HTTP/1.1 500 Internal Server Error"
},
{
"Start": "2026-10-13T02:41:40.513547882Z",
"End": "2026-10-13T02:41:40.524193852Z",
"ExitCode": 1,
"Output": "wget: server returned error: HTTP/1.1 500 Internal Server Error"
}
]
}Mari kita telaah isi laporan tersebut:
Status: unhealthy— putusan akhir yang diringkasdocker compose psmenjadi kata dalam tanda kurung.FailingStreak: 4— empat kegagalan beruntun saat laporan dibaca; status sudah jatuh sejak kegagalan ketiga, dan probe tetap berjalan tiap sepuluh detik tanpa peduli statusnya.Logmenyimpan lima pemeriksaan terakhir — riwayat probe bergeser seperti jendela: entri paling tua terdorong keluar saat entri baru lahir.- Entri pertama adalah saksi terakhir yang sehat —
ExitCode: 0denganOutputkosong pada pukul02:41:00Z: probewget --spider -qmemang hening ketika sukses. - Empat entri berikutnya menceritakan penyakitnya —
ExitCode: 1danwget: server returned error: HTTP/1.1 500 Internal Server Error:/healthztetap menjawab, tetapi dengan status 500 — handler di dalamnya menangkap galat daripool.query("SELECT 1")dan membalasdb tidak siap. - Stempel waktunya berzona Z, bukan +07:00 —
02:41:30Zdan09:41:30WIB adalah momen yang sama ditulis dua cara, tujuh jam berselisih notasi; inilah pasangan yang harus selalu dikonversi saat kita menyandingkanHealth.Logdengandocker events.
Penyebab 500 itu kini tinggal dirangkai dari dua barang bukti yang sudah kita pegang. Baris db pada docker compose ps memperlihatkan container yang baru berumur 36 detik; kronik lengkapnya terbaca lewat penyaring yang sama:
$ docker events --since 10m --until 0s --filter container=toko-db-1Output yang Dihasilkan (dipotong):
2026-10-13T09:41:05.104512312+07:00 container stop 4ccc495ebdf6562ba1a5b95f4e15fcf3cd4812941a30e3f588778b2134973f98 (image=postgres:18-alpine, name=toko-db-1)
2026-10-13T09:41:05.209871453+07:00 container die 4ccc495ebdf6562ba1a5b95f4e15fcf3cd4812941a30e3f588778b2134973f98 (image=postgres:18-alpine, name=toko-db-1, exitCode=0)
2026-10-13T09:41:05.401229801+07:00 container destroy 4ccc495ebdf6562ba1a5b95f4e15fcf3cd4812941a30e3f588778b2134973f98 (image=postgres:18-alpine, name=toko-db-1)
2026-10-13T09:41:07.812401337+07:00 container create deb60c8a4e4cdeb12dce33330749999d01be15eee53a4dd1e7246fbfef31ea94 (image=postgres:18-alpine, name=toko-db-1)
2026-10-13T09:41:08.104891245+07:00 container start deb60c8a4e4cdeb12dce33330749999d01be15eee53a4dd1e7246fbfef31ea94 (image=postgres:18-alpine, name=toko-db-1)
...
2026-10-13T09:41:19.613547882+07:00 container health_status: healthy deb60c8a4e4cdeb12dce33330749999d01be15eee53a4dd1e7246fbfef31ea94 (image=postgres:18-alpine, name=toko-db-1)Kronik itu melengkapi cerita: perubahan kecil pada service db memicu Compose menghentikan, menghancurkan, lalu menciptakan ulang container db — ID lama 4ccc495e... lenyap, ID baru deb60c8a... lahir, dan probe pg_isready di sisi db langsung lulus kembali sehingga db tampak (healthy). Yang tidak ikut diperbarui adalah pool koneksi di dalam backend: koneksi-koneksi yang dibuka pagi tadi masih menggenggam alamat container db lama yang sudah tiada, dan tanpa logika coba-ulang, setiap SELECT 1 dari /healthz dijawab kegagalan. Kejadian ini persis skenario yang pernah kami peringatkan pada Chapter Startup dan Dependency: gerbang depends_on hanya menjaga urutan start — sesudahnya, container yang dibuat ulang tidak diumumkan kepada tetangganya.
Docker Tidak Menyembuhkan yang Sakit #
Di titik inilah hampir semua operator baru bersalah paham. Dari seluruh peralatan yang kita kenal — restart policy, depends_on, healthcheck — wajar bila kita mengira daemon akan menyentuh backend yang sakit. Diagram berikut memetakan apa yang sebenarnya terjadi pada dua kelas kejadian yang berbeda:
Diagram di atas memperlihatkan dua jalur yang tidak pernah bertemu: jalur kiri adalah kejadian kesehatan — probe gagal, status turun, dan daemon berhenti di situ; jalur kanan adalah kejadian hidup-matikan — proses keluar, exit code tercatat, dan restart policy yang menimbangnya.
Reaksi atas container unhealthy, jadi, harus datang dari kita. Tiga pilihan tersusun dari yang paling manual sampai yang paling otomatis:
- Tangan manusia —
docker compose restart backendmemutus simpulnya seketika: proses dinyalakan ulang, pool koneksi lahir dari nol, dan/healthzkembali menjawab 200. Jalur ini pas untuk stack development seperti toko. - Watchdog kecil — skrip sederhana yang memungut pekerjaan ini secara berkala:
while true; do
for nama in $(docker ps --filter health=unhealthy --format '{{.Names}}'); do
echo "watchdog: memulai ulang $nama"
docker restart "$nama"
done
sleep 30
doneSkrip tersebut memakai filter health=unhealthy milik docker ps — penyaring yang lahir dari status yang kita bahas hari ini — lalu memulai ulang setiap korban tiap tiga puluh detik. Komunitas mengemas pola yang sama dalam image siap pakai bernama autoheal; prinsipnya identik, tinggal dipasang sebagai container. Kedua bentuknya sama-sama kasar: restart adalah simptomatik, bukan penyembuhan — bila akar masalahnya koneksi yang tidak pernah pulih, watchdog akan memutar-ulang container selamanya.
- Orchestrator — Swarm dan Kubernetes memperlakukan kegagalan probe sebagai urusan penjadwalan: container yang berkali-kali gagal diganti replikanya di mesin lain secara otomatis. Membawa kesehatan ke dalam keputusan penjadwalan adalah lompatan level yang kita jajaki pada Section Orchestration dan Ekosistem.
Untuk toko hari ini, tangan manusia memang cukup. Budi menjalankan jalur pertama:
$ docker compose restart backendOutput yang Dihasilkan:
[+] Restarting 1/1
✔ Container toko-backend-1 Started 1.8sMenit berikutnya kolom STATUS-nya menempuh siklus yang sama seperti pagi tadi — health: starting selama masa grasi, lalu (healthy) begitu probe pertama lulus; pool koneksi yang baru terbuka ke container db yang baru, dan docker events mencatat satu baris health_status: healthy sebagai penutup insiden. Pola lengkapnya — memadukan healthcheck, restart policy, dan probe yang dirancang untuk produksi — adalah materi Chapter Healthcheck dan Restart Policy di Section Deployment dan Production.
Kamus Status dan Artinya #
Seluruh kosakata kolom STATUS untuk container ber-healthcheck kini terkumpul dalam satu tabel:
| Status di kolom STATUS | Artinya | Siapa yang menuliskannya |
|---|---|---|
health: starting | masa grasi start_period berjalan; kegagalan probe tidak dihitung | daemon, sejak container menyala |
healthy | probe terakhir lulus; FailingStreak direset nol | daemon, setelah probe keluar exit 0 |
unhealthy | kegagalan beruntun mencapai retries; probe tetap berjalan | daemon, setelah retries kegagalan |
| tanpa tanda kurung | container tanpa healthcheck — hanya napas proses yang dilaporkan | tidak ada probe yang terpasang |
Status kesehatan menjawab satu pertanyaan dengan sangat baik: apakah aplikasi masih sanggup melayani. Tetapi container yang sakit hari ini tetap hidup — nasib yang jauh lebih ramah dibanding kelas kecelakaan yang menanti di chapter berikutnya: container yang mati sama sekali. Exited (137) tanpa pesan perpisahan, Restarting (1) yang berputar tanpa henti, dan rantai ps → inspect → logs → events yang merangkai diagnosisnya — itulah pembahasan Chapter Membaca Container Exit.
Referensi #
- docker container inspect
— field
.State.Healthlengkap denganFailingStreakdanLog. - docker compose ps — tampilan status kesehatan pada daftar service.
- Dockerfile Reference — sintaks HEALTHCHECK beserta nilai bawaan opsinya.
- Compose File Reference — Services
— kunci
healthcheckper service dan interaksinya dengandepends_on.