Build CoreOrdered learning track

Docker Networking Single Host

Learn Docker, Containerization, Docker Compose, Docker Swarm - Part 011

Docker networking single-host: bridge, host, none, macvlan, ipvlan, DNS, port publishing, localhost trap, service discovery, firewall/NAT, troubleshooting, dan network failure modeling.

17 min read3370 words
PrevNext
Lesson 1135 lesson track0719 Build Core
#docker#containerization#networking#bridge-network+6 more

Part 011 — Docker Networking: Bridge, Host, None, Macvlan, DNS, and Ports

1. Tujuan Part Ini

Part sebelumnya membahas resource management: CPU, memory, IO, PID, OOM, dan backpressure. Sekarang kita masuk ke salah satu boundary container yang paling sering disalahpahami: networking.

Docker networking sering terlihat sederhana karena command seperti ini tampak mudah:

 docker run -p 8080:8080 my-api

Tetapi di balik satu flag itu ada beberapa konsep:

  • network namespace;
  • virtual Ethernet pair;
  • Linux bridge;
  • NAT;
  • iptables/nftables rules;
  • port publishing;
  • embedded DNS;
  • hostname dan container name;
  • host interface binding;
  • route table;
  • service discovery;
  • resolver behavior;
  • firewall interaction;
  • Docker Desktop VM boundary.

Target setelah part ini:

  • memahami container networking sebagai kombinasi namespace + virtual interface + routing + DNS + port mapping;
  • bisa membedakan bridge, host, none, macvlan, dan ipvlan;
  • memahami default bridge vs user-defined bridge;
  • memahami kenapa localhost sering salah dipakai;
  • bisa mendesain network Compose dengan service discovery yang bersih;
  • bisa membaca network topology dari docker network inspect;
  • bisa debug connectivity menggunakan layer-by-layer method;
  • bisa mengenali failure mode: DNS stale, port conflict, bind address salah, hairpin NAT, firewall, MTU, proxy, IPv6, dan container-to-host access;
  • bisa membuat network contract untuk aplikasi multi-service.

Inti part ini: container networking bukan magic. Container adalah process dengan network namespace sendiri. Docker menghubungkan namespace itu ke host dan container lain melalui driver network, DNS, NAT, dan routing policy.


2. Kaufman Deconstruction: Subskill Networking yang Harus Dikuasai

Agar belajar efektif, jangan mulai dari menghafal semua driver. Pecah skill Docker networking menjadi subskill kecil:

SubskillPertanyaan yang Harus Bisa DijawabBukti Penguasaan
Namespace modelContainer melihat network stack yang mana?Bisa menjelaskan IP, interface, route dari dalam container
Driver selectionKapan pakai bridge, host, none, macvlan?Bisa memilih driver berdasarkan constraint, bukan kebiasaan
Port publishingApa beda container port, host port, exposed port?Bisa memprediksi request masuk akan sampai ke process mana
Service discoveryBagaimana container menemukan container lain?Bisa menggunakan service name, network alias, dan DNS dengan benar
Localhost semanticslocalhost menunjuk ke siapa?Tidak salah menghubungkan app container ke DB host/container
Debug flowDi layer mana koneksi gagal?Bisa debug dari process, port, DNS, route, firewall, NAT
Security boundaryNetwork mana yang boleh saling bicara?Bisa memisahkan frontend/backend/admin network
Production boundaryApa yang berubah di Swarm/Kubernetes?Bisa menjelaskan bridge single-host vs overlay multi-host

Skill goal untuk part ini bukan “tahu semua flag”, tetapi bisa menggambar traffic path.


3. Mental Model: Container Memiliki Network Stack Sendiri

Secara default, container tidak memakai network namespace host. Ia memiliki network stack sendiri:

  • interface sendiri, misalnya eth0;
  • IP address sendiri;
  • route table sendiri;
  • DNS resolver config sendiri;
  • port binding sendiri di namespace-nya;
  • loopback sendiri (127.0.0.1).

Diagram:

Konsekuensi penting:

  • localhost di container berarti container itu sendiri, bukan host;
  • port 8080 di container tidak otomatis terlihat dari host;
  • dua container di network yang sama bisa komunikasi lewat IP atau DNS name;
  • port publishing diperlukan untuk traffic dari luar host menuju container;
  • user-defined bridge memberikan DNS service discovery yang lebih baik daripada default bridge lama;
  • network boundary adalah bagian dari security design.

