Skip to content

บทที่ 02 — Docker Networking: Container คุยกันยังไง

← บทที่ 01 | สารบัญ | บทที่ 03: Volumes →

container แต่ละตัวแยกตัวกัน (จาก network namespace ในบท 00) — แล้วมันคุยกันได้ยังไง? เว็บที่รันใน container เปิดให้คนข้างนอกเข้าได้ยังไง? บทนี้ตอบคำถามเหล่านี้แบบละเอียด

อ่านจบจะ:

  • เข้าใจว่า port mapping (-p 8080:80) ทำงานยังไงจริง ๆ
  • ทำให้ container 2 ตัวคุยกันได้ (เช่น แอป ↔ database)
  • เข้าใจ network แต่ละชนิด (bridge, host, none, overlay) — ใช้ตอนไหน
  • รู้ว่าทำไม container ใน network เดียวกันเรียกชื่อกันได้

ใช้เวลา 2-3 ชั่วโมง

📚 ไม่ต้องอ่านรวดเดียวจบ — แบ่งอ่านได้ ลองรันคำสั่งทดลองตามไปด้วยจะเห็นภาพชัดกว่าอ่านอย่างเดียว


Part 1: ปัญหาที่ต้องแก้

ลองนึกภาพแอปจริง — มันไม่ได้มี container เดียว:

[เว็บแอป container]  ──ต้องคุยกับ──→  [database container]
                     ──ต้องคุยกับ──→  [redis cache container]

และคนข้างนอก (ผู้ใช้ผ่านเบราว์เซอร์) ต้องเข้าถึง "เว็บแอป container" ได้

แต่จากบท 00 — แต่ละ container มี network namespace ของตัวเอง = มี network card เสมือน, IP ของตัวเอง, แยกขาดจากกัน

คำถามคือ: แล้วมันจะคุยกันได้ยังไง? — คำตอบคือ Docker Network


Part 2: Network คืออะไรในโลก Docker

Docker จัดการเรื่อง network ผ่านสิ่งที่เรียกว่า "network" — เป็นเหมือน "วง LAN เสมือน" ที่ container เข้าร่วมได้

หลักการง่าย ๆ:

  • container ที่อยู่ใน network เดียวกัน → คุยกันได้
  • container ที่อยู่ คนละ network → คุยกันไม่ได้ (ถูกกั้น)

ดู network ที่มีในเครื่อง:

bash
docker network ls

จะเห็นประมาณ:

NETWORK ID     NAME      DRIVER    SCOPE
abc123         bridge    bridge    local
def456         host      host      local
ghi789         none      null      local

Docker สร้าง network 3 อันมาให้ตั้งแต่แรก — bridge, host, none — แต่ละอันใช้ "driver" ต่างกัน

Driver = "ชนิดของ network" — กำหนดว่า network นั้นทำงานยังไง


Part 3: Bridge Network — ชนิดที่ใช้บ่อยที่สุด

3.1 Bridge คืออะไร

bridge เป็น network driver แบบ default — เมื่อคุณ docker run โดยไม่ระบุ network → container เข้า network bridge โดยอัตโนมัติ

ลองนึกภาพ "bridge" เป็น switch (สวิตช์เครือข่าย) เสมือน ที่อยู่ในเครื่อง host

📝 switch ในที่นี้ = อุปกรณ์เชื่อมคอมหลายเครื่องในวง LAN เดียวกัน ให้ส่งข้อมูลถึงกันได้ / bridge ในโลก Docker ก็คือ switch เสมือนแบบนั้น แต่อยู่ในซอฟต์แวร์

📝 IP 172.17.0.x เหล่านี้เป็น IP ภายในเครื่อง host เท่านั้น — มองเห็นเฉพาะระหว่าง container ในเครื่องเดียวกัน เครื่องอื่นในวง LAN (เช่นโทรศัพท์เรา) ping IP เหล่านี้ไม่เจอ

container A และ B ต่อเข้า bridge เดียวกัน → คุยกันได้ผ่าน bridge นั้น (เหมือนคอม 2 เครื่องเสียบ switch ตัวเดียวกัน)

3.2 ปัญหาของ bridge แบบ default

ลองทดลอง:

