Komunikasi Container

Komunikasi Container

Bitnesia Sep 12, 2026 10 EN

Punya beberapa container yang saling terhubung ke satu custom bridge network baru menyelesaikan setengah masalah. Setelah container bisa saling melihat, pertanyaan berikutnya adalah bagaimana komunikasi itu sebenarnya bekerja di baliknya, bagaimana Docker menerjemahkan nama container menjadi alamat yang bisa dijangkau, dan bagaimana port yang dipakai aplikasi di dalam container bisa (atau tidak bisa) diakses dari luar. Developer yang membangun aplikasi multi-container butuh paham mekanisme ini supaya service saling terhubung dengan benar, sementara Sysadmin/DevOps Engineer perlu memahaminya untuk mengatur exposure port yang aman di production. Bab ini membahas cara kerja komunikasi antar container secara lebih mendalam, mekanisme DNS dan service discovery bawaan Docker, opsi --link yang sudah deprecated, sampai perbedaan mendasar antara expose dan publish port yang sering tertukar.

14.1 Komunikasi Antar Container

Custom bridge network sudah dibahas sebagai solusi utama menghubungkan container satu sama lain, tapi ada beberapa detail teknis yang perlu dipahami lebih jauh supaya komunikasi antar container tetap stabil, terutama saat topologi aplikasi mulai melibatkan lebih dari dua container atau lebih dari satu network sekaligus.

14.1.1 Prasyarat Komunikasi Antar Container

Dua container cuma bisa saling berkomunikasi langsung lewat nama kalau memenuhi dua syarat: keduanya terhubung ke network yang sama, dan network tersebut bukan default bridge network. Buktikan lagi dengan menjalankan container aplikasi dan container database di app-net yang sama.

docker network create app-net
docker run -d --name db --network app-net -e POSTGRES_PASSWORD=secret postgres:16-alpine
docker run -d --name api --network app-net alpine sleep 3600
docker exec api ping -c 2 db

Container api berhasil menjangkau db cukup lewat namanya karena keduanya berada di custom bridge network yang sama. Kalau salah satu container dijalankan tanpa opsi --network, container tersebut otomatis masuk ke default bridge network dan tidak akan bisa dijangkau lewat nama dari container lain di app-net, meski secara teknis keduanya masih berjalan di host fisik yang sama.

14.1.2 Komunikasi Lintas Network

Sebuah container bisa terhubung ke lebih dari satu network sekaligus, sebuah pola yang berguna saat sebagian service perlu terisolasi dari service lain. Skenario umum di lapangan: container reverse proxy perlu menjangkau container aplikasi frontend maupun backend, tapi frontend dan backend sendiri tidak perlu saling menjangkau langsung.

docker network create frontend-net
docker network create backend-net
docker run -d --name proxy --network frontend-net alpine sleep 3600
docker network connect backend-net proxy
docker run -d --name app-backend --network backend-net alpine sleep 3600
docker exec proxy ping -c 2 app-backend

Container proxy di atas menjadi anggota frontend-net sekaligus backend-net lewat docker network connect, sehingga bisa menjangkau container di kedua network tersebut. Sebaliknya, container yang cuma menjadi anggota backend-net saja (seperti app-backend) tidak bisa menjangkau container manapun di frontend-net. Pola ini jadi salah satu cara sederhana menerapkan segmentasi jaringan tanpa perlu firewall rule tambahan, karena isolasi terjadi otomatis selama sebuah container memang tidak didaftarkan sebagai anggota network yang ingin diisolasi.

docker rm -f proxy app-backend api db
docker network rm frontend-net backend-net app-net

14.2 DNS dan Service Discovery

Service discovery adalah mekanisme yang memungkinkan sebuah service menemukan lokasi (alamat) service lain tanpa perlu hardcode alamat IP secara manual. Docker menyediakan mekanisme ini secara bawaan lewat embedded DNS server yang berjalan otomatis di setiap custom network.

14.2.1 Embedded DNS Server