4. Docker Network Object Model

Docker memiliki object bernama network. Container dapat di-attach ke satu atau lebih network.

Command dasar:

 docker network ls
 docker network inspect bridge
 docker network create app-net
 docker network rm app-net

Object network berisi:

  • driver;
  • subnet;
  • gateway;
  • IPAM config;
  • connected containers;
  • aliases;
  • labels;
  • options driver;
  • internal/external flag;
  • scope (local atau swarm).

Contoh inspect:

 docker network inspect app-net

Yang perlu dibaca:

{
  "Name": "app-net",
  "Driver": "bridge",
  "Scope": "local",
  "IPAM": {
    "Config": [
      {
        "Subnet": "172.20.0.0/16",
        "Gateway": "172.20.0.1"
      }
    ]
  },
  "Containers": {
    "...": {
      "Name": "api",
      "IPv4Address": "172.20.0.2/16"
    }
  }
}

Mental model:

Container bukan “berada di Docker” secara abstrak. Ia memiliki endpoint pada network tertentu.


5. Network Driver Overview

Docker Engine menyediakan beberapa network driver umum:

DriverScope UmumKapan DigunakanRisiko / Trade-off
bridgeSingle-hostDefault untuk container biasa dan Compose lokalNAT/port publishing perlu dipahami
hostSingle-hostPerformance/low-latency, service yang butuh host network langsungMenghilangkan network isolation
noneSingle-hostJob yang tidak boleh network accessTidak ada external connectivity
overlayMulti-host SwarmService antar-node di SwarmDibahas detail di Part 027
macvlanLAN-likeContainer perlu tampak seperti device fisik di networkNetwork ops lebih kompleks; host-container comm punya nuance
ipvlanVLAN/L3 integrationIntegrasi network enterprise/segmentedButuh pemahaman routing/VLAN lebih matang

Untuk single-host, mayoritas kasus production/development memakai user-defined bridge.


6. Bridge Network: Default Workhorse

Bridge network menggunakan software bridge di host. Container yang terhubung ke bridge yang sama dapat saling berkomunikasi, sementara container di bridge berbeda terisolasi kecuali ada port publishing atau routing tambahan.

6.1 Default Bridge vs User-Defined Bridge

Docker punya network bawaan bernama bridge. Tetapi untuk aplikasi nyata, lebih baik membuat user-defined bridge:

 docker network create app-net
 docker run -d --name db --network app-net postgres:16
 docker run -d --name api --network app-net my-api:1.0

Kenapa user-defined bridge lebih baik?

AspekDefault bridgeUser-defined bridge
DNS by container nameTerbatas/legacy behaviorYa, automatic service discovery
Isolation antar aplikasiLemah jika semua memakai default bridgeLebih bersih per app/project
Attach/detach containerKurang fleksibelBisa connect/disconnect live
Config subnet/optionsGlobal defaultPer network
Operational claritySemua bercampurNetwork per aplikasi

Prinsip: jangan pakai default bridge untuk aplikasi multi-container yang serius. Buat network eksplisit.

6.2 Bridge Traffic Path: Container ke Container

Jika api memanggil db pada network yang sama:

 docker exec api curl http://db:5432

Path mental:

Tidak perlu publish port DB ke host untuk API container mengakses DB. Publish port hanya untuk akses dari luar network container.

6.3 Bridge Traffic Path: Host ke Container

Jika host memanggil localhost:8080 dan container di-publish:

 docker run -p 8080:8080 my-api
 curl http://localhost:8080

Path mental:

Port publishing bukan mengubah container agar memakai host port. Ia membuat host menerima traffic lalu meneruskannya ke container endpoint.


7. Port Publishing: Host Port, Container Port, Bind Address

Flag umum:

 docker run -p 8080:80 nginx

Artinya:

  • host menerima traffic di port 8080;
  • Docker meneruskan ke container port 80;
  • process di container harus benar-benar listen di port 80;
  • by default binding dapat terbuka pada semua interface host, tergantung konfigurasi dan platform.

