DNS Internal #
Salah satu fitur Docker yang sering dianggap sepele tapi sangat krusial dalam arsitektur container adalah DNS internal. Berkat DNS ini, container bisa saling menemukan satu sama lain hanya dengan nama service atau container — tidak perlu tahu IP address, tidak perlu hardcode, tidak perlu konfigurasi tambahan.
Tanpa DNS internal, membangun sistem multi-container akan jauh lebih rapuh. Setiap kali container restart, IP-nya bisa berubah. Setiap kali ada scaling, IP baru muncul. Tanpa service discovery yang stabil, satu perubahan kecil bisa meruntuhkan seluruh arsitektur.
Docker menyediakan DNS internal yang bekerja otomatis pada user-defined network. Ia embedded di Docker Engine, super cepat, dan tidak butuh konfigurasi manual. Artikel ini membahas DNS internal secara mendalam: cara kerjanya, kapan aktif, bagaimana ia berinteraksi dengan Docker Compose, dan cara troubleshoot saat resolusi nama gagal.
Apa Itu DNS Internal Docker? #
DNS internal Docker adalah DNS server bawaan yang berjalan di dalam Docker Engine. Saat container menjalankan query DNS, query tersebut secara otomatis diarahkan ke server ini lewat resolver 127.0.0.11.
flowchart LR
A[Container: app] -->|nslookup db| B[127.0.0.11]
B -->|Cek: db container di network?| C{Docker DNS}
C -- Ya, ketemu --> D[Return: 172.18.0.3]
C -- Tidak --> E[Forward ke external DNS]
E --> F[Google / Cloudflare DNS]
F --> E
E --> A
Karakteristik utama:
- Resolver otomatis — container tidak perlu konfigurasi
/etc/resolv.confmanual. - Resolve container name —
db,api,webbisa dipakai sebagai hostname. - Resolve service name — di Compose,
dbmerujuk ke servicedb. - Round-robin — untuk multi-container dengan nama yang sama, return semua IP.
- Forward external — query untuk domain publik diteruskan ke DNS eksternal.
Resolver-nya adalah127.0.0.11. Ini adalah IP internal yang hanya bisa diakses dari dalam container. Saat container menjalankancat /etc/resolv.conf, biasanya akan munculnameserver 127.0.0.11. Jangan bingung —127.0.0.11itu bukan host’s localhost, tapi embedded DNS Docker di dalam container namespace.
Alamat DNS Internal: 127.0.0.11 #
Setiap container yang dibuat dengan network modern (user-defined) akan memiliki 127.0.0.11 sebagai resolver. Cara melihatnya:
docker run --rm --network app-net alpine cat /etc/resolv.conf
Output:
nameserver 127.0.0.11
options ndots:0
nameserver 127.0.0.11— semua query DNS diarahkan ke sini.options ndots:0— jumlah dot minimum sebelum query dianggap FQDN.
ndots:0itu penting: artinya Docker DNS akan mencoba resolve nama pendek (sepertidb) langsung, tanpa menambah domain suffix. Ini yang membuat service discovery via nama pendek bekerja. Kalau ndots lebih tinggi,dbmungkin akan dianggap relatif dan ditambahkan suffix domain dulu.
Kapan DNS Internal Aktif? #
DNS internal Docker hanya bekerja optimal di user-defined network. Ini adalah salah satu perbedaan terbesar antara default bridge dan user-defined bridge.
| Network Type | DNS Internal? | Container name resolve? |
|---|---|---|
Default bridge (bridge) |
❌ Tidak ada | ❌ Tidak (harus pakai IP atau --link) |
| User-defined bridge | ✅ Ya | ✅ Ya |
| Host network | ❌ Tidak | ❌ Tidak (pakai host’s resolv.conf) |
| None network | ❌ Tidak | ❌ Tidak |
| Overlay (Swarm) | ✅ Ya | ✅ Ya (di Swarm scope) |
| Custom network plugin | Tergantung plugin | Tergantung plugin |
Jebakan paling umum: Developer menjalankan container di default bridge, lalu heran kenapaping dbgagal ataucurl http://api:8080dapat error. Ini bukan bug — ini by design. Default bridge tidak punya DNS internal. Solusinya:docker network create my-netlalu jalankan container di network itu.
Eksperimen: Default vs User-Defined #
# Default bridge - DNS tidak aktif
docker run -d --name db --network bridge postgres
docker run -it --rm --network bridge alpine sh
/ # nslookup db
# nslookup: can't resolve 'db'
# (gagal)
# User-defined network - DNS aktif
docker network create app-net
docker run -d --name db --network app-net postgres
docker run -it --rm --network app-net alpine sh
/ # nslookup db
# Server: 127.0.0.11
# Address: 127.0.0.11:53
# Non-authoritative answer:
# Name: db
# Address: 172.18.0.2
# (berhasil!)
Alur Resolusi DNS: Step by Step #
Apa yang terjadi saat container melakukan query ke db:
sequenceDiagram
participant App as Aplikasi (container)
participant R as /etc/resolv.conf
participant DNS as 127.0.0.11
participant E as External DNS
App->>R: gethostbyname("db")
R->>DNS: Query UDP 127.0.0.11:53
DNS->>DNS: Cek: "db" container di network ini?
alt Container ketemu
DNS-->>App: Return 172.18.0.3
else Container tidak ketemu
DNS->>E: Forward ke 8.8.8.8
E-->>DNS: Response (atau NXDOMAIN)
DNS-->>App: Forward response
end
Yang menarik: selama container dan service ada di network yang sama, resolve berhasil dengan latency sangat rendah (sub-millisecond). Tidak ada hop ke external DNS, tidak ada round-trip internet.
flowchart TB
subgraph Internal["Resolve Lokal (instant)"]
A[app nslookup db] --> B[127.0.0.11]
B --> C[Return IP container]
end
subgraph External["Resolve Eksternal (forward)"]
D[app nslookup google.com] --> E[127.0.0.11]
E --> F[Forward ke 8.8.8.8]
F --> G[Return IP google]
end
Kapan Docker DNS gagal?
- Container di network berbeda (tidak ada connectivity).
- Container dengan nama yang sama di network berbeda (ambigu).
- Typo di nama service.
aliasestidak di-set dengan benar di Compose.links(legacy) yang sudah deprecated — jangan dipakai.
Round-Robin untuk Multi-Container #
Saat satu service dijalankan sebagai multiple container (misal api-1, api-2, api-3), Docker DNS bisa resolve semua IP sekaligus untuk load balancing round-robin.
# Start 3 container dengan nama yang sama (alias)
docker network create --driver bridge scale-net
docker run -d --name api-1 --network scale-net --network-alias api my-api
docker run -d --name api-2 --network scale-net --network-alias api my-api
docker run -d --name api-3 --network scale-net --network-alias api my-api
# Query dari container lain
docker run -it --rm --network scale-net alpine sh
/ # nslookup api
# Name: api
# Address: 172.18.0.2
# Address: 172.18.0.3
# Address: 172.18.0.4
# Docker Compose - scale
services:
api:
image: my-api
networks:
- app-net
deploy:
replicas: 3
flowchart LR
Q[Container: client] -->|gethostbyname api| D[127.0.0.11]
D --> R1[172.18.0.2]
D --> R2[172.18.0.3]
D --> R3[172.18.0.4]
Q --> R1
Q --> R2
Q --> R3
Round-robin di sini adalah DNS-level — klien menerima list IP dan biasanya implementasikan load balancing mereka sendiri. Ini berbeda dengan load balancing di level proxy (Nginx, HAProxy) yang lebih advanced.
Penting: round-robin DNS bukan load balancing yang sempurna. Klien mungkin cache hasil dan tidak benar-benar round-robin. Untuk production, lebih baik pakai reverse proxy (Traefik, Nginx) atau orchestrator (K8s, Swarm) yang punya load balancing lebih pintar.
DNS Internal di Docker Compose #
Docker Compose secara otomatis mengaktifkan DNS internal berbasis service name. Setiap service otomatis ter-resolve.
version: "3.9"
services:
web:
image: nginx
api:
image: my-api
environment:
DATABASE_URL: postgres://user:pass@db:5432/mydb
REDIS_URL: redis://cache:6379
db:
image: postgres
environment:
POSTGRES_PASSWORD: pass
cache:
image: redis
api bisa akses db dengan db:5432, dan cache dengan cache:6379 — tanpa konfigurasi tambahan. Compose otomatis:
- Membuat satu network default untuk project.
- Meng-connect-kan semua service.
- Mengaktifkan DNS internal.
Alias Tambahan dengan aliases
#
services:
db:
image: postgres
networks:
default:
aliases:
- database
- postgres-db
- primary-db
Sekarang db bisa dipanggil dengan: db, database, postgres-db, atau primary-db. Berguna untuk:
- Migrasi — service lama pakai nama
database, service baru pakaidb. Pakai alias agar kompatibel. - Abstraksi — kode aplikasi pakai
db(generic), tapi sebenarnya underlying service bisa diganti. - Multiple environment —
dev-dbdi development,prod-dbdi production.
External DNS Resolution #
DNS internal Docker juga meneruskan query untuk domain eksternal (public) ke upstream DNS. Kamu bisa set custom DNS server untuk semua container.
services:
app:
image: my-app
dns:
- 1.1.1.1
- 8.8.8.8
dns_search:
- example.com
- internal.local
Atau set di level daemon (semua container):
// /etc/docker/daemon.json
{
"dns": ["1.1.1.1", "8.8.8.8"],
"dns-search": ["example.com"]
}
sudo systemctl restart docker
Hati-hati: kalau kamu set custom DNS di daemon dan lupa restart Docker, container baru akan tetap pakai setting lama. Restart daemon setiap kali ubah daemon.json.
Verifikasi DNS Internal #
Cara paling efektif memastikan DNS internal aktif:
# 1. Cek resolv.conf
docker exec <container> cat /etc/resolv.conf
# Harus ada nameserver 127.0.0.11
# 2. Cek hostname resolution
docker exec <container> nslookup <target-container>
# atau
docker exec <container> getent hosts <target-container>
# 3. Test connectivity via hostname
docker exec <container> ping -c 1 <target-container>
docker exec <container> wget -qO- http://<target-service>:8080
# 4. Lihat network container
docker inspect <container> --format '{{json .NetworkSettings.Networks}}'
Troubleshooting DNS Gagal #
1. “Could not resolve host” #
Penyebab umum:
- Container di default bridge.
- Container di network berbeda.
- Typo di nama.
# Debug: cek network container
docker inspect <container> | grep -A 5 NetworkSettings
# Pastikan ada di network yang sama
docker network connect app-net <container>
2. DNS Sangat Lambat #
Penyebab umum:
- Forward ke external DNS yang lambat.
ndotssetting yang membuat query berulang.
# Cek query time
docker exec <container> dig +stats <hostname>
# Lihat "Query time"
# Set DNS yang lebih cepat
docker run --dns 1.1.1.1 --dns 8.8.8.8 my-app
3. Resolve间歇性 Gagal #
Penyebab umum:
- Container restart dengan IP baru.
- Network overlay (Swarm) dengan quorum issue.
- DNS cache di aplikasi (Java DNS cache terkenal stubborn).
# Test resolve berkali-kali
docker exec <container> sh -c 'for i in 1 2 3 4 5; do nslookup db; done'
DNS Cache di Aplikasi #
Beberapa aplikasi dan runtime punya DNS cache internal yang menyimpan hasil query terlalu lama. Ini bisa menyebabkan masalah saat container restart dengan IP baru.
| Runtime | Default TTL | Catatan |
|---|---|---|
| Go | 30 detik (default) | Cukup cepat |
| Java | 30+ detik (cache forever until JVM restart) | ⚠️ Masalah umum |
| Node.js | 0 (no cache by default) | Bagus |
| Python | Library-dependent | Bervariasi |
| PHP-FPM | 60 detik (PHP bawaan) | Cukup |
Java DNS cache adalah jebakan terkenal: JVM menyimpan DNS result selamanya (atau sampai TTL setting diubah). Untuk containerized Java apps, set -Dsun.net.inetaddr.ttl=30 atau pakai library DNS resolver lain (dnsjava). Tanpa ini, restart container bisa membuat app stuck ke IP lama.
Best Practice DNS Internal #
1. Selalu Pakai User-Defined Network #
docker network create app-net
docker run --network app-net my-service
Tanpa user-defined network, DNS internal tidak aktif.
2. Gunakan Service Name (Compose), Bukan Container Name #
# ✓ Solusi: service name stabil
services:
api:
image: my-api
environment:
DATABASE_HOST: db # service name, stabil
# ✗ Anti-pattern: container name rapuh
services:
db:
container_name: my-database # tidak bisa di-scale
image: postgres
3. Jangan Hardcode IP #
# ✗ Anti-pattern
DATABASE_HOST=172.18.0.3 # bisa berubah
# ✓ Solusi
DATABASE_HOST=db # DNS resolve
4. Set DNS yang Konsisten #
// /etc/docker/daemon.json
{
"dns": ["1.1.1.1", "8.8.8.8"]
}
DNS eksternal yang konsisten membantu reproducibility.
5. Test DNS Resolution di CI/CD #
# Health check yang verify DNS
docker run --rm --network app-net my-app \
sh -c "getent hosts db && getent hosts cache"
DNS Internal di Swarm dan Kubernetes #
Docker Swarm memiliki DNS service sendiri yang lebih canggih — Swarm Mode DNS. Service yang dideploy di Swarm otomatis ter-resolve dan di-load-balance.
Kubernetes punya CoreDNS yang berjalan sebagai pod di cluster. Service name ter-resolve via Service object. Lebih advanced dari Docker DNS — ada health check, weighted load balancing, dan integration dengan service mesh.
flowchart TB
subgraph Docker["Docker / Compose"]
D1[127.0.0.11]
end
subgraph Swarm["Docker Swarm"]
S1[Swarm DNS<br/>tasks.service_name]
end
subgraph K8s["Kubernetes"]
K1[CoreDNS<br/>service.namespace.svc.cluster.local]
end
Docker --> Swarm --> K8s
Konsep yang sama, implementasi yang berbeda. Untuk development, Docker DNS cukup. Untuk production multi-host, Swarm atau K8s memberikan fitur lebih.
DNS Internal vs Service Discovery Tools #
| Aspek | Docker DNS | Consul | etcd | K8s CoreDNS |
|---|---|---|---|---|
| Built-in | ✅ | ❌ | ❌ | ✅ (default) |
| Multi-host | ❌ (kecuali Swarm) | ✅ | ✅ | ✅ |
| Health check | ❌ | ✅ | ❌ (butuh library) | ✅ |
| Load balancing | Round-robin basic | ✅ | ❌ | ✅ |
| Setup complexity | Nol | Tinggi | Tinggi | Sedang |
| Cocok untuk | Single-host Compose | Multi-host tradisional | Multi-host K8s pra-era | Kubernetes |
Untuk kebanyakan kasus, Docker DNS cukup. Ia gratis, otomatis, dan zero-config. Baru pertimbangkan Consul/etcd/CoreDNS saat kamu butuh health check based routing, multi-host, atau service mesh integration.
Ringkasan #
- DNS internal Docker adalah server DNS embedded di Docker Engine, diakses lewat
127.0.0.11. Resolve container name dan service name di user-defined network.- Resolver otomatis — container punya
127.0.0.11di/etc/resolv.conftanpa konfigurasi manual.- Hanya aktif di user-defined network. Default bridge TIDAK punya DNS internal — ini jebakan paling umum.
- Round-robin — multi-container dengan alias yang sama akan return semua IP, klien implementasi load balancing.
- External query diteruskan ke upstream DNS (default: dari host). Bisa di-override per-container atau di level daemon.
- Docker Compose otomatis mengaktifkan DNS internal berbasis service name. Tiap service bisa diakses via nama service-nya.
- Aliases di Compose memungkinkan satu service punya banyak nama (untuk kompatibilitas, abstraksi, multiple environment).
- Anti-pattern: pakai default bridge, hardcode IP, pakai
container_namedi Compose, pakai--link(deprecated).- Troubleshooting: cek
/etc/resolv.conf,nslookup,getent hosts, dan pastikan container di network yang sama.- Java DNS cache adalah jebakan terkenal — set TTL rendah untuk containerized Java apps.
- Best practice: selalu user-defined network, pakai service name (bukan container_name), jangan hardcode IP, test DNS resolution di CI/CD.
- Untuk multi-host production, pertimbangkan Swarm (built-in) atau K8s (CoreDNS). Docker DNS cukup untuk single-host Compose.
- DNS internal bukan service discovery global. Untuk health check based routing, multi-DC, dan advanced use case, butuh Consul, etcd, atau service mesh.
← Sebelumnya: Port Mapping & Exposure Berikutnya: Container-to-Container →