Sepanjang Section ini kita membangun jaringan container yang bekerja sempurna — dan justru karena itu kita belum pernah benar-benar melihatnya gagal. Di lapangan, masalah jaringan hampir selalu muncul pada momen terburuk: aplikasi berjalan baik di laptop, lalu lumpuh begitu dinaikkan ke mesin rekan; atau dua service yang kemarin saling bicara mendadak tidak saling menemukan. Kabar baiknya, lima masalah itu mengulang pola yang sama di mana-mana, dan masing-masing meninggalkan jejak galat yang khas. Pada chapter penutup ini kita kumpulkan kelimanya menjadi resep diagnosis berurutan — lengkap dengan pesan galat verbatim, perintah pemeriksa yang tepat, dan langkah pemulihan yang bisa dijalankan tanpa menebak-nebak.

Sebelum masuk ke kasus per kasus,pegang satu prinsip dari chapter Komunikasi Antar Container: diagnosis jaringan berjalan dari lapisan paling bawah ke atas. ping membuktikan rute IP, nslookup membuktikan resolusi nama, curl membuktikan layanan dan aplikasi. Ketika salah satu lapisan gagal, berhenti di situ dan perbaiki lapisan itu — tidak ada gunanya mengecek HTTP kalau namanya saja tidak terselesaikan.

Kasus 1 — “Connection refused” #

Galat ini muncul ketika nama berhasil diselesaikan dan paket TCP sampai ke tujuan, tetapi tidak ada proses yang mendengarkan di port itu. Dari dalam container app, panggilan ke db ditolak dengan pesan yang jujur:

text
nc: connect to db port 5432: Connection refused

Mari kita telaah langkah diagnosisnya:

  1. Periksa proses yang mendengarkan dari dalam container tujuan. docker exec db ss -tlnp menampilkan socket yang mendengarkan. Bila barisnya berbunyi 127.0.0.1:5432, tersangka utamanya ditemukan: aplikasi database hanya mendengarkan loopback.
  2. Kenali jebakan bind 127.0.0.1. Di dalam container, 127.0.0.1 berarti container itu sendiri — bukan host, bukan container lain (pembahasan lengkap di chapter Komunikasi Antar Container). Konfigurasi harus mengikat 0.0.0.0 agar socket terbuka bagi penghuni jaringan.
  3. Perbaiki konfigurasi aplikasi. Untuk PostgreSQL, hal ini diatur lewat listen_addresses — image resmi sudah mengaturnya dengan benar, jadi galat ini paling sering menimpa aplikasi buatan sendiri yang membaca contoh tutorial dengan bind ke loopback.
  4. Uji ulang dari container pemanggil. Setelah container tujuan dibuat ulang, nc -zv db 5432 harus melaporkan succeeded!.

Kasus 2 — “name does not resolve” #

Panggilan ke nama service berbalik pesan yang sama sekali tidak menyebut jaringan:

text
nc: getaddrinfo: Name does not resolve

Nama yang tidak terselesaikan berarti kedua container kemungkinan besar tidak berada di jaringan yang sama — DNS internal 127.0.0.11 hanya mengenal tetangga satu jaringan (chapter Container DNS). Langkah diagnosisnya:

  1. Baca dokumen kedua jaringan. docker network inspect net-latihan dan docker network inspect net-kedua — periksa blok Containers seperti yang kita latih di chapter Network Inspect. Bila app tercatat di satu jaringan dan db di jaringan lain, akar masalahnya sudah ditemukan.
  2. Hubungkan tanpa membuat ulang container. docker network connect net-latihan db memasukkan container hidup-hidup ke jaringan yang benar; docker network disconnect net-kedua db merapikan sisa sambungannya.
  3. Pindahkan deklarasi ke tempatnya. Bila kedua service dikelola Compose, penyebab umumnya adalah kunci networks yang berbeda pada kedua service — samakan deklarasi jaringannya di compose.yaml seperti pola frontend/backend pada chapter Port dan Network.
  4. Uji resolusi ulang. docker exec app getent hosts db kini mengembalikan alamat IP.

Kasus 3 — “Pool overlaps with other network on address space” #

Pembuatan jaringan dengan subnet manual tiba-tiba ditolak daemon:

text
Error response from daemon: Pool overlaps with other network on address space

