Tiga mode bawaan telah kita petakan: default bridge yang konektivitasnya lengkap tetapi bisu soal nama, mode host yang menanggalkan isolasi, dan mode none yang memutus segalanya. Kelemahan yang paling mengganjal tetap yang pertama — ping web-a yang ditolak dengan bad address pada Chapter Bridge Network — karena aplikasi nyata memang memanggil tetangganya dengan nama, bukan dengan angka IP yang bisa berpindah setiap kali container diciptakan ulang. Jawaban Docker atas kelemahan itu adalah user-defined bridge: jaringan buatan sendiri yang kelihatannya sama seperti default bridge, tetapi membawa DNS internal, kelompok isolasi sendiri, dan kendali penuh atas subnet. Chapter ini membangun jaringan pertama kita dari nol, menyambungkan container yang sedang berjalan tanpa mematikannya, lalu menyetel subnet dan IP statis untuk kebutuhan yang lebih spesifik.
Membuat Jaringan Pertama Kita #
Satu perintah cukup untuk melahirkan jaringan baru — beri nama yang menjelaskan fungsinya, karena nama inilah yang nanti dipakai setiap docker run:
$ docker network create net-aplikasiOutput yang Dihasilkan:
d4c8b2a6e0f15a7c9e1b3d5f7a9c0e2b4d6f8a1c3e5b7d9f0a2c4e6b8d0f2a4cEnam puluh empat karakter heksadesimal yang tercetak adalah ID lengkap jaringan baru kita, sama seperti ID container pada docker run. Kita periksa hasilnya di daftar jaringan:
$ docker network lsOutput yang Dihasilkan:
NETWORK ID NAME DRIVER SCOPE
9e7d2c4b1a8f bridge bridge local
3f8a6d2c9e4b host host local
7c1e9a3d5f2b none null local
d4c8b2a6e0f1 net-aplikasi bridge localMari kita telaah baris baru tersebut:
net-aplikasidengan driverbridge— jaringan buatan kita tetap memakai driver bridge yang sama dengan default; yang berubah adalah statusnya sebagai jaringan yang kita definisikan sendiri, dan status itu membuka fitur yang tidak ada di default.- ID pendek
d4c8b2a6e0f1— dua belas karakter pertama dari ID penuh yang barusan tercetak, sama hubungannya sepertiCONTAINER IDdengan ID container. - Subnet ditunjuk otomatis dari pool berikutnya — daemon tidak bertanya subnet apa yang kita mau; ia mengambil kumpulan alamat berikutnya setelah
172.17.0.0/16milik docker0, yaitu172.18.0.0/16, dan menyediakan172.19.0.0/16untuk jaringan keempat bila kelak kita buat lagi — urutan pool ini menjaga jaringan-jaringan di satu host tidak saling menabrak.
Container Pertama di net-aplikasi #
Jaringan baru kita menunggu penghuni. Kita jalankan pasangan klasik aplikasi dua tingkat — sebuah web server dan satu container utilitas yang mewakili aplikasi backend — keduanya secara eksplisit menempel ke net-aplikasi:
$ docker run -d --name web --network net-aplikasi nginxOutput yang Dihasilkan:
f7c2a91b3e55913c4a5f1c6c0a4d8e2b3f4a5b6c7d8e9f0a1b2c3d4e5f60718a$ docker run -d --name app --network net-aplikasi alpine:3.20 sleep 1hOutput yang Dihasilkan:
3b7e9f2a5c8d4617a9e0c2b4d6f8a1c3e5b7d9f0a2c4e6b8d0f2a4c6e8b1d3f5Metadata lengkap jaringan kita kini berisi dua penghuni — inilah wujud docker network inspect untuk jaringan buatan sendiri:
$ docker network inspect net-aplikasiOutput yang Dihasilkan:
[
{
"Name": "net-aplikasi",
"Id": "d4c8b2a6e0f15a7c9e1b3d5f7a9c0e2b4d6f8a1c3e5b7d9f0a2c4e6b8d0f2a4c",
"Created": "2026-10-13T19:21:48.392714853Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"3b7e9f2a5c8d4617a9e0c2b4d6f8a1c3e5b7d9f0a2c4e6b8d0f2a4c6e8b1d3f5": {
"Name": "app",
"EndpointID": "c9e2a7b4d1f68530a2c4e6b8d0f2a4c6e8b1d3f5a7c9e1b3d5f7a9c2e4b6d8f0",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"f7c2a91b3e55913c4a5f1c6c0a4d8e2b3f4a5b6c7d8e9f0a1b2c3d4e5f60718a": {
"Name": "web",
"EndpointID": "a3f8c1e5b7d29406a8c2e4f0b6d8a1c3e5f7a9b1d3f5e7c9a1b3d5f7e9c2a4b6",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]Mari kita telaah tiga bagian yang paling berharga dari output di atas:
IPAM.Config— subnet172.18.0.0/16dengan gateway172.18.0.1persis seperti ramalan pool berurutan: satu tingkat di atas172.17.0.0/16milik docker0; bendahara alamat jaringan ini membagi172.18.0.2kepadawebdan172.18.0.3kepadaapp.ContainersdenganMacAddress— MAC02:42:ac:12:00:02milikwebmemakai sandi alamat yang kita bedah pada Chapter Bridge Network: prefiks02:42, laluac:12:00:02yang terbaca sebagai172.18.0.2; keajaiban kecil ini tetap bekerja identik di jaringan buatan sendiri.Scope: localdenganOptionskosong — jaringan ini hidup pada satu host saja; kolomOptionsyang kosong menandakan kita menerima seluruh bawaan driver, berbeda dengan default bridge yang membawa baris-baris opsicom.docker.network.bridgekarena jaringan itu dibangun oleh daemon dengan opsi yang diatur sejak awal.
Nama yang Akhirnya Bisa Dipanggil #
Momen yang gagal pada default bridge kini kita ulang di jaringan sendiri. Dari dalam app, kita sapa web — dengan namanya, tanpa satu angka IP:
$ docker exec app ping -c 2 webOutput yang Dihasilkan:
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.149 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.112 ms
--- web ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.112/0.131/0.149 msBaris pertama mengatakan segalanya: PING web (172.18.0.2) — nama web berhasil diterjemahkan menjadi alamat, sesuatu yang mustahil terjadi di default bridge. Penerjemahnya adalah DNS internal Docker yang aktif otomatis pada user-defined network; bedah lengkap mesin ini — cara kerjanya, batasnya, dan perilakunya terhadap nama eksternal — menjadi materi utama Chapter Container DNS.
Menyambungkan Container yang Sedang Berjalan #
Default bridge memaksa kita memilih jaringan sebelum container menyala — salah pasang berarti buang dan jalankan ulang. User-defined network melepas kekangan itu: container yang sedang berjalan bisa kita colokkan ke jaringan tambahan tanpa mati sedetik pun. Kita siapkan satu reporter di jaringan bawaan:
$ docker run -d --name reporter alpine:3.20 sleep 1hOutput yang Dihasilkan:
5a8c2e6b1d4f7a9c0e2b4d6f8a1c3e5b7d9f0a2c4e6b8d0f1a3c5e7b9d0f2a4cReporter kini menghuni default bridge dengan alamat 172.17.0.2. Sekarang kita tambahkan kartu jaringan keduanya — ke net-aplikasi:
$ docker network connect net-aplikasi reporterPerintah ini tidak mencetak apa pun saat berhasil — keheningan output di dunia Docker sering kali justru tanda keberhasilan, dan kita verifikasi hasilnya langsung dari dalam container:
$ docker exec reporter ip addrOutput yang Dihasilkan:
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
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
29: eth1@if30: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.4/16 scope global eth1
valid_lft forever preferred_lft foreverContainer ini kini punya dua kartu jaringan: eth0 ke default bridge (172.17.0.2, perhatikan MAC dengan sandi ac:11) dan eth1 ke net-aplikasi (172.18.0.4, MAC bersandi ac:12). Pencabutannya sama halnya — satu perintah, tanpa restart:
$ docker network disconnect net-aplikasi reporterSekali lagi tanpa output, dan docker exec reporter ip addr setelahnya akan menunjukkan eth1 sudah lenyap dari daftar — container kini tinggal satu kartu di default bridge, seolah tak pernah sempat punya kartu kedua.
Subnet Khusus dan IP Statis #
Pool otomatis 172.18, 172.19, dan seterusnya nyaman untuk umum, tetapi kadang kebijakan jaringan menuntut alamat tertentu — misalnya segmen kantor yang sudah dipesan untuk keluarga server internal. Docker membiarkan kita menuliskan subnet sendiri saat membuat jaringan:
$ docker network create --subnet 10.10.0.0/24 net-kantorOutput yang Dihasilkan:
8b3e7c9a1d5f0a2c4e6b8d0f1a3c5e7b9d0f2a4c6e8a1b3d5f7a9c0e2b4d6f8aJaringan net-kantor kini berdiri di segmen 10.10.0.0/24 — dua ratus lima puluh empat alamat yang jauh lebih kecil dari /16, dan pilihan ukuran ini pun bagian dari desain. Di segmen inilah IP statis masuk akal: layanan yang seluruh tim tahu alamatnya, seperti printer kantor yang selama puluhan tahun jadi contoh klasik perangkat beralamat tetap:
$ docker run -d --name printer --network net-kantor --ip 10.10.0.7 alpine:3.20 sleep 1hOutput yang Dihasilkan:
9f2b6d8a4c7e1b3d5f7a9c0e2a4c6e8b0d2f4a6c8e1a3b5d7f9a0c2e4b6d8f1aFlag --ip 10.10.0.7 menuntut jaringannya memiliki subnet yang dideklarasikan — itulah sebabnya --subnet disertakan saat create. Kita verifikasi hasilnya dengan format ringkas:
$ docker network inspect net-kantor --format '{{range .Containers}}{{.Name}} -> {{.IPv4Address}}{{end}}'Output yang Dihasilkan:
printer -> 10.10.0.7/24IP statis tampak memikat, tetapi dua peringatan menyertainya. Pertama, konflik alamat: daemon menolak memulai container bila alamat yang kita minta sudah diduduki penghuni lain — galat address already in use muncul dan container tidak jalan, sehingga setiap --ip harus dicatat dan dikoordinasikan seperti inventaris alamat kantor sungguhan. Kedua, IP statis mengunci topologi: container yang pindah host atau diciptakan ulang di jaringan berbeda akan kehilangan alamat tetapnya, dan konfigurasi yang bergantung pada angka itu ikut patah. Praktik yang lebih sehat tetap memakai nama dan DNS internal; IP statis disimpan untuk kasus khusus yang benar-benar menuntutnya.
Default Bridge versus User-Defined Bridge #
Seluruh perbedaan yang kita alami sepanjang section ini terangkum dalam satu tabel pembanding:
| Aspek | Default bridge | User-defined bridge |
|---|---|---|
| Resolusi nama container | Tidak ada — ping web-a gagal dengan bad address | DNS internal aktif — nama diterjemahkan otomatis |
Mekanisme --link | Satu-satunya jalan, dan sudah ditinggalkan | Tidak dibutuhkan sama sekali |
| Kelompok isolasi | Seluruh container tanpa --network bercampur satu jaringan | Tiap jaringan adalah dunia terpisah sendiri |
| Menyambungkan container berjalan | Tidak bisa — jaringan dipilih saat docker run | docker network connect dan disconnect kapan pun |
| Kendali subnet dan IP | Bawaan 172.17.0.0/16, tanpa IP statis | --subnet, --gateway, --ip-range, hingga --ip per container |
Sebelum menutup, kita bereskan sisa latihan sambil menjaga dua penghuni yang masih kita perlukan untuk chapter berikutnya:
$ docker rm -f reporter printer
$ docker network rm net-kantorOutput yang Dihasilkan:
reporter
printer
net-kantorJaringan net-aplikasi sengaja kita biarkan hidup bersama penghuninya — web di 172.18.0.2 dan app di 172.18.0.3 — karena merekalah pemain utama chapter berikutnya. Nama web yang barusan berhasil dipanggil adalah pintu masuk pertama kita ke mesin di baliknya: DNS internal Docker yang bekerja pada alamat 127.0.0.11. Chapter Container DNS membedah mesin itu sampai ke roda giginya — bagaimana nama dicocokkan, apa yang terjadi pada nama eksternal seperti example.com, dan bagaimana alias memberi satu container banyak nama.
Referensi #
- Bridge Network Driver — perbedaan default bridge versus user-defined bridge dan alasannya.
- docker network create
— opsi
--subnet,--gateway, dan--ip-rangesaat membuat jaringan. - docker network connect — menyambungkan container yang sedang berjalan ke sebuah jaringan.
- docker container run
— referensi flag
--networkdan--ipuntuk alamat statis.