Playbook Kegagalan Umum

Diagnosis container yang langsung exited, konflik port, error izin, dan image yang tidak bisa ditarik.

Daftar isi

Topik ini menghimpun playbook, yaitu panduan diagnosis siap pakai, untuk kegagalan container yang paling sering ditemui. Setiap kegagalan disusun dengan format gejala, penyebab, lalu langkah diagnosis yang berurutan. Cakupannya meliputi container yang langsung berhenti, konflik port pada host, error izin pada bind mount, dan image yang tidak bisa ditarik.

Container langsung exited#

Gejalanya terbaca pada docker ps -a berupa status exited, yaitu keadaan container yang proses utamanya sudah berakhir. Status itu muncul beberapa detik setelah container dibuat. Container semacam ini tidak selalu rusak, karena banyak program memang dirancang berjalan sekali lalu berakhir. Diagnosisnya dimulai dari dua tempat, yaitu log dan kode keluar (exit code), nilai yang ditinggalkan proses utama ketika berakhir.

Urutan langkah diagnosisnya sebagai berikut.

  1. Baca bagian akhir log dengan docker logs --tail 20 nama-container untuk melihat pesan terakhir aplikasi.
  2. Baca kode keluarnya dengan docker inspect --format '{{.State.ExitCode}}' nama-container.
  3. Cocokkan kode tersebut dengan tabel di bawah, lalu telusuri penyebabnya sesuai maknanya.
bash
# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# baca bagian akhir log container yang langsung berhenti
docker logs --tail 20 catatan-app
# baca kode keluar proses utamanya
docker inspect --format '{{.State.ExitCode}}' catatan-app
KodeMakna
0Proses berakhir dengan sukses, tanpa error
125Kesalahan pada daemon, proses latar Docker, misalnya opsi docker run yang tidak dikenal
126Perintah tidak dapat dieksekusi, misalnya berkasnya bukan program yang bisa dijalankan
127Perintah tidak ditemukan di dalam container
137Proses dihentikan paksa dengan sinyal SIGKILL, yaitu sinyal penghentian yang tidak dapat ditolak proses, paling sering karena kehabisan memori

Tiga kode pertama berasal dari dokumentasi docker run, sedangkan 137 merupakan 128 ditambah nomor sinyalnya, yaitu 9 untuk SIGKILL. Kode yang lebih besar dari 128 umumnya berarti proses dihentikan sinyal, dengan nomor sinyal sebagai selisihnya. Kode 0 tidak selalu berarti aplikasi benar, karena program yang keliru konfigurasi pun dapat berakhir rapi tanpa mengerjakan apa pun.

Konflik port pada host#

Gejalanya muncul pada saat container dibuat. Perintah docker run -p 8000:8000 gagal, dan daemon menampilkan pesan error yang menyatakan alamat tersebut sudah dipakai. Penyebabnya berada di sisi host, mesin tempat Docker berjalan, yaitu proses lain yang sedang mendengarkan pada port yang sama, bukan pada container yang baru akan dibuat.

Langkah diagnosisnya sebagai berikut.

  1. Periksa proses yang mendengarkan pada port tersebut dengan ss -ltn '( sport = :8000 )'.
  2. Putuskan tindakan terhadap proses itu, yaitu menghentikannya bila memang tidak dibutuhkan, atau membiarkannya dan memindahkan container ke port host lain.
  3. Jalankan ulang container dengan pemetaan baru, misalnya -p 8080:8000, sehingga port 8080 di host meneruskan ke port 8000 di dalam container.

Perintah ss berikut diperagakan pada host dengan sebuah proses simulasi yang mendengarkan port 8000.

bash
# jalankan proses semalam yang mendengarkan port 8000 untuk simulasi
python3 -m http.server 8000 --bind 127.0.0.1 >/dev/null 2>&1 &
sleep 0.5
# periksa proses yang mendengarkan pada port 8000
ss -ltn "( sport = :8000 )"
# hentikan proses simulasi
kill $!
text Keluaran
State  Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0      5          127.0.0.1:8000      0.0.0.0:*

Baris LISTEN menyatakan satu proses sedang mendengarkan pada 127.0.0.1:8000, sehingga port itu tidak bebas. Keluaran yang hanya berisi baris judul berarti port bebas dan penyebab konfliknya ada di tempat lain. Pada host sungguhan, opsi -p milik ss menambahkan kolom proses yang menampilkan nama dan PID pemakai port, sehingga proses tersebut dapat dihentikan dengan tepat.

bash
# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# tampilkan pemetaan port yang benar-benar dipasang
docker port catatan-app

Setelah container berjalan, docker port menampilkan pemetaan yang terpasang, sehingga kesalahan urutan port pun terlihat. Urutannya selalu port host terlebih dahulu, kemudian port container, sehingga -p 8080:8000 meneruskan port 8080 di host menuju port 8000 di dalam container.

