Mode bridge menghubungkan, mode host melepas sekat — keduanya berbicara tentang berapa banyak konektivitas yang diberikan kepada container. Mode ketiga menjawab pertanyaan dari arah yang jarang diajukan: bagaimana bila konektivitasnya nol sama sekali? Terdengar seperti fitur yang tidak berguna, namun justru sebaliknya — banyak pekerjaan komputasi justru paling aman dikerjakan oleh proses yang tidak bisa menjangkau jaringan, dan beberapa profesi bahkan menjadikan ruang tanpa jaringan sebagai ruang kerja wajibnya. Chapter ini membedah mode --network none dari dalam namespace-nya, membaca dua pesan galat yang tampak mirip tetapi bekerja di lapisan berbeda, dan menutup dengan use case yang menjelaskan kapan keheningan jaringan adalah fitur, bukan cacat.

Jaringan Bernama none dengan Driver null #

Kita mulai dari daftar jaringan yang sudah familiar — baris ketiganya adalah objek kita kali ini:

bash
$ docker network ls

Output yang Dihasilkan:

text
NETWORK ID     NAME      DRIVER    SCOPE
9e7d2c4b1a8f   bridge    bridge    local
3f8a6d2c9e4b   host      host      local
7c1e9a3d5f2b   none      null      local

Baris none menyimpan istilah yang sering membingungkan: namanya none, tetapi drivernya null. Dua kata itu bukan pilihan sinonim yang asal — keduanya bekerja pada lapisan berbeda. Nama none adalah nama jaringan yang kita tunjuk dengan --network none; sedangkan null adalah nama driver yang ditugaskan untuk membangun jaringan itu, dan tugas driver null memang tidak melakukan apa-apa: tidak ada bridge yang dibuat, tidak ada veth yang disiapkan, tidak ada kumpulan alamat yang dikelola. Jaringan none adalah janji tentang ketiadaan — dan driver null adalah pihak yang menjaga janji itu tetap kosong.

Namespace Tetap Diciptakan, Isinya Hanya Loopback #

Satu salah paham yang perlu diluruskan lebih dulu: --network none bukan berarti container berjalan tanpa network namespace. Namespace tetap diciptakan — isolasi tetap utuh — tetapi isinya sengaja dibiarkan telanjang tanpa satu interface keluar pun. Kita buktikan dengan foto biasa dari dalam:

bash
$ docker run --rm --network none alpine:3.20 ip addr

Output yang Dihasilkan:

text
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever

Mari kita telaah isi foto tersebut:

  1. Hanya ada satu interface: lo — bandingkan dengan container bridge yang punya eth0@if15 beralamat 172.17.0.2, atau container host mode yang bahkan melihat kartu LAN 192.168.1.15; di sini daftarnya selesai pada baris loopback.
  2. 127.0.0.1/8 tetap hidup — proses di dalam container masih bisa bicara dengan sesama proses di container yang sama lewat localhost; aplikasi berarsitektur multi-proses lokal tetap dapat bekerja.
  3. Isolasi ke host tetap berlaku ke arah sebaliknya — namespace yang tetap diciptakan berarti proses container juga tidak bisa melihat interface host; mode none bukan mode host yang diam, melainkan rumah tanpa satu pintu keluar pun.

Tabel Routing yang Kosong #

Ketiadaan interface keluar meninggalkan bekas yang bisa dibaca pada tabel routing. Perintah ip route mencetak aturan-aturan ke mana paket harus dikirim:

bash
$ docker run --rm --network none alpine:3.20 ip route

Output yang Dihasilkan:

text

Keluarannya benar-benar kosong — bukan satu baris pun tercetak. Pada container bridge, tabel ini memuat minimal dua aturan: jaringan 172.17.0.0/16 dikirim lewat eth0, dan default route via gateway 172.17.0.1. Di sini tidak ada eth0 untuk dituju, sehingga kernel tidak punya satu pun aturan untuk dicetak. Tabel routing kosong inilah yang akan menjelaskan dua pesan galat berikutnya.

Dua Pesan Galat yang Berbeda #

Dua percobaan ping yang tampak serupa akan menghasilkan dua kegagalan yang berbeda. Yang pertama menembak alamat IP langsung:

bash
$ docker run --rm --network none alpine:3.20 ping -c 2 8.8.8.8

Output yang Dihasilkan:

text
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: sendto: Network is unreachable

Yang kedua memanggil nama domain:

bash
$ docker run --rm --network none alpine:3.20 ping -c 2 example.com

Output yang Dihasilkan:

text
ping: bad address 'example.com'