📝 หมายเหตุ: ตัวอย่างในบทนี้ใช้ nginx:1.27-alpine เพื่อ pin version — ในงานจริงให้ระบุ tag ชัดเจนเสมอ ไม่ใช้ nginx:latest

bash
# หมายเหตุ: nginx ใช้ tag แบบ patch-version เช่น nginx:1.27.3-alpine
# nginx:1.27-alpine (minor เฉย ๆ) อาจไม่มีในทุก Docker registry — ถ้า pull ไม่ได้
# ให้ตรวจ tag ที่มีจริงที่ https://hub.docker.com/_/nginx/tags หรือใช้ nginx:stable-alpine แทน
docker run -d --name a nginx:1.27-alpine
docker run -d --name b nginx:1.27-alpine

# ดู IP ของ container a
docker inspect a --format '{{.NetworkSettings.IPAddress}}'
# สมมติได้ 172.17.0.2 (เลขจริงต่างกันได้)

# จาก container b ลอง ping a ด้วย IP
docker exec b ping 172.17.0.2
# ✅ ได้ — ping ผ่าน

# จาก container b ลอง ping a ด้วย "ชื่อ"
docker exec b ping a
# ❌ ไม่ได้ — "ping: bad address 'a'"

ปัญหา: bridge แบบ default ไม่มี DNScontainer เรียกกันด้วย "ชื่อ" ไม่ได้ ต้องใช้ IP

แต่ IP ของ container เปลี่ยนทุกครั้งที่ restart! → ใช้ IP ตรง ๆ ไม่ได้จริง

3.3 ทางแก้: สร้าง Custom Bridge Network เอง

bash
# สร้าง network เอง
docker network create mynet

# รัน container เข้า network นี้
docker run -d --name a --network mynet nginx:1.27-alpine
docker run -d --name b --network mynet nginx:1.27-alpine

# ทีนี้ ping ด้วยชื่อได้แล้ว!
docker exec b ping a
# ✅ ได้ — "PING a (172.x.x.x)..." (IP จริงเปลี่ยนไปตาม network ที่มีอยู่)

ความต่างสำคัญ: custom bridge network มี DNS อัตโนมัติcontainer เรียกกันด้วย "ชื่อ container" ได้เลย

ทำไมสำคัญ? — เพราะชื่อ container ไม่เปลี่ยน (ต่างจาก IP) → เราเขียนโค้ดให้แอปเรียก database ด้วยชื่อ db ได้ มั่นใจว่าใช้ได้เสมอ

💡 กฎทอง: ใน production (และ Docker Compose) — ใช้ custom bridge network เสมอ ไม่ใช้ default bridge

3.4 ตัวอย่างจริง: แอป + Database

bash
# 1. สร้าง network
docker network create app-net

# 2. รัน database — ตั้งชื่อ "db"
docker run -d --name db --network app-net \
    -e POSTGRES_USER=appuser \
    -e POSTGRES_PASSWORD=secret \
    -e POSTGRES_DB=myapp \
    postgres:16

# 3. รันแอป — เข้า network เดียวกัน
docker run -d --name webapp --network app-net \
    -e DATABASE_HOST=db \
    -e DATABASE_USER=appuser \
    -e DATABASE_PASSWORD=secret \
    -p 8080:3000 \
    myapp:v1

⚠️ Security smell: ใส่ password ผ่าน -e DATABASE_PASSWORD=secret ตรง ๆ บน command line จะโผล่ใน ps, docker inspect, history ของ shell — ตัวอย่าง demo OK แต่ใน production ใช้ Docker secrets, env file ที่ permission 600, หรือ secret manager (Vault, AWS Secrets Manager) 📝 ถ้าไม่ใส่ POSTGRES_USER Postgres จะใช้ user default ชื่อ postgres — ระบุชัดเจนดีกว่า ลดความสับสนตอน app ตั้งค่า connection

ในโค้ดของ myapp — มันจะเชื่อมต่อ database ด้วย host = db (ชื่อ container) → Docker DNS แปลง db เป็น IP จริงให้อัตโนมัติ


Part 4: Port Mapping — เปิดให้คนข้างนอกเข้า

4.1 ปัญหา