Setiap kali sebuah container terhubung ke custom bridge network, Docker daemon otomatis mengarahkan resolusi DNS container tersebut ke embedded DNS server miliknya sendiri yang berjalan di alamat internal 127.0.0.11. Cek langsung isi /etc/resolv.conf di dalam container yang terhubung ke custom network.

docker network create app-net
docker run -d --name db --network app-net alpine sleep 3600
docker exec db cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0

Alamat 127.0.0.11 ini bukan DNS server sungguhan yang bisa diakses dari luar container, melainkan proxy internal yang dikelola Docker daemon untuk menerjemahkan nama container maupun network alias menjadi alamat IP yang sesuai di dalam network tersebut. Setiap query DNS yang tidak dikenali (misalnya domain publik seperti docker.com) diteruskan oleh embedded DNS server ini ke DNS resolver yang dipakai host, sehingga container tetap bisa melakukan resolusi nama ke internet seperti biasa.

14.2.2 Service Discovery Lewat Nama Container dan Alias

Mekanisme service discovery Docker pada dasarnya sederhana: nama container dan network alias yang sudah dibahas menjadi satu-satunya "katalog" yang dipakai embedded DNS server untuk resolusi nama. Tidak ada konfigurasi tambahan yang perlu dilakukan; begitu sebuah container terhubung ke custom network dengan nama tertentu, nama tersebut otomatis bisa dipakai container lain di network yang sama.

docker run -d --name api --network app-net --network-alias backend alpine sleep 3600
docker run -d --name web --network app-net alpine sleep 3600
docker exec web nslookup backend

Perintah nslookup di atas membuktikan bahwa alias backend berhasil di-resolve ke alamat IP container api oleh embedded DNS server. Pola inilah yang membuat konfigurasi koneksi antar service di banyak aplikasi cukup memakai nama service (misalnya DATABASE_HOST=db) tanpa perlu tahu alamat IP container yang sebenarnya, karena Docker Compose (yang membahas orkestrasi multi-container secara lebih detail) memanfaatkan mekanisme embedded DNS yang sama persis di baliknya. Di lapangan, kegagalan resolusi nama antar container hampir selalu berakar dari salah satu dari dua penyebab: container berada di network yang berbeda, atau salah ketik nama/alias container.

docker rm -f api web db
docker network rm app-net

14.3 Link Containers (Deprecated)

Sebelum custom bridge network dan embedded DNS server tersedia, Docker menyediakan opsi --link sebagai satu-satunya cara menghubungkan container secara eksplisit sekaligus mendapat resolusi nama sederhana. Opsi ini kini berstatus deprecated menurut dokumentasi resmi Docker dan tetap penting dipahami sekadar untuk mengenali pola lama di codebase atau tutorial lawas, bukan untuk dipakai pada konfigurasi baru.

14.3.1 Cara Kerja Legacy Link

Opsi --link dipakai bersama docker run untuk menghubungkan sebuah container baru ke container lain yang sudah berjalan, dengan sintaks --link <container>:<alias>.

docker run -d --name db-legacy alpine sleep 3600
docker run --rm --link db-legacy:db alpine ping -c 2 db

Secara internal, --link bekerja dengan menambahkan entri statis ke file /etc/hosts milik container yang baru dijalankan, alih-alih memakai DNS server yang bisa memperbarui pemetaan nama secara dinamis. Pendekatan ini punya banyak keterbatasan: entri /etc/hosts tidak otomatis diperbarui kalau container tujuan di-restart dan mendapat IP baru, cuma berlaku satu arah (container tujuan tidak otomatis bisa menjangkau balik container yang memakai --link), dan tidak mendukung skenario container yang tersebar di banyak network sekaligus.

14.3.2 Alasan Migrasi ke Custom Network

Custom bridge network menggantikan seluruh fungsi --link dengan cara yang jauh lebih andal: resolusi nama lewat embedded DNS server otomatis diperbarui kalau sebuah container di-restart dan berganti IP, berlaku dua arah antar seluruh anggota network, dan mendukung network alias yang lebih fleksibel dibanding alias statis milik --link. Karena itu, dokumentasi resmi Docker secara eksplisit menyarankan memakai user-defined network sebagai pengganti --link untuk seluruh kebutuhan komunikasi antar container, termasuk pada instalasi Docker Engine maupun Docker Desktop versi terkini.