Format eksplisit:

 docker run -p 127.0.0.1:8080:80 nginx
 docker run -p 0.0.0.0:8080:80 nginx
 docker run -p 192.168.1.10:8080:80 nginx
FormatMakna
-p 8080:80Publish container port 80 ke host port 8080
-p 127.0.0.1:8080:80Hanya listen di loopback host
-p 0.0.0.0:8080:80Listen di semua IPv4 interface host
-p 8080Pilih random host port untuk container exposed port
-PPublish semua exposed ports ke random host ports

7.1 EXPOSE Bukan Publish

Dockerfile:

EXPOSE 8080

EXPOSE adalah metadata/documentation. Ia tidak otomatis membuka port ke host.

Untuk akses host:

 docker run -p 8080:8080 my-api

7.2 Kesalahan Umum: App Listen di 127.0.0.1

Di dalam container, aplikasi harus listen pada interface yang dapat dicapai dari network container. Banyak framework default listen di 127.0.0.1, yang berarti hanya loopback container.

Buruk:

 node server.js --host 127.0.0.1 --port 8080

Lebih benar untuk container:

 node server.js --host 0.0.0.0 --port 8080

Kenapa?

  • 127.0.0.1 di container hanya bisa diakses dari container itu sendiri;
  • Docker port publishing meneruskan traffic ke container IP, bukan ke loopback-only listener;
  • process harus bind ke 0.0.0.0 atau container interface.

Debug:

 docker exec api ss -ltnp

Cari apakah service listen pada:

127.0.0.1:8080   # suspicious for published service
0.0.0.0:8080     # usually expected
:::8080          # IPv6/all interface depending app

8. The Localhost Trap

Ini salah satu konsep paling penting.

8.1 Dari Container ke Container

Jika api dan db berada dalam network Compose yang sama:

api -> db:5432

Bukan:

api -> localhost:5432

Karena localhost dari api berarti api sendiri.

8.2 Dari Host ke Container

Host mengakses container lewat published port:

host -> localhost:8080 -> api:8080

8.3 Dari Container ke Host

Di Docker Desktop, ada special DNS name umum:

host.docker.internal

Di Linux Engine native, behavior bisa berbeda. Untuk Linux modern, sering digunakan host gateway mapping:

 docker run --add-host=host.docker.internal:host-gateway my-app

atau Compose:

services:
  api:
    extra_hosts:
      - "host.docker.internal:host-gateway"

Namun desain yang lebih baik: jangan membuat container terlalu bergantung pada service di host kecuali memang untuk development. Untuk production-like local environment, jalankan dependency sebagai container juga.

Diagram localhost semantics:

Rule of thumb:

  • from host to container: use localhost:<published-host-port>;
  • from container to sibling container: use <service-name>:<container-port>;
  • from container to host: use explicit host gateway mechanism;
  • from container to itself: use localhost.

9. Docker DNS and Service Discovery

User-defined Docker networks provide embedded DNS service. Container dapat resolve container lain menggunakan name/alias.

Contoh:

 docker network create app-net
 docker run -d --name postgres --network app-net postgres:16
 docker run --rm --network app-net alpine getent hosts postgres

Compose default behavior:

services:
  api:
    build: .
  db:
    image: postgres:16

Compose membuat network default untuk project. Container service api bisa resolve db.

postgres://db:5432/app

Bukan:

postgres://localhost:5432/app

9.1 Service Name vs Container Name

Di Compose, gunakan service name sebagai stable DNS name.

Baik:

http://catalog-api:8080

Kurang baik:

container_name: catalog-api

container_name sering mengganggu scaling karena nama container harus unik. Gunakan service name dan network alias bila perlu.

9.2 Network Alias

services:
  api:
    image: my-api
    networks:
      backend:
        aliases:
          - internal-api

networks:
  backend:

Gunakan alias untuk compatibility, bukan untuk menyembunyikan model service yang buruk.

9.3 DNS TTL and Connection Reuse

Aplikasi sering cache DNS atau connection pool. Saat container diganti, DNS bisa berubah tetapi connection lama masih menunjuk endpoint lama.

Failure mode:

  • service restart;
  • IP container berubah;
  • client tetap memakai connection lama;
  • request gagal sampai pool refresh.