container webapp ข้างบนรัน เว็บอยู่ — แต่คนข้างนอก (เบราว์เซอร์บนเครื่องคุณ หรือผู้ใช้บน internet) ยังเข้าไม่ได้

เพราะ container อยู่ใน network เสมือน (172.x.x.x) ที่โลกภายนอกมองไม่เห็น

4.2 ทางแก้: -p (Port Mapping / Port Publishing)

bash
docker run -d -p 8080:3000 myapp:v1

-p 8080:3000 หมายความว่า:

"ใครก็ตามที่เข้ามาที่ port 8080 ของเครื่อง host — ให้ส่งต่อ (forward) ไปที่ port 3000 ของ container"

รูปแบบคือ -p [host port]:[container port]ตัวซ้ายคือเครื่องจริง ตัวขวาคือ container

4.3 รูปแบบ port mapping

bash
-p 8080:80              # host 8080 → container 80
-p 80:80                # ตรงกันก็ได้
-p 8080:80/udp          # ระบุ protocol UDP (default คือ tcp)
-p 127.0.0.1:8080:80    # bind เฉพาะ localhost — คนนอกเครื่องเข้าไม่ได้
-p 8080:80 -p 8443:443  # หลาย port
-P                      # (P ตัวใหญ่) เปิดทุก port ที่ EXPOSE ไว้ ด้วย port สุ่ม

อธิบาย -p 127.0.0.1:8080:80:

  • ปกติ -p 8080:80 = 0.0.0.0:8080:80 = ฟังทุก network interface = ใครในวง LAN ก็เข้าได้
  • ใส่ 127.0.0.1 ข้างหน้า = ฟังเฉพาะ localhost = เข้าได้แค่จากเครื่องตัวเอง — ปลอดภัยกว่าตอน dev

⚠️ Linux server + ufw/firewalld: Docker จัดการ iptables โดยตรงและ bypass ufw rules — ดังนั้น -p 8080:80 จะเปิด port ออก internet ได้แม้ ufw จะ block port นั้นอยู่ ถ้าต้องการจำกัดการเข้าถึงให้ใช้ -p 127.0.0.1:8080:80 หรือตั้ง DOCKER_OPTS เพิ่มเติม

4.4 ดู port mapping

ถ้าลืมว่า container ไหน map port อะไรไว้ ใช้ docker port ดูได้ — มันแสดงว่า port ภายใน container ถูกผูกกับ IP:port อะไรบนเครื่อง host ช่วยตรวจสอบเวลาเชื่อมต่อไม่ได้:

bash
docker port webapp
# 3000/tcp -> 0.0.0.0:8080

4.5 ⚠️ ความเข้าใจผิดที่พบบ่อย

มือใหม่มักงงว่า: "ถ้า container 2 ตัวอยู่ใน network เดียวกัน คุยกัน — ต้องใช้ -p ไหม?"

ตอบ: ไม่ต้อง!

  • -p ใช้สำหรับ "คนข้างนอก → เข้า container" เท่านั้น
  • "containercontainer" ใน network เดียวกัน — คุยกันได้เลย ไม่ต้อง -p

ตัวอย่าง: webapp คุยกับ db — ไม่ต้อง -p ที่ db. แต่ webapp ต้องการให้ผู้ใช้เข้าได้ — ต้อง -p ที่ webapp

อย่าใส่ -p ที่ database! ถ้าใส่ = เปิด database ให้คนทั้ง LAN เข้าได้ = อันตราย


Part 5: Network Driver ชนิดอื่น

5.1 Host Network

bash
docker run -d --network host nginx

host network = container ใช้ network ของเครื่อง host โดยตรง — ไม่มีการแยก network namespace

ผลคือ:

  • container ฟัง port ไหน = เครื่อง host ฟัง port นั้นเลย (ไม่ต้อง -p)
  • เร็วกว่า bridge นิดหน่อย (ไม่มีการแปลง address)
  • แต่ไม่มี isolationcontainer เห็น network เครื่องจริงทั้งหมด

ใช้เมื่อ: ต้องการ performance สูงสุด, เครื่องมือ monitoring network ไม่ใช้เมื่อ: production ทั่วไป (เสีย isolation), และ บน Mac/Windows ใช้ไม่ได้เต็มที่ (เพราะ Docker รันใน VM)