docker rm -f db-legacy

14.4 Expose vs Publish Ports

Dua istilah yang sering tertukar oleh pemula adalah expose dan publish port. Keduanya terdengar mirip tapi punya efek yang sangat berbeda terhadap keterjangkauan sebuah container dari luar host.

14.4.1 EXPOSE di Dockerfile

Instruksi EXPOSE di dalam Dockerfile berfungsi murni sebagai dokumentasi, memberi tahu siapa pun yang membaca image bahwa aplikasi di dalam container mendengarkan (listening) di port tertentu. Instruksi ini tidak membuka port tersebut agar bisa diakses dari luar container atau dari host.

FROM nginx:alpine
EXPOSE 80

Efek praktis EXPOSE cuma terasa di dua hal: metadata image menampilkan port tersebut lewat docker inspect atau docker image inspect, dan opsi -P (huruf kapital) pada docker run memanfaatkan daftar port yang di-EXPOSE ini untuk otomatis melakukan publish ke port acak di host. Selain dua hal itu, container yang di-EXPOSE port-nya tapi dijalankan tanpa opsi publish apa pun tetap sama sekali tidak bisa diakses dari luar container.

14.4.2 Publish Port dengan -p

Publish adalah tindakan sebenarnya yang membuka jalur akses dari luar host menuju port di dalam container, dilakukan lewat opsi -p atau --publish saat menjalankan docker run.

docker run -d --name web -p 8080:80 nginx:alpine
curl http://localhost:8080

Sintaks -p 8080:80 di atas memetakan port 8080 di host ke port 80 di dalam container. Docker mengatur pemetaan ini lewat aturan NAT di level kernel host (memakai iptables pada Linux), sehingga trafik yang masuk ke port host diteruskan ke container yang bersangkutan. Tanpa publish, port yang dibuka aplikasi di dalam container cuma bisa diakses oleh container lain yang berada di network yang sama, tidak bisa dijangkau dari luar host sama sekali.

Opsi -P (huruf kapital, tanpa menentukan port tujuan) mempublikasikan seluruh port yang sudah di-EXPOSE di Dockerfile ke port acak yang dipilih Docker di host.

docker run -d --name web2 -P nginx:alpine
docker port web2

Perintah docker port di atas menampilkan pemetaan port acak yang dipilih Docker untuk container web2, berguna terutama saat menjalankan banyak instance container yang sama tanpa perlu menentukan port host secara manual satu per satu.

14.4.3 Kapan Expose Saja Sudah Cukup

Dalam skenario komunikasi antar container di network yang sama, publish port dari host sama sekali tidak diperlukan. Container database misalnya, cukup di-EXPOSE (atau bahkan tanpa EXPOSE sama sekali, karena bukan sebuah keharusan) dan terhubung ke custom network yang sama dengan container aplikasi, tanpa perlu opsi -p apa pun.

docker network create app-net
docker run -d --name db --network app-net -e POSTGRES_PASSWORD=secret postgres:16-alpine
docker run -d --name api --network app-net -p 3000:3000 node-app:latest

Pada contoh di atas, container db cuma perlu terhubung ke app-net agar bisa dijangkau container api lewat nama db dan port default PostgreSQL (5432), tanpa publish ke host sama sekali. Sebaliknya, container api memang perlu di-publish lewat -p 3000:3000 karena harus bisa diakses dari luar host, misalnya oleh browser pengguna. Sysadmin/DevOps Engineer yang mengelola container di production perlu disiplin menerapkan prinsip ini: publish port cuma untuk service yang benar-benar butuh diakses dari luar, sementara service internal seperti database atau cache cukup terhubung lewat network tanpa publish, supaya permukaan serangan (attack surface) tetap seminimal mungkin. Attacker yang melakukan pemindaian port dari luar host tidak akan menemukan port database yang tidak pernah dipublish, meski container tersebut tetap berjalan dan bisa diakses normal oleh container aplikasi yang memang membutuhkannya.

docker rm -f db api web web2
docker network rm app-net