Kontainer menjawab di LAN kantor, lalu berhenti menjawab pada saat VPN perusahaan tersambung. Tidak ada yang berubah di dalam kontainer: tidak ada mulai ulang, tidak ada pembaruan image, tidak ada pengeditan konfigurasi. Yang berubah adalah tabel perutean host, tempat rute yang ditambahkan terowongan kini mencakup alamat yang diberikan Docker. Sebelum Anda mengedit subnet atau meminta pengecualian VPN, letakkan kedua rencana alamat berdampingan, karena perbaikannya memakan waktu yang sangat berbeda.

Baca rutenya sebelum mengubah konfigurasi

Mulailah dari jaringan yang benar-benar dibangun Docker. Blok IPAM adalah rencana alamat, dan subnet adalah baris yang penting:

docker network inspect project_default --format '{{json .IPAM.Config}}'
# [{"Subnet":"172.18.0.0/16","Gateway":"172.18.0.1"}]

Compose mengalokasikan /16 untuk setiap proyek baru secara default, sehingga dua layanan dapat berada dalam rentang 65,536 alamat. Lebar itulah alasan tumpang tindih umum terjadi: /16 yang dipilih acak cukup besar untuk menelan situs yang Anda jangkau lewat terowongan, dan tidak ada yang menyadarinya sampai terowongan menyala.

Kemudian bandingkan pemilihan rute untuk satu alamat kontainer, sekali dengan terowongan mati dan sekali dengan terowongan hidup:

ip route get 172.18.0.7
# 172.18.0.7 dev br-3f2a9c src 172.18.0.1

Dua bentuk jawaban mengarah ke tempat berbeda. Jika keluarannya menyebut tun0, wg0 atau perangkat terowongan lain, prefiks VPN setidaknya sama spesifiknya dengan rute jembatan dan paketnya tidak pernah mencapai kontainer. Jika masih menyebut jembatan, host dapat mencapai kontainer, dan kesalahan Anda adalah penyaringan, DNS, atau jalur balik yang gagal hanya dalam satu arah.

Mengapa tabrakan /16 mudah terjadi

Docker mengambil jaringan jembatan dari kumpulan privat, dan kumpulan default berasal dari blok 172.16.0.0/12 dalam potongan /16. Jaringan korporat sering memakai ruang privat yang sama, dan VPN akses jarak jauh mendorong prefiks itu ke setiap klien yang tersambung. Ketika kedua pihak yakin memiliki 172.18.0.0/16, satu tabel perutean menyimpan dua klaim yang bertentangan.

Panjang prefiks menentukan pemenang, bukan urutan kemunculan rute. Terowongan yang mendorong 10.0.0.0/8 tidak mengalahkan rute jembatan 172.18.0.0/16, karena /8 kurang spesifik. Terowongan yang mendorong 172.18.0.0/16, atau 172.18.5.0/24 di dalamnya, menang. Itulah sebabnya satu laptop berfungsi di jaringan kantor dan gagal di Wi-Fi hotel dengan VPN yang sama: klien menerima prefiks berbeda.

Tabel yang sama mengatur arah sebaliknya. Kontainer yang membutuhkan host internal di 10.8.4.20 mengirim paket ke gateway jembatannya, dan host lalu merutekannya ke terowongan. Jalur itu biasanya berfungsi karena host melakukan NAT, tetapi gagal ketika pihak korporat hanya menerima alamat VPN laptop, atau ketika penyaringan jalur balik membuang balasan asimetris.

Bandingkan tiga perbaikan

Hanya ada tiga jalan keluar, dan semuanya berbeda dalam siapa yang harus menyetujuinya dan apa yang rusak saat Anda menerapkannya.

RepairWho owns itWhat it costs
Renumber the container networkYouRecreates the network, restarts services, invalidates literal addresses in configs and scripts
Exclude your range from the tunnelNetwork teamChanges what every laptop sees, needs a change request and a client profile update
Reach the service through a published portYou and the clientOne port only, no direct container-to-container routing across the tunnel

Penomoran ulang adalah satu-satunya perbaikan yang bisa Anda selesaikan tanpa tiket, dan itulah sebabnya sebagian besar tulisan berhenti di situ. Perbaikan ini murah pada proyek muda dan mahal begitu alat migrasi atau string koneksi tersimpan menunjuk alamat literal. Hitung rujukan itu sebelum mengedit YAML, bukan sesudahnya.