5.2 None Network

bash
docker run -d --network none alpine

none = container ไม่มี network เลย มีแค่ loopback ของตัวเอง

📝 loopback คือ network ปลอมที่ใช้คุยกับตัวเองวนกลับเข้าเครื่องเดิม (โปรแกรมในเครื่องเดียวกันคุยกันผ่านตัวนี้) ย่อชื่อว่า lo มี IP คือ 127.0.0.1 — ทุกเครื่อง (ทั้ง host และ container) มีตัวนี้ติดมาตั้งแต่แรก

💡 จำ -p 127.0.0.1:8080:80 ใน Part 4.3 ได้ไหม? — 127.0.0.1 คือ IP ของ loopback นั่นเอง = "ฟังเฉพาะ localhost"

ใช้เมื่อ: รันงาน batch ที่ไม่ต้องต่อ network เลย — เพื่อความปลอดภัยสูงสุด

5.3 Overlay Network

🚀 โซนขั้นสูง — มือใหม่ในเครื่องเดียว ข้ามทั้ง Part 5.3 ได้เลย overlay ใช้ตอนรัน container ข้ามหลายเครื่อง (cluster) — กลับมาอ่านตอนเรียน Kubernetes ก็ทัน

overlay = network ที่เชื่อม container ที่อยู่ คนละเครื่อง host ให้คุยกันได้เหมือนอยู่ network เดียว

📝 VXLAN = เทคนิค "ขุดอุโมงค์" ให้ container ที่อยู่คนละเครื่องคุยกันเหมือนอยู่ในวง LAN เดียวกัน (ย่อมาจาก Virtual Extensible LAN — LAN = Local Area Network เครือข่ายในพื้นที่เดียวกัน เช่น วง network ในออฟฟิศ) ไม่ต้องเข้าใจรายละเอียดตอนนี้

ใช้ในระบบ cluster — เดิม Docker Swarm ใช้ overlay เป็นหลัก

⚠️ 2026 status: Docker Swarm อยู่ใน maintenance mode มานานหลายปี — production cluster ปัจจุบันใช้ Kubernetes แทบทั้งหมด

K8s ใช้ CNI plugin แทน (เช่น Cilium, Calico, Flannel) — CNI บางตัวใช้ VXLAN เช่นกัน แต่เป็น implementation ของ CNI เอง ไม่ใช่ Docker overlay โดยตรง ดังนั้นแนวคิด overlay ของ Docker กับ K8s network ไม่ใช่สิ่งเดียวกัน — เรียนละเอียดในหมวด Kubernetes

ตอนนี้แค่รู้จักไว้ — บนเครื่องเดียวเราใช้ bridge ก็พอ

5.4 สรุปตาราง

Driverใช้ตอนไหน
bridge (custom)งานทั่วไป — container คุยกันในเครื่องเดียว ⭐ ใช้บ่อยสุด
hostต้องการ performance, monitoring tool — เสีย isolation
noneไม่ต้องการ network เลย
overlaycluster — container ข้ามเครื่อง (Swarm, K8s)

Part 6: DNS ใน Docker — Container เรียกชื่อกันยังไง

6.1 หลักการ

ใน custom bridge network — Docker รัน DNS server เล็ก ๆ ให้อัตโนมัติ

เมื่อ container ในนั้นเรียกชื่อ container อื่น → DNS ของ Docker แปลงชื่อเป็น IP ปัจจุบันให้

bash
docker network create shop
docker run -d --name db --network shop postgres:16
docker run -d --name api --network shop myapi

# ใน api — เรียก db ได้เลย:
docker exec api ping db
docker exec api nc -zv db 5432       # ทดสอบเชื่อม port 5432 ของ db

→ ในโค้ดของ api — ใส่ database host = "db" ได้เลย

6.2 Network Alias — ตั้งชื่อเพิ่ม

bash
docker run -d --name backend \
    --network shop \
    --network-alias api \
    --network-alias api-server \
    myapi

container นี้ชื่อจริง backend แต่ก็เรียกด้วย api หรือ api-server ได้ด้วย