Error izin pada bind mount#

Gejalanya muncul saat aplikasi di dalam container mengakses berkas pada direktori host yang dipetakan. Pesan errornya menyatakan izin ditolak, sedangkan berkas yang sama terbaca biasa di host. Penyebabnya bukan pada izin baca-tulis biasa, melainkan pada kepemilikan. Bind mount hanya meneruskan direktori host apa adanya, sedangkan pengguna di dalam container berjalan dengan UID yang berbeda dari pemilik berkas di host. UID adalah angka identitas pengguna.

Langkah diagnosisnya sebagai berikut.

  1. Catat UID proses di dalam container dengan docker exec nama-container id -u.
  2. Periksa pemilik berkas di host dengan menampilkan UID numerik, sebagaimana perintah berikut.
  3. Samakan keduanya dengan mengubah kepemilikan berkas di host menggunakan chown, atau jalankan container dengan UID yang cocok melalui opsi --user.

Perintah berikut menyiapkan direktori yang nantinya dipetakan ke container, lalu menampilkan kepemilikan berkasnya secara numerik.

bash
# siapkan direktori yang nantinya dipetakan ke container sebagai bind mount
mkdir -p data-catatan
printf "isi catatan pertama\n" > data-catatan/catatan-1.txt
# tampilkan kepemilikan berkas dengan UID dan GID numerik
stat -c "UID=%u GID=%g berkas=%n" data-catatan/catatan-1.txt
text Keluaran
UID=1001 GID=1001 berkas=data-catatan/catatan-1.txt

Keluaran di atas menunjukkan berkas dimiliki UID 1001 dan GID 1001 pada lingkungan yang menjalankannya. Nilai tersebut mengikuti pengguna di setiap host, umumnya 1000 untuk pengguna pertama pada distribusi Linux. Container yang menjalankan prosesnya sebagai root membawa UID 0, sedangkan container non-root membawa UID yang tertulis pada USER di Dockerfile-nya. Apabila kedua UID tidak cocok, penulisan berkas ditolak oleh kernel, dan itulah error izin yang muncul.

bash
# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# catat UID proses di dalam container
docker exec catatan-app id -u
# jalankan container dengan UID yang cocok dengan pemilik berkas di host
docker run --rm -u 1001 catatan

Image yang tidak bisa ditarik#

Gejalanya muncul sebelum container sempat dibuat. Perintah docker pull atau docker run yang menarik image gagal, dan daemon menampilkan pesan error. Pesan tersebut menyatakan manifest tidak ditemukan bila nama atau tag salah, atau akses ditolak bila repositorinya privat. Manifest adalah daftar lapisan image yang disimpan registry, yaitu gudang penyimpanan image. Daftar itu hanya ada untuk kombinasi nama dan tag yang benar-benar terbit.

Langkah diagnosisnya sebagai berikut.

  1. Periksa ejaan nama image beserta tag-nya, termasuk huruf besar kecil dan tanda pisahnya.
  2. Pastikan kombinasi nama dan tag itu benar-benar terbit di registry tempat image disimpan.
  3. Bila repositorinya privat, jalankan docker login terlebih dahulu, lalu tarik ulang image-nya.
  4. Periksa jaringan host bila keduanya sudah benar, karena registry yang tidak terjangkau menghasilkan kegagalan dengan pesan yang berbeda.
bash
# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# tarik image dengan tag yang belum terbit, misalnya versi yang salah
docker pull catatan:9.9
# masuk ke registry privat sebelum menarik image
docker login
# tarik ulang image setelah login
docker pull catatan:2.0

Perintah login meminta nama pengguna dan kata sandi secara interaktif, lalu menyimpan kredensialnya untuk penarikan berikutnya. Penarikan yang tetap gagal setelah ejaan dan login diperiksa menunjuk masalah jaringan atau registry yang sedang tidak tersedia. Bentuk pesan errornya membedakan keduanya.

Ringkasan#

  • Container yang langsung berhenti didiagnosis dari docker logs dan .State.ExitCode, dengan kode 125 untuk kesalahan daemon, 126 perintah yang tidak dapat dieksekusi, 127 perintah yang tidak ditemukan, dan 137 untuk penghentian paksa.
  • Konflik port didiagnosis dari pendengar port di host, lalu diselesaikan dengan menghentikan prosesnya atau mengganti port host pada opsi -p.
  • Error izin pada bind mount berasal dari perbedaan UID antara proses container dan pemilik berkas di host, dan diselesaikan dengan menyamakan UID.
  • Image yang gagal ditarik disebabkan nama atau tag yang salah, repositori privat yang membutuhkan docker login, atau jaringan yang tidak menjangkau registry.

Referensi#