kubectl debug: Atasi Pod CrashLoopBackOff & Distroless

Foto oleh Bernd Dittrich on Unsplash
Image distroless hanya membawa biner aplikasi Anda, tanpa shell, package manager, atau coreutils. kubectl exec bekerja dengan menjalankan program yang sudah ada di dalam container, jadi tanpa sh atau bash perintah itu gagal dengan error executable-not-found. Gunakan kubectl debug dengan ephemeral container yang membawa image berisi alatnya sendiri.
Container yang crash-loop hanya hidup beberapa detik, jadi tidak ada proses stabil untuk di-attach dengan kubectl exec. Gunakan kubectl debug dengan --copy-to untuk mengkloning pod dan menimpa command container yang crash dengan shell, contohnya kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh. Salinan itu boot dan idle sehingga bisa diselidiki; pod aslinya tidak tersentuh.
--target berbagi process namespace milik container target dengan ephemeral container debug Anda. Dari image berisi alat seperti busybox atau netshoot Anda bisa melihat PID aplikasi, membaca /proc-nya, dan memeriksa environment-nya meski image aplikasi tidak punya alat debug. Berbagi process namespace harus didukung container runtime, dan tidak semua platform mengizinkannya.
Tidak. Menurut dokumentasi Kubernetes, Anda tidak boleh mengubah atau menghapus ephemeral container setelah menambahkannya ke pod. Jika salah, Anda harus memasang satu lagi dan hidup dengan kekacauannya sampai pod dibuat ulang. Ephemeral container juga tidak boleh punya ports, livenessProbe, readinessProbe, atau resources, dan tidak pernah di-restart otomatis.
Ephemeral container menempel pada pod yang berjalan, jadi cocok saat pod hidup tapi berperilaku aneh. Ketika pod crash-loop tidak ada container stabil untuk di-attach, jadi gunakan --copy-to untuk membangun salinan yang dimodifikasi, dengan command baru, sidecar debug tambahan (--share-processes), atau image lebih lengkap (--set-image). Pod asli yang crash dibiarkan apa adanya untuk pemeriksaan lanjutan.