ใช้ตอน: มีหลาย container ที่อยาก resolve ด้วยชื่อเดียวกัน (load balance ง่าย ๆ)

6.3 ตั้ง DNS server เอง

bash
docker run --dns 1.1.1.1 --dns 8.8.8.8 alpine

บอกให้ container ใช้ DNS ภายนอกตามที่ระบุ (สำหรับ resolve ชื่อ internet)


Part 7: Network Isolation — กั้นไม่ให้บางตัวคุยกัน

เทคนิคสำคัญด้าน security: ใส่ container ในหลาย network เพื่อควบคุมว่าใครคุยกับใครได้

ตัวอย่าง — เว็บ 3 ชั้น:

[ผู้ใช้] → [web] → [api] → [database]

ความต้องการ: web คุยกับ api ได้ / api คุยกับ database ได้ / แต่ web ห้าม คุยกับ database ตรง ๆ

bash
# สร้าง 2 network
docker network create frontend
docker network create backend

# web อยู่แค่ frontend
docker run -d --name web --network frontend mynginx

# api อยู่ทั้ง 2 network (เป็นสะพานเชื่อม)
docker run -d --name api --network frontend myapi
docker network connect backend api

# database อยู่แค่ backend
docker run -d --name database --network backend postgres:16

ผลลัพธ์:

  • webapi — ได้ (อยู่ frontend ด้วยกัน)
  • apidatabase — ได้ (อยู่ backend ด้วยกัน)
  • webdatabaseไม่ได้ (ไม่มี network ร่วมกัน) ✅

→ ถ้า web โดน hack — attacker ก็ยังเข้า database ตรง ๆ ไม่ได้ ต้องผ่าน api

docker network connect = เพิ่ม container เข้า network เพิ่มอีกอัน (1 container อยู่ได้หลาย network)


Part 8: คำสั่งจัดการ Network

bash
# ดู network ทั้งหมด
docker network ls

# สร้าง network
docker network create mynet

# สร้างพร้อมระบุ subnet
docker network create --subnet 172.30.0.0/16 mynet

# ดูรายละเอียด — ใครอยู่ใน network นี้บ้าง
docker network inspect mynet

# เพิ่ม container เข้า network
docker network connect mynet mycontainer

# เอา container ออกจาก network
docker network disconnect mynet mycontainer

# ลบ network (ต้องไม่มี container ใช้อยู่)
docker network rm mynet

# ลบ network ที่ไม่มีใครใช้
docker network prune

Part 9: Debug ปัญหา Network

เวลา container คุยกันไม่ได้ — ตรวจตามนี้:

bash
# 1. ทั้ง 2 ตัวอยู่ network เดียวกันไหม?
docker network inspect mynet
# ดูใน "Containers" ว่ามีทั้งคู่ไหม

# 2. ดู IP + network config ของ container
docker exec mycontainer ip addr

# 3. ทดสอบ DNS resolution
docker exec api nslookup db        # nslookup = ทดสอบแปลงชื่อเป็น IP ผ่าน DNS
docker exec api ping db            # ping = ยิง ICMP ดูว่าตอบกลับไหม

# 4. ทดสอบว่าต่อ port ได้ไหม
docker exec api nc -zv db 5432     # nc (netcat) = ลองเชื่อม TCP ดูว่า port เปิดไหม; -z = ลองเชื่อมแล้วออกทันที (ไม่ส่งข้อมูล), -v = verbose แสดงผล
docker exec api curl http://web:80

# 5. ดู DNS config
docker exec api cat /etc/resolv.conf

# 6. ดู port ที่ container เปิด — แนะนำ ss (จาก iproute2) เพราะ netstat เลิกพัฒนาแล้ว
docker exec api ss -tlnp           # ss = ดู socket ที่เปิดฟัง (modern)
# ทางเลือกเก่า (อาจไม่มีใน image เล็ก):
docker exec api netstat -tlnp      # netstat = ดู port ที่เปิดฟัง (deprecated)