Solusi:

  • implement retry dengan backoff;
  • gunakan connection pool health validation;
  • jangan hardcode container IP;
  • gunakan service name;
  • desain aplikasi tahan terhadap reconnect.

10. Host Network Driver

host network driver menghilangkan network namespace isolation. Container memakai network stack host.

 docker run --network host my-api

Konsekuensi:

  • process container listen langsung di host port;
  • tidak perlu -p;
  • port conflict langsung dengan host process;
  • localhost di container adalah localhost host;
  • isolation berkurang;
  • cocok untuk use case tertentu, bukan default.

Kapan masuk akal:

  • low-latency network path;
  • agent yang harus melihat network host;
  • local diagnostic tools;
  • service discovery/monitoring tertentu;
  • development khusus.

Kapan sebaiknya dihindari:

  • multi-service app biasa;
  • environment yang butuh network isolation;
  • ketika port binding harus eksplisit;
  • ketika security boundary penting;
  • saat ingin portability ke Compose/Swarm/Kubernetes.

Diagram:

Decision heuristic:

Use host network only when you can explain exactly which isolation you are giving up and why the performance/visibility benefit is worth it.


11. None Network Driver

none membuat container hanya punya loopback. Tidak ada external network.

 docker run --network none alpine ip addr

Kapan digunakan:

  • offline batch job;
  • cryptographic processing yang tidak butuh network;
  • malware/sample analysis sandbox tambahan;
  • test yang ingin memastikan tidak ada outbound call;
  • build or transform job dengan input/output via volume.

Contoh:

 docker run --rm \
   --network none \
   -v "$PWD/input:/input:ro" \
   -v "$PWD/output:/output" \
   my-transformer:1.0

Security benefit:

  • tidak bisa call external API;
  • tidak bisa exfiltrate lewat network biasa;
  • dependency harus eksplisit lewat file/volume.

Namun jangan menganggap none sebagai sandbox sempurna. Masih ada boundary lain: filesystem, capability, seccomp, user, resource, dan host mounts.


12. Macvlan and Ipvlan

macvlan membuat container terlihat seperti device tersendiri di network fisik. Container mendapat MAC address sendiri.

Kapan digunakan:

  • legacy app butuh L2 adjacency;
  • monitoring network appliance;
  • DHCP/static IP integration;
  • service harus muncul sebagai host terpisah di LAN;
  • network policy enterprise mengharuskan identitas IP/MAC khusus.

Contoh konseptual:

 docker network create -d macvlan \
   --subnet=192.168.1.0/24 \
   --gateway=192.168.1.1 \
   -o parent=eth0 lan-net

 docker run --rm --network lan-net alpine ip addr

Trade-off:

  • butuh koordinasi dengan network team;
  • switch port/security policy bisa membatasi multiple MAC;
  • host-to-container communication punya nuance;
  • observability/NAT behavior berbeda dari bridge;
  • tidak cocok untuk default local dev.

ipvlan mirip dalam tujuan integrasi network eksternal, tetapi dengan behavior L2/L3 yang berbeda. Pakai hanya bila model routing/VLAN dipahami.

Prinsip: macvlan/ipvlan adalah network architecture decision, bukan sekadar Docker flag.


13. Compose Networking Model Preview

Compose secara default membuat satu network per project.

services:
  api:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

# Compose implicitly creates: <project>_default

api dapat mengakses db:5432.

Lebih eksplisit:

services:
  reverse-proxy:
    image: nginx:alpine
    ports:
      - "8080:80"
    networks:
      - public
      - backend

  api:
    build: ./api
    networks:
      - backend
      - data

  db:
    image: postgres:16
    networks:
      - data

networks:
  public:
  backend:
  data:
    internal: true

Diagram:

Design rule:

  • expose hanya edge service;
  • internal service tidak perlu publish port;
  • DB tidak perlu reachable dari host kecuali untuk dev/admin;
  • pisahkan public/backend/data network bila boundary penting;
  • gunakan service name, bukan IP.

14. Network Security Boundary

Docker network bukan firewall enterprise lengkap, tapi ia memberi isolation boundary penting.

14.1 Jangan Publish Port yang Tidak Perlu

Buruk:

services:
  db:
    image: postgres:16
    ports:
      - "5432:5432"