Mari kita telaah mengapa dua kegagalan itu berbeda:

  1. Network is unreachable adalah kegagalan lapisan routing — kernel menerima permintaan kirim paket ke 8.8.8.8, mencari aturan di tabel routing, tidak menemukan satu pun (tabelnya kosong), lalu menolak dengan pesan ini; paket gagal bahkan sebelum sempat dibuat.
  2. bad address adalah kegagalan lapisan resolusi nama — sebelum ping bisa mengirim apa pun ke example.com, nama itu harus diterjemahkan menjadi alamat IP oleh server DNS; permintaan DNS itu sendiri adalah paket jaringan yang harus menempuh routing — dan di sinilah semuanya kandas, karena tidak ada jalur menuju server DNS mana pun.
  3. Urutan kejadiannya berbeda — kegagalan pertama terjadi saat kernel mencari jalur; kegagalan kedua terjadi lebih awal, saat aplikasi masih mencari tahu alamat tujuannya. Dua pesan yang sama-sama berujung pada ketiadaan jaringan ini melatih kita membaca gejala: pesan routing menunjuk jalur, pesan bad address menunjuk DNS.
  4. Jebakan diagnosis yang dihindari — pemula yang melihat bad address sering menuduh konfigurasi DNS sebagai akar masalah, padahal pada container none akarnya memang ketiadaan konektivitas; memperbaiki berkas resolv.conf tidak akan menolong selama tabel routing tetap kosong.

docker exec Tetap Bekerja #

Ketiadaan jaringan sering dicemaskan berlebihan: “kalau tidak ada jaringan, bagaimana cara mengurus containernya?” Kekhawatiran itu berasal dari pencampuradukan dua jalur yang berbeda. docker exec masuk ke container bukan lewat TCP/IP milik container, melainkan lewat jalur internal daemon: CLI berbicara dengan dockerd lewat Unix socket host, dockerd menjalankan proses baru di dalam namespace container lewat mekanisme kernel. Tidak satu paket pun harus menempuh stack jaringan si container. Kita buktikan dengan container yang sengaja dibiarkan hidup:

bash
$ docker run -d --name terisolasi --network none alpine:3.20 sleep 1h

Output yang Dihasilkan:

text
4e8b2d6f0a9c1c3e5a7b9d0f2a4c6e8b1d3f5a7c9e0b2d4f6a8c0e2b4d6f8a1c
bash
$ docker exec terisolasi echo jalur exec tetap hidup

Output yang Dihasilkan:

text
jalur exec tetap hidup

Pesan itu tercetak mulus dari container yang tidak bisa menjangkau apa pun di luar dirinya. Konsekuensi praktisnya lega: docker logs, docker exec, docker stop, dan docker inspect tetap berfungsi penuh — hanya lalu lintas jaringan container yang mati, bukan kemampuan kita mengendalikannya.

Kapan Keheningan adalah Fitur #

Tiga kelompok kerja menjadikan mode none sebagai pilihan sadar. Kelompok pertama adalah batch job komputasi murni: kompilasi kode, konversi media, pengolahan data — pekerjaan yang inputnya sudah tersedia lokal dan tidak membutuhkan satu pun akses jaringan; memutus jaringannya menutup seluruh kelas kebocoran sekaligus, termasuk kebiasaan buruk build yang diam-diam mengunduh dependensi dan merusak reproduksibilitas yang kita bangun pada Chapter Reproducible Build. Kelompok kedua adalah laboratorium riset keamanan: menganalisis sampel perangkat lunak mencurigakan di ruang tanpa jaringan memastikan sampel itu tidak bisa memanggil pulang, mengunduh payload tambahan, atau menyelidiki lingkungannya — praktik standar malware analysis. Kelompok ketiga adalah pengujian ketahanan: menjalankan aplikasi dalam mode none adalah cara paling cepat membuktikan apakah aplikasi kita sungguh bisa menyala tanpa layanan jaringan yang selama ini dianggap “pasti ada”.

Kita rapikan container latihan chapter ini:

bash
$ docker rm -f terisolasi

Output yang Dihasilkan:

text
terisolasi

Spektrum konektivitas kini lengkap dipetakan: host memberi segalanya, none mencabut segalanya, dan default bridge berdiri di tengah dengan satu kekurangan yang sudah kita buktikan — container tetangganya tidak bisa dipanggil dengan nama. Saatnya membangun jawaban yang menyatukan keunggulan semua mode: jaringan buatan sendiri dengan subnet yang kita tentukan, lengkap dengan DNS internal yang menghilang di default bridge. Chapter Membuat Custom Network mengajarkan kita menjadi arsitek jaringan pertama kita sendiri.

Referensi #