Subnet yang kita minta sudah dipakai jaringan lain — baik jaringan Docker maupun rentang yang dipegang VPN kantor. Langkah berikut menyelesaikannya:

  1. Petakan subnet yang sudah terpakai. docker network ls diikuti docker network inspect per jaringan, lalu baca IPAM.Config[0].Subnet — atau pakai loop audit IP dari chapter Network Inspect agar satu perintah mengumpulkan semuanya.
  2. Pilih rentang yang bebas. Rentang privat 172.16.0.0/12 luas; memilih 10.88.0.0/24 yang jauh dari pool otomatis Docker (yang mengisi 172.17, 172.18, dan seterusnya) hampir selalu aman.
  3. Buat ulang jaringan dengan subnet eksplisit. docker network create --subnet 10.88.0.0/24 net-baru — pola yang sama dengan net-kantor di chapter Membuat Custom Network.
  4. Catat pilihan itu sebagai keputusan tim. Bentrok subnet adalah masalah berulang di laptop yang menjalankan VPN kantor bersamaan dengan banyak project Compose — satu baris komentar di compose.yaml menjelaskan mengapa rentang itu dipilih.

Kasus 4 — DNS internet gagal di dalam container #

Container bisa saling memanggil dengan nama, tetapi resolusi ke internet mati:

text
nc: getaddrinfo: Could not resolve host: example.com

Pembedaan penting: DNS internal (antar-container) bekerja, sedangkan penerusan ke DNS upstream gagal. Diagnosisnya:

  1. Pastikan container memakai DNS daemon. docker exec app cat /etc/resolv.conf harus menunjukkan nameserver 127.0.0.11 — tanda resolver daemon yang meneruskan pertanyaan tak dikenal ke upstream (chapter Container DNS).
  2. Uji nama eksternal langsung. docker exec app nslookup example.com — bila galat berlanjut sedangkan ping 8.8.8.8 berhasil, masalahnya murni pada resolver upstream host.
  3. Atur fallback DNS pada daemon. Tambahkan "dns": ["8.8.8.8", "1.1.1.1"] ke daemon.json lalu restart daemon — pola konfigurasi yang kita kenal dari chapter Konfigurasi Docker Engine. Perubahan ini berlaku bagi container baru.
  4. Periksa VPN korporat. Bila host menjalankan VPN yang merengkuh seluruh trafik DNS, container kerap mengikuti nasib yang sama — pindai aturan split-DNS VPN sebelum menyalahkan Docker.

Kasus 5 — “port is already allocated” #

Perintah docker run -p 8080:80 atau docker compose up berakhir dengan penolakan daemon:

text
Error response from daemon: driver failed programming external connectivity on endpoint web:
Bind for 0.0.0.0:8080 failed: port is already allocated

Sebuah proses di host — atau container lain yang lebih dulu minta port yang sama — sudah menduduki port 8080. Langkah pemulihannya:

  1. Identikan pemegang port. ss -tlnp | grep 8080 menampilkan proses host yang mendengarkan; bila tidak ada, cek docker ps — container lain bisa saja memetakan port yang sama (kejadian persis ini kita saksikan pada percobaan --scale web=3 di chapter Service).
  2. Pilih salah satu jalan: usir atau geser. Hentikan proses lama bila memang sudah tidak dipakai, atau geser pemetaan container ke port host lain — -p 8081:80.
  3. Kunci port di konfigurasi, bukan di ingatan. Bila project dijalankan berdampingan, naikkan pemetaan lewat variabel ${WEB_PORT:-8080}:80 sehingga tiap mesin bisa memilih portnya sendiri — pola .env per orang yang dibahas di chapter Mengelola Environment Development.
  4. Verifikasi dengan docker port. docker port web menegaskan pemetaan yang benar-benar aktif setelah container berjalan (chapter Port Mapping).

Tabel rekap lima resep #

GejalaPenyebab paling umumDiagnosisSolusi
Connection refusedaplikasi bind ke 127.0.0.1docker exec <c> ss -tlnpubah bind ke 0.0.0.0
Name does not resolvebeda jaringandocker network inspect (keduanya)docker network connect
Pool overlapssubnet dipakai jaringan/VPN lainbaca IPAM.Config semua network--subnet 10.88.0.0/24
DNS internet gagalresolver upstream bermasalahcat /etc/resolv.conf + nslookup"dns" di daemon.json
Port already allocatedproses/container lain memegang portss -tlnp + docker psganti port / hentikan pemegang

Dengan kelima resep ini, perjalanan kita melalui jaringan container tuntas: dari network namespace dan bridge pertama, custom network dengan DNS, komunikasi antar container, verifikasi port, alias, sampai inspeksi dokumen jaringan dan pemulihan kegagalan. Namun ada satu beban yang belum kita angkat — setiap latihan Section ini tetap menuntut kita mengetik deretan docker run panjang dengan flag yang harus diingat urutannya. Menjelang akhir chapter sebelumnya kita bahkan sempat menitipkan tiga perintah pembuka jaringan hanya untuk menyiapkan satu kasus latihan. Beban itulah yang diangkat Docker Compose: satu berkas deklaratif yang menyimpan seluruh jaringan, container, dan konfigurasinya — pintu masuk Section berikutnya.

Referensi #