การ Publish และ Expose port
EXPOSE กับ -p ต่างกันอย่างไร
หัวข้อที่มีชื่อว่า “EXPOSE กับ -p ต่างกันอย่างไร”Dockerfile ของคุณอาจมีบรรทัดเช่น EXPOSE 80 สิ่งนี้บอกผู้อ่าน (และเครื่องมือ) ว่า application ภายใน container ฟังที่ port 80 แต่ ไม่ได้ publish port นั้นสู่ภายนอก
หากต้องการให้ host หรือโลกภายนอกสามารถเข้าถึง port ของ container ได้จริง คุณต้องใช้ flag -p (หรือ --publish) เมื่อรัน container
Syntax การ Publish port
หัวข้อที่มีชื่อว่า “Syntax การ Publish port”รูปแบบพื้นฐานคือ -p <host-port>:<container-port>:
docker run -d --name webserver -p 8080:80 nginx:alpineสิ่งนี้ผูก port 8080 ของ host กับ port 80 ของ container การ request ที่มาถึง localhost:8080 จะถูกส่งต่อไปยัง port 80 ของ container โดย Docker
ดูรายการ Port Mapping
หัวข้อที่มีชื่อว่า “ดูรายการ Port Mapping”ตรวจสอบว่า port ใดถูก publish สำหรับ container:
docker port webserverผลลัพธ์จะแสดง: 80/tcp -> 0.0.0.0:8080
ทดสอบ Published Port
หัวข้อที่มีชื่อว่า “ทดสอบ Published Port”เมื่อ publish แล้ว คุณสามารถเข้าถึงได้จาก host:
curl http://localhost:8080ผูกกับ Interface เฉพาะ
หัวข้อที่มีชื่อว่า “ผูกกับ Interface เฉพาะ”โดยค่าเริ่มต้น Docker จะ bind กับทุก interface (0.0.0.0) หากต้องการผูกเฉพาะ loopback interface:
docker run -d --name local-only -p 127.0.0.1:9090:80 nginx:alpineวิธีนี้ทำให้ service เข้าถึงได้เฉพาะจาก machine นั้นเอง ไม่สามารถเข้าถึงได้จาก network ภายนอก
Publish หลาย Port พร้อมกัน
หัวข้อที่มีชื่อว่า “Publish หลาย Port พร้อมกัน”ใช้ flag -p หลายครั้งเพื่อ publish หลาย port:
docker run -d --name multi -p 8080:80 -p 8443:443 nginx:alpineลงมือปฏิบัติ: Publishing Ports
หัวข้อที่มีชื่อว่า “ลงมือปฏิบัติ: Publishing Ports”# Publish port 80 of nginx to host port 8080
docker run -d --name webserver -p 8080:80 nginx:alpine
# List port mappings
docker port webserver
# Curl the published port
curl http://localhost:8080
# Bind to loopback only
docker run -d --name local-only -p 127.0.0.1:9090:80 nginx:alpine
# Multiple ports
docker run -d --name multi -p 8080:80 -p 8443:443 nginx:alpine
# Cleanup
docker stop webserver local-only multi && docker rm webserver local-only multiข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
Publish ไปที่ 0.0.0.0 (ทุก interface) | เข้าถึงได้จากทุกเครื่องในเครือข่าย เหมาะกับ service ที่ต้องเปิดสู่ภายนอกจริง | เปิดช่องเข้าถึงกว้างเกินจำเป็นถ้า service นั้นควรใช้แค่ภายในเครื่อง |
Publish ไปที่ 127.0.0.1 เท่านั้น | จำกัดการเข้าถึงเฉพาะจาก host เดียวกัน ปลอดภัยกว่า | เข้าถึงจากเครื่องอื่นในเครือข่ายไม่ได้เลย ต้องแก้ flag ถ้าจะเปิดออกภายหลัง |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- เข้าใจผิดว่า
EXPOSEใน Dockerfile publish port ออกมาจริง ทั้งที่เป็นแค่เอกสารบอกว่า container ฟัง port ไหน ต้องใช้-p/--publishเท่านั้นถึงจะ map port ออกมาให้เข้าถึงได้จริง - Publish port ไปที่
0.0.0.0โดยไม่ตั้งใจสำหรับ service ที่ควรเข้าถึงได้แค่จาก localhost เช่น database หรือ admin panel ทำให้เปิดสู่เครือข่ายภายนอกโดยไม่จำเป็น - Publish port เดียวกันซ้ำจากหลาย container บน host เดียว ทำให้
docker runล้มเหลวเพราะ port ถูกจองไปแล้วโดย container ตัวอื่น
💡 ตัวอย่างจากของจริง
Pattern ทั่วไปในการ deploy คือ publish port แค่จาก reverse proxy ตัวเดียว (เช่น Traefik หรือ nginx) ที่
0.0.0.0:80และ0.0.0.0:443ส่วน backend service อื่น ๆ ไม่ publish port เลย แต่คุยกันผ่าน internal network ภายใน ทำให้พื้นที่ที่เปิดสู่ภายนอกมีแค่จุดเดียว