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

การ Publish และ Expose port

Dockerfile ของคุณอาจมีบรรทัดเช่น EXPOSE 80 สิ่งนี้บอกผู้อ่าน (และเครื่องมือ) ว่า application ภายใน container ฟังที่ port 80 แต่ ไม่ได้ publish port นั้นสู่ภายนอก

หากต้องการให้ host หรือโลกภายนอกสามารถเข้าถึง port ของ container ได้จริง คุณต้องใช้ flag -p (หรือ --publish) เมื่อรัน container

รูปแบบพื้นฐานคือ -p <host-port>:<container-port>:

Terminal window
docker run -d --name webserver -p 8080:80 nginx:alpine

สิ่งนี้ผูก port 8080 ของ host กับ port 80 ของ container การ request ที่มาถึง localhost:8080 จะถูกส่งต่อไปยัง port 80 ของ container โดย Docker

ตรวจสอบว่า port ใดถูก publish สำหรับ container:

Terminal window
docker port webserver

ผลลัพธ์จะแสดง: 80/tcp -> 0.0.0.0:8080

เมื่อ publish แล้ว คุณสามารถเข้าถึงได้จาก host:

Terminal window
curl http://localhost:8080

โดยค่าเริ่มต้น Docker จะ bind กับทุก interface (0.0.0.0) หากต้องการผูกเฉพาะ loopback interface:

Terminal window
docker run -d --name local-only -p 127.0.0.1:9090:80 nginx:alpine

วิธีนี้ทำให้ service เข้าถึงได้เฉพาะจาก machine นั้นเอง ไม่สามารถเข้าถึงได้จาก network ภายนอก

ใช้ flag -p หลายครั้งเพื่อ publish หลาย port:

Terminal window
docker run -d --name multi -p 8080:80 -p 8443:443 nginx:alpine
# 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
ตัวเลือกBenefitCost
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 ภายใน ทำให้พื้นที่ที่เปิดสู่ภายนอกมีแค่จุดเดียว

คำสั่ง EXPOSE ใน Dockerfile จริงๆ แล้วทำอะไร?
คุณรัน: docker run -p 9000:3000 myapp ข้อใดต่อไปนี้อธิบาย port mapping ได้ถูกต้อง?
จะจำกัด published port ให้เข้าถึงได้เฉพาะจาก local machine (loopback interface) ได้อย่างไร?
คำสั่งใดแสดงรายการ port mapping ของ container ชื่อ 'webserver'?