📝 หมายเหตุสำคัญ: เครื่องมือ debug พวกนี้ — netstat (อ่าน "เน็ท-สแตท"), ss (อ่าน "เอส-เอส"), nc (อ่าน "เอ็น-ซี" หรือ netcat), nslookup (อ่าน "เอ็น-เอส-ลุ๊ก-อัพ"), ping, ip addrอาจไม่มีติดมาใน image เล็ก ๆ (เช่น alpine หรือ distroless ที่ตัดของออกเยอะ) ถ้าสั่งแล้วขึ้น "not found" ไม่ใช่ของพัง แต่ image นั้นไม่ได้ลงเครื่องมือนั้นมา

ทางแก้:

  • ติดตั้งเพิ่มชั่วคราวบน alpine: apk add iputils busybox-extras iproute2 (อ่าน "เอ-พี-เค แอ๊ดด์")
  • หรือใช้ debug container แยกต่างหากที่มีเครื่องมือครบ เช่น nicolaka/netshoot

ปัญหาที่พบบ่อย:

  • คุยกันไม่ได้ → อยู่คนละ network — เช็คด้วย docker network inspect
  • เรียกชื่อไม่เจอ → ใช้ default bridge (ไม่มี DNS) — ย้ายไป custom network
  • คนนอกเข้าไม่ได้ → ลืม -p หรือ bind ผิด interface
  • container ตายทันที → ดู docker logs — อาจ port ชนกัน

Part 10: Reverse Proxy Pattern

pattern ที่ใช้บ่อยในงานจริง: ใช้ container ตัวหนึ่ง (เช่น nginx) เป็น "ประตูหน้า" รับ request แล้วกระจายไปยัง container อื่น

📝 คำศัพท์ก่อนอ่านโค้ด:

  • upstream = กลุ่มเซิร์ฟเวอร์ปลายทาง (backend) ที่ nginx จะส่ง request ต่อไปให้ — เช่น ถ้ามีแอป 3 ตัว upstream คือ 3 ตัวนั้น
  • server block = นิยาม virtual host หนึ่งตัว — ฟัง port ไหน, ตอบ request อะไรบ้าง
  • location = match path ของ URL แล้วบอกว่าทำอะไรกับ request นั้น
bash
docker network create web

# 3 แอป — ไม่ใส่ -p (คนนอกเข้าตรงไม่ได้)
# hashicorp/http-echo คือ web server ทดลองขนาดเล็กที่ตอบข้อความที่กำหนด
# -listen และ -text เป็น argument ส่งเข้าโปรแกรมข้างใน container (ไม่ใช่ docker option)
docker run -d --name app1 --network web hashicorp/http-echo \
    -listen=:3000 -text="hello from app1"
docker run -d --name app2 --network web hashicorp/http-echo \
    -listen=:3000 -text="hello from app2"

# nginx — ใส่ -p (คนนอกเข้าได้)
# ⚠️ สำคัญ: mount ไปที่ /etc/nginx/conf.d/default.conf ไม่ใช่ /etc/nginx/nginx.conf
# เพราะ nginx.conf หลักต้องมี events{} และ http{} block ครบ
# — mount แบบ partial ทับไฟล์หลักจะทำให้ nginx start ไม่ขึ้น
docker run -d --name proxy --network web -p 80:80 \
    -v ./nginx.conf:/etc/nginx/conf.d/default.conf:ro \
    nginx:1.27-alpine

nginx.conf (เป็น partial config ที่ไป mount ใน conf.d/ — ไม่ต้องเขียน events{}/http{} ทับ):