Jika hanya api yang perlu akses DB, cukup:

services:
  db:
    image: postgres:16
    networks:
      - data

Publish port DB hanya bila host benar-benar butuh akses. Untuk development, boleh tetapi bind ke loopback:

ports:
  - "127.0.0.1:5432:5432"

14.2 Bind Address Matters

BindReachability
127.0.0.1:8080:8080Hanya host lokal
0.0.0.0:8080:8080Semua interface host
192.168.1.10:8080:8080Interface tertentu

Kesalahan bind address bisa mengubah service lokal menjadi service LAN/public.

14.3 Internal Network

Compose mendukung network internal:

networks:
  data:
    internal: true

Gunakan untuk network yang tidak perlu outbound external secara langsung. Tetapi tetap validasi behavior sesuai platform dan kebutuhan, karena DNS/proxy/routing bisa memiliki nuance.


15. Firewall, NAT, and Host Policy

Docker dapat memanipulasi firewall rules host untuk network dan port publishing. Di Linux, ini biasanya berhubungan dengan iptables/nftables.

Hal yang sering terjadi:

  • port sudah published tetapi firewall host memblokir;
  • corporate endpoint security mengubah packet filtering;
  • distro firewall (ufw, firewalld) punya interaksi tidak intuitif;
  • rules manual hilang setelah Docker restart;
  • Docker Desktop menambahkan VM/network layer tambahan.

Debug layer:

 docker ps
 docker port api
 docker inspect api
 ss -ltnp
 sudo iptables -S
 sudo nft list ruleset

Production heuristic:

  • jangan mengandalkan “default Docker opened it” sebagai security policy;
  • documented firewall policy tetap harus eksplisit;
  • bind sensitive local port ke 127.0.0.1;
  • audit published ports dalam CI/lint Compose;
  • monitor exposed host ports.

16. IPv4, IPv6, MTU, and Proxy Nuance

16.1 IPv4 Assumption

Banyak tutorial Docker mengasumsikan IPv4 private subnet. Dalam environment modern, IPv6 bisa relevan. Pastikan aplikasi dan dependency tidak diam-diam gagal karena resolver mengembalikan IPv6 dulu.

Debug:

 getent hosts service-name
 curl -4 http://service-name:8080
 curl -6 http://service-name:8080

16.2 MTU Problem

MTU mismatch bisa menyebabkan request kecil berhasil tetapi payload besar timeout/hang.

Gejala:

  • TLS handshake random fail;
  • HTTP upload/download besar gagal;
  • service antar network tertentu timeout;
  • VPN aktif memperburuk.

Debug awal:

 ip link
 docker network inspect app-net
 ping -M do -s 1472 target

16.3 Corporate Proxy

Container tidak otomatis mewarisi semua proxy host.

Yang perlu diperiksa:

  • daemon proxy untuk pull image;
  • build proxy untuk RUN apt-get/npm install;
  • runtime proxy untuk app outbound call;
  • NO_PROXY untuk internal service name seperti db, redis, .local, atau private subnet.

Kesalahan NO_PROXY sering membuat container mencoba mengakses internal service lewat corporate proxy.


17. Debugging Connectivity: Layer-by-Layer Method

Jangan debug networking secara acak. Gunakan urutan.

17.1 Pertanyaan 1 — Process Listen?

 docker exec api ss -ltnp

Validasi:

  • port benar;
  • protocol benar TCP/UDP;
  • bind address benar (0.0.0.0 vs 127.0.0.1);
  • process masih hidup.

17.2 Pertanyaan 2 — Container Punya IP dan Route?

 docker exec api ip addr
 docker exec api ip route

Validasi:

  • interface eth0 ada;
  • IP sesuai network;
  • default route ada jika butuh outbound.

17.3 Pertanyaan 3 — DNS Resolve?

 docker exec api getent hosts db
 docker exec api nslookup db

Validasi:

  • service name benar;
  • container berada di network yang sama;
  • tidak memakai container_name yang mengacaukan assumption;
  • resolver config benar.

17.4 Pertanyaan 4 — TCP Reachable?

 docker exec api nc -vz db 5432
 docker exec api curl -v http://web:8080/health