Pengecualian dari terowongan adalah jawaban terbersih ketika tumpang tindih berada di rentang yang benar-benar dimiliki perusahaan Anda. Ini juga yang paling lambat, dan tidak berguna bagi kontraktor yang tidak dapat mengubah profil klien. Port yang dipublikasikan atau proksi terbalik kecil menghindari perdebatan: klien berbicara dengan alamat yang sudah dirutekan terowongan dengan benar, dan hanya port itu yang harus dapat dijangkau.

Patok rentang dengan sengaja

Untuk satu proyek, deklarasikan subnet di berkas compose agar proyek berhenti mengambil dari kumpulan bersama:

networks:
  default:
    ipam:
      config:
        - subnet: 10.201.7.0/24

Ambil rentang itu dari register yang dipelihara tim Anda, bukan dari contoh yang Anda temukan saat mencari. Periksa terhadap prefiks yang didorong VPN, LAN rumah tempat orang bekerja, dan jaringan kontainer lain di host yang sama. Lalu rencanakan pembuatan ulang, karena jaringan yang sudah ada mempertahankan subnet lamanya: docker compose down, lalu up -d. docker network rm menolak selama endpoint terpasang, dan setiap ipv4_address entri di berkas harus berada di dalam rentang baru.

Untuk jaringan yang dibuat Docker sendiri, tetapkan kumpulan daemon di /etc/docker/daemon.json:

{
  "default-address-pools": [
    { "base": "10.201.0.0/16", "size": 24 },
    { "base": "10.202.0.0/16", "size": 24 }
  ]
}

Kumpulan berlaku untuk jaringan yang dibuat setelah daemon dimulai ulang, dan jembatan yang sudah ada mempertahankan alamatnya. Itu nyaman dan mudah dilupakan, jadi perlakukan proyek lama sebagai masih tumpang tindih sampai seseorang membuat ulang jaringannya. Dokumentasi Docker tentang jaringan mesin menjelaskan aturan alokasi jika Anda perlu mempertahankan kumpulan itu dalam tinjauan.

Jembatan Linux dan Docker Desktop gagal dengan cara berbeda

Pada host Linux, kontainer berada di jembatan dalam ruang nama host. Satu tabel menentukan segalanya, jadi perbandingan di atas adalah keseluruhan cerita: baca rute jembatan, baca rute terowongan, dan lihat mana yang menang untuk alamat kontainer nyata.

Docker Desktop menempatkan kontainer di belakang VM dengan NAT sendiri. Host sama sekali tidak punya rute ke alamat kontainer; ia mencapai layanan melalui port yang dipublikasikan, biasanya terikat ke 127.0.0.1. Karena itu klien VPN dapat merusak layanan tanpa tumpang tindih subnet, entah dengan memasang rute untuk rentang internal VM atau dengan memblokir lalu lintas loopback selama terowongan tersambung. Jika ip route get di host melaporkan tidak ada rute untuk alamat kontainer, itu memang diharapkan dan bukan bugnya.

Konsekuensi praktisnya adalah dari mana Anda melihat lebih dulu. Di Linux, mulailah dari tabel perutean. Di Desktop, mulailah dari port yang dipublikasikan dan aturan firewall klien VPN, lalu periksa apakah subnet internal VM bertabrakan dengan sesuatu yang didorong terowongan.

Verifikasi dengan terowongan hidup

Sambungkan ulang VPN dua kali sebelum menyebutnya beres, karena profil yang mendorong rute saat tersambung dan menariknya kembali saat terputus bisa terlihat benar setelah percobaan pertama. Lalu jalankan pemeriksaan yang benar-benar dijalankan klien:

  1. ip route get dari host, memakai alamat asli kontainer.
  2. Permintaan dari kontainer lain, untuk membuktikan layanannya sendiri sehat.
  3. curl -sv http://127.0.0.1:8080/ dari klien dengan terowongan hidup, lalu traceroute -n ke alamat kontainer dari mesin di LAN.
  4. sysctl net.ipv4.conf.all.rp_filter jika permintaan mencapai host tetapi balasannya menghilang.

Terakhir, tuliskan rentang yang dipilih ke register yang sama yang Anda pakai untuk memilihnya, dengan tanggal dan proyek yang memilikinya. Tumpang tindih berikutnya akan datang dari proyek yang tidak didokumentasikan siapa pun, dan satu-satunya pertahanan adalah rentang itu dicadangkan dengan sengaja, bukan diambil acak.

Artikel terkait