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

DNS ของ Container และ User-Defined Networks

อย่างที่เห็นในบทเรียนก่อนหน้า container บน default bridge สามารถสื่อสารกันผ่าน IP address ได้ แต่ไม่สามารถ resolve ชื่อกันได้ นี่เป็นข้อจำกัดที่สำคัญในทางปฏิบัติ — IP address เป็นค่าที่เปลี่ยนแปลงได้และเปลี่ยนทุกครั้งที่ container ถูกสร้างใหม่

การ hardcode IP address ไว้ใน configuration ของ application นั้นเปราะบาง คุณต้องการวิธีอ้างอิง service ด้วยชื่อที่คงที่ เอกสาร networking อย่างเป็นทางการของ Docker ระบุความต่างนี้ชัดเจน: container บน default bridge จะได้แค่สำเนาของ /etc/resolv.conf ของ host เท่านั้น ในขณะที่ container บน custom (user-defined) network จะใช้ embedded DNS server ของ Docker ที่ 127.0.0.11 (docs.docker.com/engine/network) user-defined network คือวิธีที่ทำให้ได้ที่อยู่แบบชื่อที่คงที่แบบนี้

ใช้ docker network create เพื่อสร้าง bridge network ของคุณเอง:

Terminal window
docker network create appnet

Docker จะสร้าง bridge ใหม่ (แยกจาก docker0) และเริ่ม embedded DNS resolver ที่ผูกกับ network นั้นโดยเฉพาะ container ที่แนบกับ appnet จะ resolve ชื่อกันได้อัตโนมัติ

ใช้ flag --network เพื่อแนบ container เข้ากับ appnet เมื่อรัน:

Terminal window
docker run -d --name web --network appnet nginx:alpine
docker run -d --name client --network appnet alpine sleep 300

ทั้งสอง container ตอนนี้อยู่บน appnet และมี DNS resolver ของ Docker ให้บริการ

จาก client ลอง ping web ด้วยชื่อ:

Terminal window
docker exec client ping -c 3 web

การ ping สำเร็จ! DNS resolver ของ Docker แปลชื่อ web เป็น IP address ของ container นั้นโดยอัตโนมัติ

ดูรายละเอียด network รวมถึง container ที่เชื่อมต่ออยู่:

Terminal window
docker network inspect appnet
Terminal window
docker stop web client
docker rm web client
docker network rm appnet
# Create a user-defined bridge network
docker network create appnet

# Start an nginx container on appnet
docker run -d --name web --network appnet nginx:alpine

# Start a client container on appnet and ping web by name
docker run --rm --name client --network appnet alpine ping -c 3 web

# Inspect the network to see attached containers
docker network inspect appnet

# Cleanup
docker stop web && docker rm web
docker network rm appnet
ตัวเลือกBenefitCost
ต่อกันด้วย IP addressไม่ต้องพึ่ง DNS resolver ใด ๆต้องคอย query IP ใหม่ทุกครั้งที่ container restart เพราะ IP เปลี่ยนได้เสมอ
ต่อกันด้วยชื่อ container (DNS)resolve ชื่อเป็น IP ให้อัตโนมัติ อ้างอิงได้แม้ IP จะเปลี่ยนใช้ได้เฉพาะบน user-defined network เท่านั้น ไม่ทำงานบน default bridge
  • Hardcode IP address ของ container ไว้ในโค้ดหรือ environment variable แทนที่จะใช้ชื่อ container เป็น DNS name ทำให้ระบบพังทันทีที่ container ถูกสร้างใหม่และได้ IP อื่น
  • คาดหวังว่า DNS resolution จะทำงานบน default bridge network ทั้งที่ embedded DNS resolver ของ Docker รองรับเฉพาะ user-defined network เท่านั้น
  • ลืมว่า container ต้องอยู่บน user-defined network เดียวกันจริง ๆ ถึงจะ resolve ชื่อกันได้ — อยู่คนละ user-defined network ก็ resolve กันไม่ได้เหมือนกัน

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

ใน docker-compose.yml ชื่อ service เองก็คือ DNS hostname อยู่แล้ว เช่น service web เชื่อมต่อ database ได้ด้วย db:5432 ตรง ๆ โดยไม่ต้องรู้ IP เลย เพราะ Compose สร้าง user-defined network ให้อัตโนมัติและลงทะเบียน DNS ของทุก service ไว้ในนั้น

คุณสมบัติใดที่ user-defined bridge network มีแต่ default bridge ไม่มี?
คำสั่งใดสร้าง user-defined bridge network ชื่อ 'appnet'?
คุณรัน container สองตัวบน user-defined bridge network เดียวกัน container A ชื่อ 'api' และ container B ชื่อ 'db' container A จะเชื่อมต่อ container B ได้อย่างไร?
เกิดอะไรขึ้นกับการ resolve ชื่อ container ถ้าคุณย้าย container กลับไปที่ default bridge หลังจากใช้ user-defined network?