Chapter Container Health menutup dengan pengamatan yang tepat: container yang sakit namun tetap hidup adalah nasib yang cukup ramah — probe masih mengetuk, status masih bisa berubah menjadi unhealthy, dan kita masih sempat bertindak sebelum semuanya terlampau. Kelas kecelakaan berikutnya jauh lebih dingin: container yang berhenti total tidak lagi bisa di-probe, tidak lagi menjawab, dan tidak lagi muncul di docker ps. Kabar baiknya, kematian container hampir tidak pernah terjadi diam-diam: daemon mencatat exit code proses utamanya, waktu berhentinya, penanda khusus bila proses dibunuh kelaparan memori, sampai detik ketika event die dituliskan. Stack toko kita baru saja mendapat korban semacam ini: laporan-harian — service job yang dijadwalkan scheduler menyala setiap tengah malam untuk merangkum penjualan sehari dan mengirim ringkasan ke API tim marketing — tidak mengirim apa pun pada dini hari 14 Oktober. Chapter ini melakukan otopsi lengkap atas kematian itu dengan merangkai empat alat yang sudah kita kumpulkan sepanjang section: docker ps -a, docker inspect, docker logs, dan docker events.
Exit Code sebagai Berita Kematian Container #
Setiap proses Unix berakhir dengan satu angka — exit code — dan container mewarisi angka milik proses utamanya (PID 1). Konvensinya sudah kita bedah tuntas di chapter Memahami Exit Code: 0 berarti sukses, kode 1 sampai 125 adalah wilayah aplikasi, dan kode 128 ke atas berarti proses dihentikan sinyal — 137 untuk SIGKILL (128+9), 143 untuk SIGTERM (128+15) — sementara 125, 126, dan 127 milik sisi Docker. Pada chapter tersebut kita memproduksi kegagalan kecil secara sengaja; sekarang kegagalan datang sendiri tanpa undangan, dan tugas kita membacanya seperti otopsi.
Papan docker ps -a adalah pintu masuknya. Format tabel ringkas membuat kita bisa memindai seluruh container yang sudah berhenti beserta kode keluarnya:
$ docker ps -a --filter status=exited --format 'table {{.Names}}\t{{.Status}}'Output yang Dihasilkan:
NAMES STATUS
laporan-harian Exited (1) 9 hours ago
toko-migrate-1 Exited (0) 12 hours ago
uji-nyasar Exited (127) 3 days agoMari kita telaah perintah dan tabel tersebut:
--filter status=exitedmenyaring hanya container berstatusExited— container yang hidup tidak ikut mengganggu pemeriksaan pagi ini.--format 'table ...'memilih kolom yang relevan untuk diagnosis (nama dan status keluar) sehingga daftar panjang tetap mudah dipindai mata.toko-migrate-1denganExited (0)bukanlah kegagalan — job migrasi memang dirancang selesai, dan kode 0 setelah gerbangservice_completed_successfullydi chapter Startup dan Dependency justru berarti tugasnya tuntas.laporan-hariandenganExited (1)adalah korban kita — kode 1 adalah bahasa klasik aplikasi yang menemui galat lalu menyerah; sisanya hanya menunggu dibedah.
Otopsi dengan docker inspect #
Kolom STATUS memberi angkanya; struktur State pada docker inspect memberi konteksnya. Lima field berikut adalah set standar otopsi kita:
$ docker inspect laporan-harian --format 'Status={{.State.Status}} ExitCode={{.State.ExitCode}} OOMKilled={{.State.OOMKilled}} Error={{.State.Error}} FinishedAt={{.State.FinishedAt}}'Output yang Dihasilkan:
Status=exited ExitCode=1 OOMKilled=false Error= FinishedAt=2026-10-13T16:15:03.902183744ZMari kita bedah kelima field tersebut satu per satu:
State.Statusadalah kondisi terakhir container —exited,running, ataurestarting— versi resmi daemon, bukan tebakan kolomps.State.ExitCodeadalah angka warisan PID 1 — inti berita kematian yang sama dengan yang terlihat di kolomSTATUS.State.OOMKilledbernilaitruehanya bila kernel membunuh proses karena cgroup memori container kehabisan ruang — petunjuk emas ketika exit code adalah 137.State.Errormemuat pesan galat dari sisi daemon, bukan dari aplikasi.State.FinishedAtadalah waktu berhentinya dalam UTC — angka yang bisa disandingkan dengan jejak waktu di log aplikasi dan didocker events.
Peta Kecurigaan per Kode Keluar #
Angka saja belum cukup menuntun tindakan. Tabel berikut memetakan tujuh kode yang paling sering muncul ke langkah diagnosis pertama yang paling produktif:
| Exit code | Arti paling mungkin | Langkah diagnosis pertama |
|---|---|---|
0 | Tugas selesai normal — khususnya container batch/job | Bukan masalah; baca docker logs bila ingin hasil kerjanya |
1 | Aplikasi menemui galat lalu keluar | Baca docker logs, cari baris terakhir sebelum mati |
125 | Daemon gagal menjalankan container — flag atau nilainya tidak valid | Periksa penulisan perintah docker run; pesan galatnya tampil di terminal |
126 | Perintah ditemukan tetapi tidak bisa dieksekusi | Periksa bit eksekusi berkas (chmod +x) dan baris shebang |
127 | Perintah tidak ditemukan di dalam image | Periksa ejaan nama biner dan variabel PATH; verifikasi image yang dipakai |
137 | Dihentikan SIGKILL — docker kill, tenggang stop habis, atau OOM | Baca State.OOMKilled; bila ragu, periksa dmesg |
143 | Dihentikan SIGTERM — umumnya docker stop | Wajar saat dihentikan; curiga bila muncul tanpa stop dari siapa pun |
Kode 137 pantas mendapat perhatian ekstra karena memiliki dua tersangka besar. Tersangka pertama adalah OOM killer kernel — dan bila State.OOMKilled bernilai true, kasusnya langsung jelas: arah perbaikannya adalah limit memori atau kebocoran di aplikasi. Tersangka kedua adalah SIGKILL dari tangan manusia — docker kill, atau masa tenggang docker stop yang kehabisan waktu. Bila OOMKilled bernilai false namun kecurigaan OOM belum gugur, catatan kernel di host menjadi hakim terakhir:
$ sudo dmesg | grep -i 'out of memory'Output yang Dihasilkan (dipotong):
[4831.204812] Memory cgroup out of memory: Killed process 1873 (python3) total-vm:418816kB, anon-rss:251392kBBaris tersebut adalah pengakuan tertulis kernel: proses bernama python3 di dalam cgroup suatu container dibunuh karena memakai memori melebihi plafonnya — mekanisme cgroups yang kita bahas di chapter Resource Limit. Tidak ada baris seperti ini di dmesg, tidak ada OOM; tersangka berpindah kembali ke tangan manusia.
Merangkai Empat Alat dalam Satu Otopsi #
Satu perintah jarang cukup untuk menutup kasus. Alur lengkapnya dirangkai dari empat alat: ps -a menunjukkan siapa yang mati, inspect menjelaskan bagaimana ia mati, logs mengisi kata-kata terakhirnya, dan events mengunci kronologinya. Dua langkah pertama sudah kita jalankan: laporan-harian berhenti dengan kode 1, bukan OOM, pada pukul 16:15:03Z UTC. Kini giliran kata-kata terakhirnya:
$ docker logs --tail 6 laporan-harianOutput yang Dihasilkan:
[2026-10-13 23:15:00] laporan harian dimulai
[2026-10-13 23:15:00] membaca konfigurasi lingkungan...
Traceback (most recent call last):
File "/app/laporan.py", line 41, in <module>
token = os.environ['API_TOKEN']
~~~~~~~~~^^^^^^^^^^^^^
KeyError: 'API_TOKEN'Mari kita telaah jejak yang ditinggalkan log tersebut:
- Dua baris pertama sehat — aplikasi menyala dan langsung membaca konfigurasi lingkungan; kegagalan baru terjadi di langkah berikutnya.
KeyError: 'API_TOKEN'adalah vonisnya — skrip Python membacaos.environ['API_TOKEN']dan variabel tersebut tidak ada di environment container;tracebacklengkap dengan nomor barisnya adalah pola yang sudah kita kenal dari chapter Docker Logs.- Exit code 1 turun secara otomatis — Python menutup dirinya dengan kode 1 untuk exception yang tidak tertangani; tidak ada yang salah dengan container atau daemon, yang kurang cuma satu baris environment.
- Waktunya 23:15 waktu lokal — aplikasi mencetak timestamp sendiri dengan zona waktu mesin (WIB), dan angka ini akan menjadi kunci saat disandingkan dengan arsip UTC pada
inspectdi bawah.
Terakhir, kita kunci kronologi dari sisi daemon. Karena inspect sudah memberi tahu waktu kematiannya, jendela waktu events bisa ditulis presisi mengelilingi angka itu:
$ docker events --since '2026-10-13T16:14:55Z' --until '2026-10-13T16:15:10Z' --filter container=laporan-harianOutput yang Dihasilkan:
2026-10-13T23:15:00.104923155+07:00 network connect 6b1e2f3a4b5c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e (container=6b1e2f3a4b5c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e, name=bridge, type=bridge)
2026-10-13T23:15:00.208511907+07:00 container start 6b1e2f3a4b5c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e (image=laporan:1.3, name=laporan-harian)
2026-10-13T23:15:03.902183744+07:00 container die 6b1e2f3a4b5c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e (image=laporan:1.3, name=laporan-harian, exitCode=1)
2026-10-13T23:15:03.981350441+07:00 network disconnect 6b1e2f3a4b5c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e (container=6b1e2f3a4b5c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e, name=bridge, type=bridge)Mari kita bedah bagaimana keempat baris itu saling mengunci dengan bukti-bukti sebelumnya:
container diedanFinishedAtadalah satu peristiwa yang sama — event menunjuk23:15:03.902183744, sedangkaninspectmenyimpan2026-10-13T16:15:03.902183744Z; nanodetik902183744identik di keduanya karena memang dicatat dari sumber yang sama.- Atribut
exitCode=1pada eventdiecocok denganState.ExitCode— tiga alat yang berbeda menyebut satu angka, dan angka itu konsisten. - Tiga jam, dua zona waktu, satu momen —
FinishedAttersimpan dalam UTC (16:15:03Z),docker eventsmerendernya dalam zona waktu mesin kita — WIB, tujuh jam di depan UTC, konvensi yang kita kenal dari chapter Docker Events — dan aplikasi mencetak23:15dari jam lokalnya sendiri.16:15:03ditambah tujuh jam memang menjadi23:15:03; ketiga angka itu tidak bertentangan, semuanya menunjuk detik yang sama. - Umur container hanya 3,7 detik — jarak antara
startdandie— cukup bagi Python untuk menyala, gagal membaca environment, dan tumbang.
Empat kesaksian yang saling mengunci membuat perbaikannya tinggal satu langkah: menambahkan API_TOKEN pada environment service laporan-harian — persis pola fail-fast yang sehat, karena aplikasi menolak bekerja tanpa bekalnya. Sebagai penutup, docker wait — yang memblokir terminal sampai container berhenti lalu mencetak exit code-nya, sebagaimana kita praktikkan di chapter Memahami Exit Code — tetap menjadi alat andalan untuk skrip yang menunggu job secara programatik; namun untuk otopsi manual, rantai ps -a → inspect → logs → events inilah yang memberi konteks paling kaya.
Exit code memberi tahu kapan dan bagaimana sebuah container mati. Namun ada kelas kegagalan yang justru tidak membunuh container sama sekali: aplikasi hidup dan sehat di mata docker ps, tetapi tidak bisa dijangkau siapa pun. Kelas kegagalan semacam itu bersembunyi di lapisan jaringan, dan membongkarnya menuntut resep yang bergerak dari dalam container ke luar — materi chapter Debugging Network.
Referensi #
- Referensi docker container ls
— filter
statusdanexited, serta pemakaian--formatpada daftar container. - Referensi docker container inspect
— struktur
Statebeserta fieldExitCode,Error,OOMKilled, danFinishedAt. - Referensi docker container logs
— flag
--tailuntuk membaca kata-kata terakhir container yang mati. - Referensi docker system events
— format event
die, atributexitCode, dan pemfilteran rentang waktu.