Jaringan net-aplikasi kini berdiri dengan subnet pilihan kita sendiri, dan janji terbesarnya baru selesai setengah: kelemahan default bridge yang paling menyakitkan — tetangga tidak bisa dipanggil dengan nama — telah diperbaiki oleh embedded DNS, tetapi kita belum pernah membuka kap mesinnya. Padahal mesin itu bekerja di balik satu berkas kecil dan satu alamat IP yang bahkan bukan alamat sungguhan: 127.0.0.11. Chapter ini membongkar keduanya, membedah dari mana datangnya jawaban DNS, lalu menguji seluruh rantai resolusi dengan ping, nslookup, dan getent — termasuk keanehan output yang akan kita temui di tengah jalan dan cara membacanya. Di ujung chapter, nama container, alias, dan bahkan domain internet akan terasa seperti satu sistem yang sama, karena memang begitulah Docker merancangnya.
nameserver 127.0.0.11 di resolv.conf #
Kita bangun kembali dua penghuni net-aplikasi — web sebagai server nginx dan app sebagai pembantu uji berbasis Alpine — di atas jaringan yang ditinggalkan Chapter Membuat Custom Network:
$ docker run -d --name web --network net-aplikasi nginxOutput yang Dihasilkan:
a30f44ee181d3fc508d63f7247bca1dbc366945e9ed35d3797a3e1d3b9cb9abf$ docker run -d --name app --network net-aplikasi alpine:3.20 sleep 1hOutput yang Dihasilkan:
dfe3682735b12f97dae4236e6b6a4332ff49bfcd9c556706538186bdb72bbf39Dari dalam app, berkas pertama yang menarik untuk dibaca adalah konfigurasi resolver:
$ docker exec app cat /etc/resolv.confOutput yang Dihasilkan:
nameserver 127.0.0.11
options ndots:0Mari kita telaah dua baris pendek itu:
nameserver 127.0.0.11— seluruh pertanyaan DNS dari container ini diarahkan ke alamat loopback port 53; alamat itu bukan server luar, melainkan pintu menuju embedded DNS server milik daemon Docker yang menyala di dalam network namespace container.options ndots:0— aturan resolver soal titik: tanpa opsi ini, nama pendek akan dicoba dengan sufiks pencarian lebih dulu; denganndots:0, nama apa pun dicoba apa adanya terlebih dahulu, sehingga nama container pendek terjawab tanpa perputaran tambahan.- Berkas ini ditulis ulang oleh daemon — container di user-defined network tidak mewarisi
/etc/resolv.confmilik host sebagaimana container di default bridge; daemon menimpanya agar seluruh resolusi berpusat di127.0.0.11.
Ping dengan Nama #
Bukti paling cepat bahwa rantai resolusi bekerja adalah memanggil web dengan namanya dari dalam app:
$ 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.121 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.109 ms
--- web ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.109/0.115/0.121 msMari kita telaah baris pertama yang paling penting:
PING web (172.18.0.2)— sebelum satu paket pun terkirim, tekswebtelah berubah menjadi alamat; perubahan itu dilakukan embedded DNS, dan tanda kurung memperlihatkan hasil terjemahannya.- Alamat yang dijawab adalah 172.18.0.2 — web adalah container pertama yang menempel di net-aplikasi, jadi bendahara alamat jaringan memberinya nomor kedua setelah gateway; persis peta IP yang kita kenal dari Chapter Membuat Custom Network.
ttl=64dan waktu di bawah 0,2 ms — perjalanan selesai di dalam switch virtual, tanpa NAT dan tanpa keluar host; indikator yang sama seperti saat kita membandingkan bridge default pada Chapter Bridge Network.- Kontras dengan kegagalan yang dulu — perintah seiras ini pada default bridge berakhir dengan
ping: bad address 'web-a'; sekarang berhasil, dan satu-satunya hal yang berubah adalah jaringannya.
Dua Sumber Jawaban DNS #
Server di 127.0.0.11 bukan sekadar penerjemah nama container. Ia adalah resolver dua arah yang menggabungkan dua sumber jawaban menjadi satu pintu, dan memahami pembagian kerja ini adalah kunci mendiagnosis masalah DNS kelak:
| Sumber jawaban | Melayani | Karakteristik |
|---|---|---|
| Tabel internal daemon | nama container dan network alias pada jaringan yang sama | selalu segar — container baru otomatis terdaftar, container mati otomatis dicabut |
| Penerusan ke DNS upstream host | nama domain internet seperti example.com | bergantung pada konektivitas DNS host; jawaban datang dari luar |
Perjalanan satu pertanyaan DNS melalui kedua sumber itu tergambar berikut:
Diagram di atas memperlihatkan satu titik keputusan di jantung embedded DNS. Mari kita telaah implikasinya:
- Kabar baik bagi nama internal — jawaban untuk nama container tidak pernah meninggalkan host, tidak bergantung pada internet, dan tidak pernah basi karena daemon selalu tahu penghuni setiap network.
- Kabar baik kedua bagi nama eksternal — container tidak perlu tahu DNS apa pun milik host; penerusan itu sebabnya
apk addpada chapter berikutnya bisa mengunduh paket dari repositori publik tanpa konfigurasi tambahan. - Sisi rapuhnya ada di cabang kanan — bila DNS host bermasalah, nama container tetap sehat sementara nama internet mati; gejala asimetris seperti ini akan kita pakai sebagai alat diagnosis pada Chapter Troubleshooting Network.
Format Nama Internal #
Nama yang dilayani tabel internal punya wujud yang khas: pendek, tanpa titik, satu label. Nama web terdaftar sebagai web — bukan web.example.com, bukan web.net-aplikasi, dan bukan web.local. Ini bukan kelalaian Docker, melainkan konsekuensi dari cara kerja tabel itu: daemon mendaftarkan identitas container (nama dan alias) sebagai label tunggal di dalam jaringan, tanpa membungkusnya dengan sufiks domain apa pun.
Konsekuensinya menguntungkan selama kita mengikuti konvensinya. Nama pendek tidak akan pernah tertukar dengan domain publik — tidak ada situs publik bernama satu-label web — dan kombinasi dengan ndots:0 membuat pencarian selesai dalam satu langkah. Karena itu kebiasaan penamaan yang baik di sisi DNS sederhana: gunakan nama pendek yang kaya makna (web, db, app, cache) sebagai nama container, lalu simpan kekayaan konteks di alias atau di environment variable aplikasi.
/etc/hosts dan –hostname #
Berkas kedua yang menempel di setiap container adalah /etc/hosts. Isinya memuat loopback bawaan dan satu baris istimewa di ujung:
$ docker exec app cat /etc/hostsOutput yang Dihasilkan:
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 dfe3682735b1Mari kita telaah baris-barisnya:
- Enam baris pertama adalah standar Linux — loopback IPv4 dan IPv6 beserta alamat multicast; hadir di setiap container terlepas dari network-nya.
- Baris terakhir memetakan alamat container ke namanya sendiri —
172.18.0.3adalah alamat app, dandfe3682735b1adalah bentuk pendek ID container, 12 karakter heksadesimal yang juga muncul didocker ps. - Hostname bawaan memang ID pendek — itulah sebabnya prompt shell di dalam container sering menampilkan deretan aneh; Docker tidak berusaha mengarang nama, ia memakai identitas yang pasti unik.
Flag --hostname mengganti identitas itu saat container diciptakan. Kita buktikan dengan container sekali jalan:
$ docker run --rm --network net-aplikasi --hostname peladen alpine:3.20 cat /etc/hostsOutput yang Dihasilkan:
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.5 peladenDua hal perlu dicatat dari percobaan ini. Pertama, baris ID heksadesimal tergantikan peladen, dan alamat yang menyertainya adalah 172.18.0.5 — nomor urut berikutnya setelah web dan app. Kedua, dan ini yang sering mengejutkan: peladen tidak terdaftar di embedded DNS. --hostname hanya mengurus identitas internal container — berkas /etc/hosts dan prompt shell — sedangkan nama yang bisa dipanggil container lain tetaplah nama container dan aliasnya.
Alias dengan –network-alias #
Sebuah container boleh punya nama tambahan di jaringan, dan nama tambahan itu justru ditetapkan saat container diciptakan. Kita undang penghuni ketiga net-aplikasi — database untuk latihan kita — sekaligus memperkenalkan flag-nya:
$ docker run -d --name db --network net-aplikasi --network-alias db-utama \
-e POSTGRES_PASSWORD=rahasia123 postgres:18-alpineOutput yang Dihasilkan:
90e6daa3f3c79ad6399fbf3489358bbebd9dfc70bb8c59f8a2d0c4af0e8394ffContainer ini kini punya dua identitas di jaringan yang sama. Kita uji keduanya dari app:
$ docker exec app ping -c 2 db-utamaOutput yang Dihasilkan:
PING db-utama (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.143 ms
64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.128 ms
--- db-utama ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.128/0.135/0.143 msMari kita telaah identitas ganda itu:
db-utamadandbmenuju alamat yang sama — alias bukan container baru, melainkan baris tambahan di tabel internal daemon; keduanya diterjemahkan ke172.18.0.4.- Flag dapat diulang — satu
docker runboleh memasang banyak--network-aliassekaligus, pola yang akan kita perdalam pada Chapter Network Alias. - Password tetap lewat environment variable —
POSTGRES_PASSWORD=rahasia123tidak ada hubungannya dengan DNS; ia cuma kebiasaan lama dari Section Konfigurasi Container yang tetap kita bawa agar PostgreSQL mau menyala.
Verifikasi dengan nslookup dan getent #
ping membuktikan resolusi bekerja, tetapi dua perkakas lain memperlihatkan mekanismenya lebih telanjang. Yang pertama bertanya langsung ke server DNS:
$ docker exec app nslookup webOutput yang Dihasilkan:
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: web
Address: 172.18.0.2
Non-authoritative answer:Output di atas memuat satu keanehan yang tampak seperti galat, padahal bukan. Mari kita telaah tiga hal sekaligus:
- Bagian
Server:mengonfirmasi lawan bicara — busyboxnslookupmembaca/etc/resolv.conf, menemukan127.0.0.11, dan mencantumkan port standarnya, 53. Name: webdanAddress: 172.18.0.2— inilah jawaban dari tabel internal daemon; perhatikan nama yang dikembalikan persis satu label tanpa titik, sesuai format nama internal.- Baris
Non-authoritative answer:kedua yang kosong — busybox mengirim dua pertanyaan sekaligus untuk satu nama: A (IPv4) dan AAAA (IPv6); jawaban IPv4 tampil lengkap, sedangkan jawaban IPv6 kosong karena net-aplikasi tidak mengalokasikan alamat IPv6 — baris kosong itu sekadar jejak pertanyaan kedua.
Perkakas kedua menempuh jalur yang dipakai aplikasi sungguhan — resolver sistem, bukan server DNS langsung:
$ docker exec app getent hosts webOutput yang Dihasilkan:
172.18.0.2 webgetent menanyakan resolver sistem yang pada gilirannya membaca /etc/hosts lalu /etc/resolv.conf; satu baris balasan ini adalah wujud yang juga dilihat aplikasi saat memanggil connect() dengan nama. Ketika sebuah aplikasi gagal menyambung padahal nslookup berhasil, bedakan jalurnya: nslookup menguji server DNS, getent menguji seluruh rantai resolver.
DNS Eksternal Lewat 127.0.0.11 #
Cabang kanan diagram kita belum teruji. Nama internet juga harus bisa ditanyakan dari container, tetap lewat alamat yang sama:
$ docker exec app nslookup example.comOutput yang Dihasilkan:
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: example.com
Address: 23.215.0.136
Name: example.com
Address: 23.215.0.138
Name: example.com
Address: 96.7.128.175
Non-authoritative answer:
Name: example.com
Address: 2606:2800:220:1:248:1893:25c8:1946Mari kita telaah jawaban yang datang dalam dua ronde:
- Tiga alamat IPv4 pada ronde pertama — jawaban untuk pertanyaan A; example.com memang dilayani beberapa alamat sekaligus, dan daftar persisnya bisa berbeda pada waktu lain.
- Satu alamat IPv6 pada ronde kedua — jawaban untuk pertanyaan AAAA yang busybox kirim berikutnya; ronde ini kosong pada nama container karena container kita tak punya IPv6, sementara domain internet sungguhan punya.
- Tidak ada satu pun paket yang keluar dari container menuju DNS internet — seluruh tanya-jawab terjadi ke
127.0.0.11, lalu daemon yang meneruskannya ke DNS upstream host; container tidak tahu dan tidak perlu tahu DNS apa yang dipakai host.
Tiga Alamat yang Perlu Dikenali #
Kita telah bertemu tiga alamat istimewa dalam satu chapter, dan ketiganya akan kembali berulang kali. Tabel berikut merangkumnya sebagai peta kecil:
| Alamat | Perannya | Kapan tersedia |
|---|---|---|
127.0.0.11 | pintu embedded DNS di dalam container | hanya pada user-defined network |
host.docker.internal | nama khusus yang menunjuk host | bawaan Docker Desktop; di Linux perlu flag tambahan |
172.18.0.1 | gateway subnet net-aplikasi, wajah host di jaringan | setiap bridge network punya satu |
Baris kedua dan ketiga masih berupa pengumuman tanpa demo. Keduanya menunggu panggung yang lebih besar — studi kasus tiga container yang saling bekerja sama dengan curl dan nc — dan panggung itu dibangun pada Chapter Komunikasi Antar Container.
Sebelum pindah, kita bersihkan penghuni net-aplikasi sambil membiarkan jaringannya berdiri:
$ docker rm -f web app dbOutput yang Dihasilkan:
web
app
dbMesin nama Docker kini sudah terbongkar: satu alamat loopback, dua sumber jawaban, nama pendek sebagai kontrak, /etc/hosts sebagai identitas diri, dan alias sebagai nama tambahan. Tetapi tahu mesinnya belum sama dengan mengemudikannya — container sungguhan saling bekerja lewat HTTP dan koneksi TCP, dan itulah percakapan yang akan kita dengarkan langsung di chapter berikutnya.
Referensi #
- Docker Networking Overview
— perilaku embedded DNS
127.0.0.11, penerusan ke DNS host, dan perbedaan default bridge. - docker container run — CLI Reference
— flag
--network,--network-alias,--hostname, dan--add-host. - docker network connect — CLI Reference — menambah container ke jaringan beserta aliasnya.