nginx
server {
    listen 80;
    server_name _;   # รับทุก hostname

    # ⚠️ "/" ท้าย proxy_pass มีผล: ตัด prefix /app1/ ออกก่อนส่งต่อ
    # → request /app1/foo  จะถึง app1 เป็น /foo (ไม่ใช่ /app1/foo)
    location /app1/ { proxy_pass http://app1:3000/; }   # ใครเข้า /app1/ → ส่งต่อไป app1
    location /app2/ { proxy_pass http://app2:3000/; }   # ใครเข้า /app2/ → ส่งต่อไป app2
}

📝 trailing slash ใน proxy_pass: proxy_pass http://app1:3000/; (มี / ท้าย) = nginx ตัด prefix ของ location ออกก่อนส่งต่อ → /app1/foo กลายเป็น /foo ที่ app1 / ถ้าไม่ใส่ / ท้าย → /app1/foo ถูกส่งทั้ง path ไปเป็น /app1/foo แทน — เลือกให้ตรงกับที่ app รองรับ

ตัวอย่างนี้เขียนแบบเรียบง่าย — เรียก app1:3000 ตรง ๆ ใน proxy_pass (ไม่ใช้ upstream block) เพื่อให้อ่านง่าย. ถ้ามี backend หลายตัวต่อ service และอยาก load balance → ห่อใน upstream block แล้ว proxy_pass http://app1/;

ข้อดี:

  • เปิด port แค่ที่ proxy — แอปข้างหลังซ่อนจากโลกภายนอก
  • proxy ทำ SSL, load balance, rate limit ได้ที่จุดเดียว

Part 11: Lab

Lab 1: 2 Container คุยกัน

แล็บนี้พิสูจน์ว่า container ใน network เดียวกันคุยกันได้ด้วย "ชื่อ" — สร้าง network, รัน Postgres ชื่อ db แล้วต่อ psql จากอีก container โดยอ้างถึง host เป็น db ตรง ๆ (ไม่ต้องรู้ IP, ไม่ต้องใช้ -p):

bash
docker network create lab
docker run -d --name db --network lab \
    -e POSTGRES_PASSWORD=test postgres:16
docker run -it --rm --network lab postgres:16 \
    psql -h db -U postgres
# ใส่ password test → เข้า psql ได้ = คุยกันสำเร็จ

Lab 2: เทียบ default bridge vs custom

แล็บนี้ชี้ความต่างสำคัญระหว่าง default bridge กับ custom network — บน default bridge container เรียกกันด้วยชื่อไม่ได้ (ping fail) แต่บน network ที่เราสร้างเองมี DNS ในตัวให้ ping ชื่อได้เลย นี่คือเหตุผลที่ควรสร้าง network เองเสมอ:

bash
# default bridge — เรียกชื่อไม่ได้
docker run -d --name x1 nginx
docker run -d --name x2 nginx
docker exec x2 ping -c1 x1        # ❌ fail

# custom — เรียกชื่อได้
docker network create cn
docker run -d --name y1 --network cn nginx
docker run -d --name y2 --network cn nginx
docker exec y2 ping -c1 y1        # ✅ success

Lab 3: Network Isolation

ทำตาม Part 7 — สร้าง frontend/backend network — พิสูจน์ว่า web เข้า database ไม่ได้


Part 12: Checkpoint

  1. container ใน network เดียวกัน คุยกันได้ไหม? คนละ network ล่ะ?
  2. default bridge ต่าง custom bridge ยังไง? (ข้อสำคัญที่สุด)
  3. -p 8080:80 — ตัวซ้าย/ตัวขวาคืออะไร?
  4. containercontainer ต้องใช้ -p ไหม?
  5. ทำไมไม่ควรใส่ -p ที่ database?
  6. -p 127.0.0.1:8080:80 ต่าง -p 8080:80 ยังไง?
  7. host network ต่าง bridge ยังไง?
  8. Docker DNS ทำงานยังไง — container เรียกชื่อกันได้เพราะอะไร?
  9. Network isolation pattern ทำยังไง?
  10. overlay network ใช้ตอนไหน?

Part 13: สรุปบทนี้

  • container ใน network เดียวกัน คุยกันได้ / คนละ network ถูกกั้น
  • custom bridge network = ใช้เสมอ — มี DNS ให้เรียกชื่อ container ได้
  • default bridge = ไม่มี DNS — เลี่ยง
  • -p host:container = เปิดให้คนข้างนอกเข้า container — ใช้แค่กับ container ที่ต้องเปิดสู่ภายนอก
  • containercontainer ใน network เดียวกัน ไม่ต้อง -p
  • host network = เร็วแต่ไม่มี isolation / none = ไม่มี network / overlay = ข้ามเครื่อง
  • Network isolation = ใส่ container หลาย network เพื่อคุมว่าใครคุยกับใครได้

บทต่อไป — Volumes: เก็บข้อมูลถาวรยังไง ไม่ให้หายเมื่อลบ container


← บทที่ 01 | สารบัญ | บทที่ 03: Volumes →