ข้ามไปยังเนื้อหา

Custom Networks และการแยก Container

การใส่ container ทั้งหมดไว้บน network เดียวกันหมายความว่าพวกเขาสามารถสื่อสารกันได้ทั้งหมด — ไม่ว่าจะเป็น frontend กับ database หรือ microservice กับ microservice อื่นที่ไม่ควรรู้จักกัน การแยก network เป็นมาตรการความปลอดภัยที่ไม่มีต้นทุน (zero-cost): container บน network ต่างกันเข้าถึงกันไม่ได้ เว้นแต่จะเชื่อมต่อเข้ากับทั้งสอง network อย่างชัดเจน

การสร้าง network แยกสำหรับแต่ละ tier ของ application ช่วยให้คุณ:

  • จำกัดการสื่อสารเฉพาะที่จำเป็น
  • ลดพื้นที่การโจมตีหากมี container ถูก compromise
  • สร้างสถาปัตยกรรมที่ชัดเจนและ document ตัวเองได้

docker network create ใช้ driver bridge เป็นค่าเริ่มต้น จึงละ --driver bridge ได้เพื่อความกระชับ สร้าง network สองตัวสำหรับ frontend และ backend:

Terminal window
docker network create frontend-net
docker network create backend-net
Terminal window
docker run -d --name frontend --network frontend-net nginx:alpine
docker run -d --name database --network backend-net -e POSTGRES_PASSWORD=example postgres:alpine

frontend และ database อยู่คนละ network จึงสื่อสารกันไม่ได้โดยค่าเริ่มต้น

application แบบ three-tier ทั่วไปจะขยายแนวคิดนี้ไปเป็นสาม network:

NetworkContainer ที่แนบอยู่เข้าถึงได้
frontend-netnginx-proxy, web-appกันเองเท่านั้น
backend-netweb-app, api-serverกันเองเท่านั้น
data-netapi-server, postgresกันเองเท่านั้น

web-app เชื่อมต่อทั้ง frontend-net และ backend-net จึงเป็นสะพานเชื่อมสองชั้น ส่วน postgres อยู่บน data-net เพียงอย่างเดียว — nginx proxy เข้าถึง database โดยตรงไม่ได้ แม้จะถูก compromise ก็ตาม

Terminal window
docker exec frontend ping -c 2 database || echo "Cannot reach database"

การ ping ล้มเหลวตามที่คาดหวัง เพราะ frontend อยู่บน frontend-net และ database อยู่บน backend-net

Container ที่กำลังรันอยู่สามารถแนบเข้ากับอีก network หนึ่งได้โดยไม่ต้องรีสตาร์ท:

Terminal window
docker network connect backend-net frontend

ตอนนี้ frontend มี interface อยู่บนทั้ง frontend-net และ backend-net และสามารถ resolve และเข้าถึง database ด้วยชื่อได้:

Terminal window
docker exec frontend ping -c 2 database
Terminal window
# Detach frontend from backend-net again
docker network disconnect backend-net frontend
# Filter docker network ls to just bridge networks
docker network ls --filter driver=bridge
# Inspect a network's driver, subnet, gateway, and attached containers
docker network inspect frontend-net

ไม่สามารถลบ network ได้ขณะที่ยังมี container แนบอยู่ — หยุดและลบ container ก่อน แล้วจึงลบ network:

Terminal window
docker network rm frontend-net
Terminal window
docker stop frontend database
docker rm frontend database
docker network rm frontend-net backend-net
# Create two isolated networks
docker network create frontend-net
docker network create backend-net

# Run containers on separate networks
docker run -d --name frontend --network frontend-net nginx:alpine
docker run -d --name database --network backend-net -e POSTGRES_PASSWORD=example postgres:alpine

# frontend cannot reach database (different networks)
docker exec frontend ping -c 2 database || echo "Cannot reach database"

# Connect frontend to backend-net so it can reach the database
docker network connect backend-net frontend

# Now frontend can reach database
docker exec frontend ping -c 2 database

# Inspect a network
docker network inspect frontend-net

# Disconnect
docker network disconnect backend-net frontend

# Cleanup
docker stop frontend database && docker rm frontend database
docker network rm frontend-net backend-net
ตัวเลือกBenefitCost
รวม container ทั้งหมดไว้บน network เดียวตั้งค่าเร็ว ไม่ต้องคิดเรื่อง network topologycontainer ทุกตัวมองเห็นและเข้าถึงกันได้หมด เพิ่มพื้นที่การโจมตีโดยไม่จำเป็น
แยก network ตาม tier (frontend/backend/data)จำกัดการสื่อสารเฉพาะที่จำเป็น ลดผลกระทบหากมี container ถูก compromiseต้องบริหารจัดการหลาย network และ connect/disconnect container เอง
  • ใส่ container ที่ไม่เกี่ยวข้องกันทั้งหมดไว้บน network เดียว (หรือปล่อยไว้บน default bridge) ทำให้ database ถูกเข้าถึงได้จาก container ไหนก็ได้ที่รันอยู่บนเครื่องเดียวกัน
  • ลืมว่า docker network connect เชื่อม container เข้ากับ network เพิ่มได้ แต่ต้อง docker network disconnect ออกเองด้วยเหมือนกัน ไม่ได้หลุดออกเองเมื่อ container หยุดทำงาน
  • ใช้ network เดียวกันสำหรับทุก environment (dev/staging/prod) ทำให้ container จากคนละ environment ปนกันโดยไม่ได้ตั้งใจ

💡 ตัวอย่างจากของจริง

Docker Compose สร้าง user-defined network แยกให้แต่ละโปรเจกต์โดยอัตโนมัติ (ตั้งชื่อตาม project directory เช่น myapp_default) เพื่อให้ service ในโปรเจกต์หนึ่งไม่ชนหรือมองเห็น container ของอีกโปรเจกต์บนเครื่อง dev เดียวกัน — เป็น pattern มาตรฐานสำหรับ multi-project local development

Container สองตัวอยู่บน user-defined bridge network ที่ต่างกัน สามารถสื่อสารกันได้โดยค่าเริ่มต้นหรือไม่?
คุณมี container ชื่อ 'api' ที่กำลังรันอยู่และต้องการเชื่อมต่อกับ network ชื่อ 'data-net' โดยไม่รีสตาร์ท คำสั่งใดที่ใช้?
คุณลอง docker network rm mynet แต่ได้รับ error ว่า network มี active endpoints สิ่งที่ต้องทำก่อนคืออะไร?
ใน three-tier app คุณต้องการให้ database container เข้าถึงได้โดย API server แต่ไม่ใช่ frontend proxy การออกแบบ network ที่ถูกต้องคืออะไร?