Aplikasi katalog yang sesungguhnya kini berjalan sebagai image buatan sendiri, tetapi ia masih berdiri sebagai pulau: service web tidak tahu di mana db berada, dan satu-satunya kabel yang terpasang hanyalah pemetaan port yang ditulis dalam bentuk paling singkat. Chapter ini membangun seluruh lapisan jaringan stack katalog: bentuk pendek dan panjang kunci ports lengkap dengan jebakan penulisannya, kunci expose sebagai dokumentasi port antar service, network bawaan project yang diam-diam sudah bekerja sejak chapter pertama, DNS antar service yang membuat nama db bermakna, hingga custom network untuk isolasi berlapis. Di ujungnya, seluruh konfigurasi itu kita rangkai menjadi berkas katalog final dan saksikan Compose menyelaraskan daemon dengannya tanpa satu perintah pembongkaran manual.
Bentuk Pendek ports dan Empat Variannya #
Kunci ports menerima bentuk pendek berupa string "host:container" — bentuk yang sudah kita pakai sejak chapter pembuka dan yang padanan flag-nya kita bedah tuntas pada Chapter Port Publishing. Empat varian yang paling sering dijumpai:
| Bentuk | Efek |
|---|---|
"8080:3000" | port host 8080 di semua antarmuka menuju port container 3000 |
"127.0.0.1:8080:3000" | hanya proses di mesin host yang dapat menghubungi |
"9000:3000/udp" | pemetaan protokol udp |
"8080-8082:3000" | rentang tiga port host menuju satu port container — senjata --scale pada Chapter Service |
Kutipan pada varian kedua layak digarisbawahi: mengikat ke 127.0.0.1 membatasi pintu host hanya untuk mesin itu sendiri — kebiasaan wajib untuk service internal di server ber-IP publik, persis pembahasan kita pada Chapter Port Publishing tentang membatasi antarmuka.
Long Syntax: Menulis ports Secara Eksplisit #
Bentuk pendek menyembunyikan empat keputusan dalam satu string. Long syntax membukanya menjadi pemetaan dengan empat kunci:
| Kunci | Peran | Nilai pada katalog |
|---|---|---|
target | port di dalam container yang menerima koneksi | 3000 |
published | port di host yang diterbitkan | "8080" |
protocol | tcp atau udp — bawaan tcp | tcp |
mode | host atau ingress — bawaan ingress | ingress |
Untuk service web katalog, bentuk panjang yang setara dengan "8080:3000" adalah:
web:
ports:
- target: 3000
published: "8080"
protocol: tcp
mode: ingressPerbedaan mode adalah pengetahuan yang baru benar-benar berarti di skala orchestration. Mode host memasang pemetaan langsung pada host tempat container berjalan, sedangkan mode ingress memasangnya melalui routing mesh — mekanisme Swarm yang meneruskan lalu lintas dari node mana pun ke container yang benar. Pada satu host seperti laptop kita keduanya berperilaku sama; begitu stack berpindah ke klaster, perbedaannya menentukan arsitektur jaringan — materi yang menanti di Section Orchestration dan Ekosistem. Versi terbaru Compose memakai ingress sebagai bawaan, dan nilai itulah yang tercetak pada hasil render docker compose config di chapter sebelumnya.
expose: Dokumentasi Port Antar Service #
Kunci expose sering disalahartikan sebagai adik kecil ports, padahal keduanya bekerja di ruang yang berbeda. expose mendaftarkan port container tanpa menerbitkannya ke host sama sekali — ia adalah catatan untuk pembaca berkas dan untuk Compose:
| Aspek | ports | expose |
|---|---|---|
| Menerbitkan pintu ke host | ya | tidak |
| Bentuk nilai | pemetaan host ke container | daftar port container |
| Efek jaringan nyata | pemetaan dibuat di host | tidak ada — murni dokumentasi |
| Terbaca lewat | docker port dan kolom PORTS | pembaca compose.yaml |
| Peran utama | pintu dari luar host | catatan port antar service |
Pembanding ini mengulang satu kebenaran yang sudah kita ukir di Section Jaringan Container: dua container dalam satu network saling menghubungi langsung ke port container masing-masing, tanpa memerlukan ports maupun expose — materi Chapter Komunikasi Antar Container dan EXPOSE dan Port. Konsekuensinya untuk katalog: db tidak membutuhkan satu baris ports pun, karena satu-satunya pelanggannya adalah web yang tinggal di network yang sama.
Network Bawaan Project #
Sejak chapter pembuka, setiap docker compose up mencetak baris ✔ Network katalog_default Created — dan sekarang saatnya membuka benda itu. Compose selalu memfasilitasi setiap project dengan satu network bawaan bernama <project>_default; seluruh service yang tidak mendeklarasikan networks otomatis bergabung ke dalamnya. Daftar network di daemon memperlihatkan kehadirannya:
$ docker network lsOutput yang Dihasilkan:
NETWORK ID NAME DRIVER SCOPE
e3f1c2a9b7d4 bridge bridge local
a5d7e9c1f3b6 host host local
0c9b8d7f5a3e none null local
4f2d81e6b3a7 katalog_default bridge localMari kita telaah empat baris tersebut: tiga network pertama adalah milik sistem yang lahir bersama daemon — bridge default docker0, mode host, dan mode none; baris keempat adalah milik Compose, diciptakan khusus untuk project katalog dengan driver bridge. Meski sama-sama bridge, statusnya berbeda dari docker0: katalog_default adalah user-defined network, dan perbedaan itu membawa satu hak istimewa besar yang kita buktikan pada Chapter Container DNS — embedded DNS di 127.0.0.11 hanya aktif pada user-defined network, bukan pada bridge default. Itulah sebabnya Compose tidak pernah memakai docker0 untuk service-service-nya.
DNS Antar Service dan Berkas Final #
Hak istimewa itu bisa kita saksikan bekerja dari dalam container web. Perintah docker compose exec mengeksekusi perintah di service yang sedang jalan — padanan docker exec untuk stack:
$ docker compose exec web nslookup dbOutput yang Dihasilkan:
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: db
Address: 172.18.0.2Mari kita telaah jawaban DNS tersebut: server 127.0.0.11 adalah embedded DNS milik network — bukan DNS rumah atau kantor; nama db — nama service di compose.yaml — menyelesaikan menjadi 172.18.0.2, alamat container postgres di network katalog. Nama container katalog-db-1 juga menyelesaikan ke alamat yang sama; Compose mendaftarkan keduanya sebagai alias. Inilah fondasi yang membuat aplikasi cukup menulis db sebagai alamat database.
Seluruh potongan chapter ini kini dirangkai menjadi berkas katalog final:
name: katalog
services:
web:
build: .
image: katalog-web:dev
ports:
- target: 3000
published: "8080"
protocol: tcp
mode: ingress
environment:
DATABASE_URL: postgres://katalog:rahasia123@db:5432/katalog
restart: unless-stopped
db:
image: postgres:18-alpine
environment:
- POSTGRES_USER=katalog
- POSTGRES_PASSWORD=rahasia123
- POSTGRES_DB=katalog
expose:
- "5432"
restart: unless-stoppedMari kita telaah perubahan final tersebut:
portsweb memakai long syntax — empat keputusan yang tadinya tersembunyi dalam string kini tertulis eksplisit; nilainya setara dengan"8080:3000".DATABASE_URLpada environment web — string koneksi lengkap untuk aplikasi: userkatalog, kata sandirahasia123, hostdb, port5432, basis datakatalog; host dalam string itu adalah nama service yang barusan kita buktikan menyelesaikan lewat DNS. Bentuk pemetaan dipakai di sini sebagai variasi dari bentuk daftar — kedua bentuk sah, persis kesaksian renderer pada Chapter Struktur compose.yaml.expose: "5432"pada db — dokumentasi bagi pembaca berkas bahwa postgres hidup di port 5432; tanpa satu punports, db tetap tak terjangkau dari luar host.- Aplikasi katalog sendiri belum membaca
DATABASE_URL—server.jskita masih menjawab JSON statis; menyambungkan aplikasi ke database adalah pekerjaan Chapter Application dan Database di Section Aplikasi Multi-Container. Tugas chapter ini menuntaskan jalurnya: nama, port, dan jaringan sudah siap dipakai.
Custom Network: Frontend dan Backend #
Network bawaan project menghubungkan semua service dengan semua service — topologi yang ramah tetapi tanpa sekat. Stack yang lebih besar biasanya memecahnya menjadi beberapa network top-level, dengan pola paling umum adalah frontend/backend:
services:
proxy:
image: nginx:1.29-alpine
networks:
- frontend
web:
build: .
image: katalog-web:dev
networks:
- frontend
- backend
db:
image: postgres:18-alpine
networks:
- backend
networks:
frontend:
backend:Network yang dideklarasikan top-level menjalankan aturan penamaan yang sudah kita kenal: frontend pada project katalog lahir sebagai katalog_frontend, dan backend sebagai katalog_backend. Topologinya membentuk pertahanan berlapis — proxy hanya berjumpa web, web menjadi satu-satunya jembatan menuju db, dan container frontend tidak punya jalur sama sekali menuju database. Kebijakan jaringan semacam ini adalah lanjutan langsung dari latihan isolasi pada Chapter Membuat Custom Network.
Dua perluasan masih tersedia pada deklarasi network. Subnet bisa ditetapkan eksplisit lewat blok ipam ketika host memiliki rencana penomoran sendiri, dan service boleh menerima nama tambahan dalam sebuah network lewat aliases — mekanisme nama alternatif yang kita bedah pada Chapter Network Alias:
networks:
backend:
ipam:
config:
- subnet: 10.66.0.0/24 db:
networks:
backend:
aliases:
- basisdataUntuk katalog dengan dua service, keputusan kita sederhana: tetap di network bawaan project. Satu network untuk dua service belum memerlukan sekat, dan menambahkan lapisan sekarang hanya menambah bahasan tanpa manfaat — custom network akan kembali relevan begitu stack bertumbuh menjadi proxy plus aplikasi plus cache, kisah Section Aplikasi Multi-Container.
Konflik Port dan Isolasi Antar Project #
Satu jebakan menanti setiap orang yang menjalankan dua stack sekaligus di satu host — misalnya katalog dan lingkungan ujinya dari Chapter Service. Kedua project memakai berkas dengan published: "8080", dan port host hanya boleh dipakai satu pemetaan:
Error response from daemon: driver failed programming external connectivity on endpoint katalog-uji-web-1 (9a3f2c8e4b1d): Bind for 0.0.0.0:8080 failed: port is already allocatedDua jalan keluarnya persis resep yang Budi jalankan pada Chapter Service: mengganti nomor port terbitkan pada berkas project kedua, atau menjalankan berkas yang sama sebagai project terpisah lewat -p dengan port yang tetap berbeda — dua stack boleh berbagi host, tetapi tidak boleh berbagi nomor pintu.
Yang menarik, kedua project itu tetap terisolasi satu sama lain meski berbagi mesin. Setiap project membawa network sendiri — katalog_default dan katalog-uji_default — dan embedded DNS hanya melayani nama dalam network yang sama: nama db di dalam container project katalog menyelesaikan ke postgres milik katalog, tidak pernah ke postgres milik katalog-uji. Tabrakan nama antar project mustahil terjadi karena keduanya tidak pernah berbagi ruang nama; tabrakan hanya mungkin terjadi di ruang nomor port milik host.
Idempoten: Berkas sebagai Sumber Kebenaran #
Berkas final di atas mengubah kedua service sekaligus, dan inilah momen terbaik untuk menyaksikan karakter utama Compose. Budi menjalankan perintah yang sama dengan yang sudah puluhan kali ia ketik:
$ docker compose up -dOutput yang Dihasilkan:
[+] Running 4/4
✔ Container katalog-db-1 Recreated 0.3s
✔ Container katalog-db-1 Started 0.6s
✔ Container katalog-web-1 Recreated 0.2s
✔ Container katalog-web-1 Started 0.4sMari kita telaah apa yang baru saja terjadi: Compose membaca berkas, membandingkan setiap service dengan container yang sedang hidup, dan menemukan dua perbedaan — expose baru pada db serta long syntax dan DATABASE_URL baru pada web. Container lama dibongkar, container baru diciptakan sesuai deklarasi terbaru, semuanya dalam satu perintah tanpa satu docker rm manual. Jalankan perintah yang sama lagi tanpa mengubah berkas, dan Compose tidak menyentuh apa pun — deklarasi dan keadaan daemon sudah cocok. Inilah makna sesungguhnya dari deklaratif: berkas adalah sumber kebenaran, perintah hanyalah penyelarasan.
Jalur jaringan katalog kini utuh: port host diterbitkan eksplisit dengan long syntax, nama db menyelesaikan lewat embedded DNS, dan seluruh service berbagi network bawaan project. Namun cerita ini menyisakan satu lubang yang sudah kita kenali jauh sebelum Compose tiba: docker compose down membongkar container db, dan bersamanya seluruh direktori data PostgreSQL — yang hidup di writable layer container — ikut lenyap, persis tragedi yang kita bangun kesadarannya pada Chapter Writable Container Layer dan Konsep Persistence. Compose punya jawaban deklaratifnya juga: blok volumes. Chapter Volume dan Bind Mount memindahkan data katalog ke tempat yang aman dari down.
Referensi #
- networks — Compose file reference — blok networks top-level, konfigurasi ipam, dan alias per service.
- Docker networking — konsep bridge, user-defined network, dan embedded DNS yang mendasari perilaku Compose.
- PostgreSQL — Docker Hub — variabel POSTGRES_* dan utilitas pg_isready pada image yang dipakai service db.