Foto oleh Bernd Dittrich on Unsplash
Ringkasan Utama
Pod distroless dan CrashLoopBackOff memblokir kubectl exec karena tidak punya shell atau sudah mati. kubectl debug memasang ephemeral container dengan image toolbox sendiri, dan --target berbagi process namespace milik aplikasi. Untuk pod yang crash, --copy-to mengkloning pod dengan command atau image debug baru, tanpa mengubah pod aslinya.
Pelajaran debugging Kubernetes pertama yang dipelajari semua orang adalah kubectl exec ke sebuah pod lalu menjelajah. Pelajaran kedua, yang dipelajari dengan susah payah di produksi, adalah bahwa dua pod yang paling perlu Anda periksa justru dua pod yang tidak bisa Anda exec: yang macet di CrashLoopBackOff, dan yang distroless dan ter-harden yang dikirim tanpa shell sama sekali.
Saya mengalami keduanya dalam satu shift on-call yang sama. Beginilah kubectl debug dan ephemeral container memberi saya shell yang berfungsi di samping pod yang menolak bekerja sama, plus jebakan yang tidak disebut siapa pun sampai Anda tersandung.
CrashLoopBackOff bukanlah error tersendiri. Itu adalah Kubernetes yang memberi tahu Anda bahwa sebuah container terus memulai, keluar, lalu di-restart, dengan jeda back-off yang makin lama di antara percobaan. Proses yang ingin Anda periksa hanya hidup satu-dua detik sebelum mati, jadi saat Anda mengetik kubectl exec, tidak ada container yang berjalan untuk di-attach dan perintah itu gagal.
Log dan kubectl describe pod adalah tempat pemberhentian pertama yang tepat untuk alasan exit. Tetapi ketika crash bergantung pada filesystem yang hidup, config yang di-mount, atau lookup DNS yang hanya gagal di dalam cluster, membaca log saja tidak cukup. Anda perlu berada di dalam container yang bertahan cukup lama untuk menjalankan perintah secara manual, dan itulah yang justru ditolak oleh crash loop.
Image distroless membuang semua yang bukan aplikasi Anda: tanpa shell, tanpa package manager, tanpa coreutils. Itu keuntungan keamanan yang nyata, karena memperkecil attack surface dan menghapus alat yang justru akan dicari penyerang. Dokumentasi Kubernetes tegas soal harganya: karena image distroless tidak menyertakan shell atau utilitas debugging apa pun, sulit mem-troubleshoot-nya hanya dengan kubectl exec. Tidak ada sh yang bisa dijalankan oleh exec.
# A distroless pod has no shell, so exec just fails:
$ kubectl exec -it api-7d9f -- sh
OCI runtime exec failed: exec failed: unable to start container process:
exec: "sh": executable file not found in $PATH: unknown
# Attach an ephemeral debug container instead — a full toolbox
# is added next to the running app, sharing its Pod:
$ kubectl debug -it api-7d9f --image=busybox:1.28 --target=api
# --target=api shares the target container's process namespace,
# so from busybox you can see the app's PIDs, /proc, and env.
# Swap busybox for netshoot when the problem is the network:
$ kubectl debug -it api-7d9f --image=nicolaka/netshoot --target=apiFlag --target adalah inti dari semuanya. Ia berbagi process namespace milik container target dengan container debug Anda, sehingga dari busybox atau netshoot Anda bisa melihat PID aplikasi, membaca /proc-nya, dan memeriksa environment-nya meski image aplikasi itu sendiri tidak punya alat. Perhatikan bahwa berbagi process namespace harus didukung oleh container runtime, dan tidak semua platform mengizinkannya.
Ephemeral container adalah container sementara yang ditambahkan kubectl debug ke pod yang berjalan melalui subresource khusus ephemeralcontainers di API, bukan dengan menyunting spec pod. Karena ia menumpang di dalam pod yang ada, ia berbagi jaringan pod dan, dengan --target, process namespace milik target. Anda membawa image sendiri yang penuh alat, jadi image aplikasi tetap minimal sementara Anda tetap mendapat shell penuh.
Dokumentasi resmi menyatakannya dengan jelas: ephemeral container berguna untuk troubleshooting interaktif ketika kubectl exec tidak memadai karena sebuah container telah crash atau image container tidak menyertakan utilitas debugging. Satu kalimat itu mencakup kedua masalah on-call saya sekaligus, itulah kenapa ini alat pertama yang saya raih sekarang.
Ephemeral container sempurna untuk pod yang berjalan tetapi berperilaku aneh. Ia tidak membantu ketika pod sedang crash-loop, karena tidak ada container stabil untuk di-attach. Untuk kasus itu kubectl debug bisa mengkloning pod dengan --copy-to: ia membangun salinan di mana Anda menimpa command container yang crash dengan sebuah shell, sehingga salinan itu boot dan idle alih-alih mati. Anda juga bisa menambah sidecar debug dengan --share-processes, atau menukar image ramping dengan yang gemuk lewat --set-image. Pod asli dibiarkan persis apa adanya.
# 1) Copy the pod and drop a debug container next to the app,
# sharing the process namespace — app keeps its own command:
$ kubectl debug myapp -it --image=ubuntu --share-processes --copy-to=myapp-debug
# 2) The container crashes on boot, so nothing to exec into.
# Copy it but override the ENTRYPOINT with a shell so it stays up:
$ kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh
# 3) Swap a slim production image for a fat one with debug tools.
# '*' rewrites every container in the copy:
$ kubectl debug myapp --copy-to=myapp-debug --set-image=*=ubuntu
# The original crashing pod is untouched; you poke at the copy.Dua jebakan ephemeral container yang menggigit di produksi: Anda tidak boleh mengubah atau menghapus ephemeral container setelah menambahkannya ke pod, jadi satu typo berarti Anda memasang satu lagi dan hidup dengan kekacauan itu sampai pod dibuat ulang. Dan ephemeral container tidak boleh punya port, jadi ports, livenessProbe, readinessProbe, dan resources semuanya dilarang. Mereka juga tidak punya jaminan resource dan tidak pernah di-restart otomatis.
Keduanya memberi Anda baris perintah di dalam cluster, tetapi memecahkan masalah yang berbeda. exec menjalankan program yang sudah ada di dalam container yang berjalan; debug menyuntikkan container baru dengan alat yang Anda butuhkan. Beginilah cara saya memilih di antara keduanya.
| Aspek | kubectl exec | kubectl debug (ephemeral) |
|---|---|---|
| Butuh shell di dalam image | Ya — gagal di distroless | Tidak — Anda membawa image sendiri |
| Jalan di pod yang crash-loop | Tidak — tak ada container untuk di-attach | Pakai --copy-to untuk salinan stabil |
| Menambah container baru | Tidak — jalan di dalam yang sudah ada | Ya — container debug sementara |
| Bisa dihapus setelah dipakai | Tak ada yang dihapus — cukup keluar | Tidak — bertahan sampai pod dibuat ulang |
Patokan saya: pakai kubectl exec untuk pod sehat yang kebetulan punya shell, beralih ke kubectl debug dengan ephemeral container begitu image-nya distroless atau alatnya hilang, dan mundur ke --copy-to ketika pod bahkan tak bisa tetap hidup. Sediakan image jaringan seperti nicolaka/netshoot, dan Anda bisa mengejar masalah konektivitas tanpa pernah menanam alat debug ke image produksi.