Validasi:

  • packet sampai;
  • service menerima;
  • firewall internal tidak memblokir;
  • protocol tidak salah.

17.5 Pertanyaan 5 — Host Port Published?

 docker ps
 docker port api
 ss -ltnp | grep 8080
 curl -v http://localhost:8080/health

Validasi:

  • host port benar;
  • bind address benar;
  • tidak conflict;
  • process dalam container listen pada container port yang benar.

17.6 Pertanyaan 6 — Network Object Benar?

 docker network ls
 docker network inspect app-net

Validasi:

  • kedua container ada di network yang sama;
  • subnet tidak overlap dengan VPN/corporate network;
  • alias benar;
  • internal flag sesuai.

Debug flow:


18. Common Failure Modes and Fixes

18.1 Connection refused from Host

Meaning: target reachable, no process accepting on that port, or NAT goes to port with no listener.

Check:

 docker ps
 docker port api
 docker exec api ss -ltnp

Likely causes:

  • app crashed;
  • app listens on wrong port;
  • app binds to 127.0.0.1 inside container;
  • host port maps to wrong container port.

18.2 Connection timed out

Meaning: packet not reaching target or response not coming back.

Likely causes:

  • firewall;
  • wrong IP/host;
  • route issue;
  • network not shared;
  • external service blocked;
  • MTU/VPN issue.

18.3 Name or service not known

Likely causes:

  • wrong service name;
  • containers not on same user-defined network;
  • using default bridge without proper DNS behavior;
  • app using custom DNS/resolver incorrectly;
  • Compose project/network mismatch.

18.4 Works from Host, Fails from Container

Likely causes:

  • using localhost inside container;
  • proxy missing;
  • DNS difference;
  • outbound firewall;
  • host service only binds to 127.0.0.1 and container cannot reach it through host gateway;
  • Docker Desktop VM boundary.

18.5 Works in Compose, Fails in CI

Likely causes:

  • CI uses different project name;
  • port conflict on shared runner;
  • service readiness not guaranteed;
  • DNS name depends on container_name;
  • network cleanup stale;
  • test starts before dependency is ready.

19. Network Design Patterns

19.1 Edge/Internal Split

Expose only reverse proxy or API gateway.

services:
  proxy:
    image: nginx
    ports:
      - "127.0.0.1:8080:80"
    networks: [edge, app]

  api:
    image: my-api
    networks: [app, data]

  db:
    image: postgres
    networks: [data]

networks:
  edge:
  app:
  data:
    internal: true

Benefits:

  • DB not published;
  • API not directly published if proxy handles edge;
  • data network restricted;
  • topology documents intent.

19.2 Per-Bounded-Context Network

For larger local environments:

networks:
  identity:
  billing:
  case-management:
  shared-observability:

Do not put every service in one giant network unless the whole app is intentionally flat.

19.3 Admin Network

Admin tools should not be on same public path by default.

services:
  pgadmin:
    image: dpage/pgadmin4
    profiles: [admin]
    ports:
      - "127.0.0.1:5050:80"
    networks: [data]

Run only when needed:

 docker compose --profile admin up pgadmin

20. Anti-Patterns

20.1 Publishing Every Service

Bad:

services:
  api:
    ports: ["8080:8080"]
  db:
    ports: ["5432:5432"]
  redis:
    ports: ["6379:6379"]
  rabbitmq:
    ports: ["5672:5672"]

Better:

  • publish only what host needs;
  • bind admin/dev ports to 127.0.0.1;
  • internal dependencies use service discovery.

20.2 Hardcoding Container IP

Bad:

DB_HOST=172.20.0.3

Good:

DB_HOST=db

Container IP can change. Service name is the contract.

20.3 Using container_name Everywhere

Bad:

services:
  api:
    container_name: api

Problems:

  • prevents scaling;
  • creates global name conflicts;
  • makes project isolation harder;
  • hides Compose service model.

Use service name. Use alias only when necessary.

20.4 Using Host Network to Avoid Learning Networking

Bad reasoning:

“Bridge networking is confusing, so use --network host.”

This trades confusion for weaker isolation and less portability.

Use host network only when the requirement demands it.

20.5 Relying on Startup Order as Readiness

Network path existing does not mean dependency is ready.

depends_on order is not enough unless paired with health semantics where supported. This will be covered deeply in Compose parts.


21. Practice Lab

Lab 1 — Bridge Service Discovery

Create network:

 docker network create lab-net

Run Nginx:

 docker run -d --name web --network lab-net nginx:alpine

Resolve and call it:

 docker run --rm --network lab-net alpine sh -c \
   "apk add --no-cache curl >/dev/null && getent hosts web && curl -I http://web"

Observe:

 docker network inspect lab-net

Questions:

  • What IP does web have?
  • Where does DNS name come from?
  • Is port 80 published to host?
  • Can host call http://localhost:80?

Lab 2 — Port Publishing

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

Questions:

  • What is host port?
  • What is container port?
  • Why does EXPOSE 80 alone not publish?

Lab 3 — Localhost Trap

Run DB:

 docker network create trap-net
 docker run -d --name db --network trap-net postgres:16 \
   -e POSTGRES_PASSWORD=example

From another container:

 docker run --rm --network trap-net postgres:16 \
   psql postgresql://postgres:example@db:5432/postgres -c 'select 1'

Try wrong host:

 docker run --rm --network trap-net postgres:16 \
   psql postgresql://postgres:example@localhost:5432/postgres -c 'select 1'

Explain why it fails.

Lab 4 — None Network

 docker run --rm --network none alpine ip addr
 docker run --rm --network none alpine ping -c 1 8.8.8.8

Questions:

  • Which interface exists?
  • What failure do you see?
  • When is this useful?

Lab 5 — Inspect a Compose Network

Create compose.yaml:

services:
  api:
    image: nginx:alpine
    ports:
      - "127.0.0.1:8081:80"
  client:
    image: alpine
    command: sleep infinity

Run:

 docker compose up -d
 docker compose exec client wget -qO- http://api
 docker network ls
 docker network inspect $(basename "$PWD")_default

Questions:

  • What network did Compose create?
  • How did client resolve api?
  • Why does host use localhost:8081 but client uses api:80?

Cleanup:

 docker compose down
 docker network rm lab-net trap-net || true
 docker rm -f web web-published db || true

22. Review Checklist

Untuk setiap Dockerized application, tanyakan:

  • service mana yang benar-benar perlu publish port ke host?
  • published port bind ke 127.0.0.1 atau semua interface?
  • dependency internal memakai service name, bukan IP?
  • ada container yang memakai localhost untuk dependency lain?
  • ada network yang terlalu flat?
  • DB/cache/message broker terekspos tanpa alasan?
  • user-defined bridge dipakai untuk app multi-container?
  • container_name dipakai tanpa alasan kuat?
  • ada subnet conflict dengan VPN/corporate network?
  • ada proxy/NO_PROXY requirement?
  • health/readiness dipisahkan dari network reachability?
  • debug tools tersedia untuk minimal image?

23. Key Takeaways

  • Container memiliki network namespace sendiri; localhost di container bukan host.
  • User-defined bridge adalah default terbaik untuk single-host multi-container app.
  • Port publishing menghubungkan host port ke container port; EXPOSE hanya metadata.
  • Internal container-to-container traffic sebaiknya memakai service name dan container port.
  • Jangan publish dependency internal tanpa alasan.
  • Host network mengorbankan isolation; gunakan hanya bila benar-benar perlu.
  • none berguna untuk workload offline atau restricted.
  • Macvlan/ipvlan adalah keputusan arsitektur jaringan, bukan default development shortcut.
  • Debug networking harus layer-by-layer: process, port, DNS, route, TCP, firewall, protocol.
  • Network design yang baik membuat dependency graph terlihat jelas dan mengurangi blast radius.

24. Transisi ke Part 012

Networking menjawab bagaimana container saling bicara. Part berikutnya membahas boundary yang sama pentingnya: storage.

Kita akan masuk ke:

  • writable layer;
  • copy-on-write;
  • volumes;
  • bind mounts;
  • tmpfs;
  • permission/ownership;
  • backup/restore;
  • storage driver mental model;
  • stateful container pitfalls.

Jika networking salah, service tidak bisa berkomunikasi. Jika storage salah, data bisa hilang, corrupt, bocor ke host, atau membuat environment tidak reproducible.

Lesson Recap

You just completed lesson 11 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.