วิธีตั้งค่า Docker Compose Networking อย่างละเอียด
เรียนรู้การทำงานของ Docker Compose Network ทั้งการเชื่อมต่อผ่าน service name การจัดการ bridge network และกรณีที่ควรใช้ host mode รวมถึงข้อควรระวังเรื่อง port ที่ข้าม UFW
สิ่งที่ Compose สร้างก่อนที่แอปพลิเคชันของคุณจะเริ่มทำงาน
การทำงานของเครือข่ายใน Docker Compose มีกฎพื้นฐานหนึ่งข้อ: docker compose up จะสร้างเครือข่ายส่วนตัวสำหรับโปรเจกต์ เชื่อมต่อทุกเซอร์วิสเข้ากับเครือข่ายนั้น และอนุญาตให้เซอร์วิสเหล่านั้นติดต่อสื่อสารกันได้ผ่านชื่อเซอร์วิส คุณไม่จำเป็นต้องเขียนบรรทัด networks: ใดๆ เพื่อให้ได้ฟังก์ชันนี้ ความสับสนส่วนใหญ่เกี่ยวกับเครือข่ายของ Compose เกิดจากการไม่ทราบว่าค่าเริ่มต้นนี้มีอยู่แล้ว
นี่คือไฟล์ตัวอย่างขนาดเล็ก ให้บันทึกไฟล์นี้เป็น compose.yaml ในไดเรกทอรีที่ชื่อว่า shop
services:
web:
image: nginx:1.27
ports:
- "8080:80"
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: exampleเริ่มการทำงานของโปรเจกต์และตรวจสอบสิ่งที่ Docker สร้างขึ้น:
docker compose up -d
docker network lsรายการที่แสดงตอนนี้จะมีเครือข่ายที่ชื่อว่า shop_default อยู่ด้วย Compose จะตั้งชื่อเครือข่ายนี้ว่า <project>_default โดยชื่อโปรเจกต์จะใช้ชื่อไดเรกทอรีเป็นตัวพิมพ์เล็กโดยอัตโนมัติ คุณสามารถกำหนดชื่อใหม่ได้ด้วย docker compose -p myproject up -d หรือใช้คำสั่ง name: myproject ที่ระดับบนสุดของไฟล์ ไดรเวอร์ของเครือข่ายนี้คือ bridge ซึ่งทำหน้าที่เป็นสวิตช์เสมือนภายในโฮสต์ คอนเทนเนอร์แต่ละตัวจะได้รับที่อยู่บนซับเน็ตส่วนตัว และทราฟฟิกขาออกจะถูกแปลงที่อยู่ (NAT) ไปเป็นที่อยู่ของโฮสต์ในขณะที่ส่งออกไป
docker compose down จะลบเครือข่ายนั้นออก นี่คือสาเหตุที่คอนเทนเนอร์ที่ค้างมาจากโปรเจกต์เก่าอาจทำให้เครือข่ายยังคงเปิดอยู่: Docker จะปฏิเสธการทำงานพร้อมข้อความ error while removing network: network shop_default has active endpoints และวิธีแก้ไขคือการหยุดหรือลบคอนเทนเนอร์ที่ยังคงเชื่อมต่อกับเครือข่ายนั้นอยู่
หากคุณเพิ่งเริ่มใช้งาน Compose การอ่าน โครงสร้างไฟล์ Compose และคำสั่งวงจรชีวิต ก่อนถือเป็นเรื่องดี เพราะเนื้อหาทั้งหมดด้านล่างนี้ตั้งอยู่บนพื้นฐานที่คุณสามารถเริ่มและหยุดโปรเจกต์ได้แล้ว
DNS ตามชื่อบริการคือสิ่งที่มือใหม่มักมองข้าม
บนเครือข่ายที่ผู้ใช้กำหนดเอง Docker จะรันเซิร์ฟเวอร์ DNS แบบฝังตัวที่คอนเทนเนอร์แต่ละตัวมองเห็นได้ที่ 127.0.0.11 ซึ่งจะทำหน้าที่แปลงชื่อบริการให้เป็นที่อยู่ของคอนเทนเนอร์ในปัจจุบัน ดังนั้น web จึงสามารถเข้าถึงฐานข้อมูลได้ที่ชื่อโฮสต์ db บนพอร์ต 5432 โดยไม่ต้องตั้งค่าใดๆ เพิ่มเติม
docker compose exec web getent hosts dbคำสั่งดังกล่าวจะแสดงบรรทัดที่คล้ายกับ 172.18.0.2 db หากไม่แสดงผลลัพธ์ใดๆ แสดงว่าบริการทั้งสองไม่ได้อยู่บนเครือข่ายเดียวกัน
ข้อผิดพลาดที่เกือบทุกคนเคยทำคือการใช้ localhost ในการตั้งค่าแอปพลิเคชัน ภายในคอนเทนเนอร์นั้น localhost หมายถึงตัวคอนเทนเนอร์นั้นเอง ไม่ใช่โฮสต์และไม่ใช่บริการอื่น ไคลเอนต์ Postgres จะรายงานเรื่องนี้ไว้อย่างชัดเจน:
could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP connections on port 5432?สตริงการเชื่อมต่อควรเป็น postgresql://postgres:example@db:5432/postgres โดยส่วนของโฮสต์คือชื่อบริการ
มีรายละเอียดสองประการที่จะช่วยประหยัดเวลาในภายหลัง ประการแรก ชื่อจะถูกแปลงเป็นสิ่งที่กำลังทำงานอยู่ในขณะนั้น ดังนั้น docker compose up -d --scale web=3 จะให้ชื่อเดียวที่มีสามที่อยู่ และไคลเอนต์ที่แคช DNS ไว้ตลอดไปจะยึดติดอยู่กับคอนเทนเนอร์ที่หยุดทำงานไปแล้ว ประการที่สอง เครือข่าย bridge แบบเดิมที่ใช้โดย docker run ทั่วไปที่ไม่มี --network นั้นไม่มีการแปลงชื่อใดๆ ทั้งสิ้น ซึ่งเป็นเหตุผลว่าทำไมคำแนะนำเกี่ยวกับการเชื่อมโยงคอนเทนเนอร์จากปี 2016 จึงไม่ตรงกับสิ่งที่คุณพบในปัจจุบัน
คุณไม่จำเป็นต้องใช้ ports: เพื่อเชื่อมต่อสองบริการเข้าด้วยกัน
ports: จะเผยแพร่พอร์ตของคอนเทนเนอร์ไปยังโฮสต์ ซึ่งใช้สำหรับทราฟฟิกที่มาจากภายนอก Docker เท่านั้น โดยไม่มีผลใดๆ ต่อทราฟฟิกที่สื่อสารระหว่างบริการด้วยกันเอง ซึ่งสามารถทำงานได้อยู่แล้วผ่านพอร์ตทุกช่วงบนเครือข่ายของโปรเจกต์
ดังนั้น ports: - "5432:5432" ที่หลายคนเพิ่มเข้าไปในบริการฐานข้อมูลจึงไม่มีประโยชน์และส่งผลเสียจริง เพราะเป็นการเปิดเผย Postgres บนอินเทอร์เฟซสาธารณะของเซิร์ฟเวอร์ ให้ลบออกเสีย หากคุณต้องการเข้าถึงฐานข้อมูลจากแล็ปท็อปเพื่อทำการย้ายข้อมูล ให้ผูกไว้กับ loopback ด้วย "127.0.0.1:5432:5432" แล้วเข้าถึงผ่าน SSH tunnel แทน ความแตกต่างระหว่าง listening socket, พอร์ตที่เผยแพร่ และกฎของไฟร์วอลล์ ได้รับการอธิบายไว้ใน วิธีการทำงานของพอร์ตและบริการที่รอรับการเชื่อมต่อบน Linux
expose: เป็นเพียงเอกสารประกอบภายใต้ Compose เท่านั้น มันไม่ได้เปิดการเชื่อมต่อใดๆ เนื่องจากไม่มีการปิดกั้นการสื่อสารระหว่างคอนเทนเนอร์ที่อยู่บนเครือข่ายเดียวกันอยู่แล้ว
เมื่อใดที่ควรใช้ network_mode host และผลกระทบที่ตามมา
โหมด host จะยกเลิก network namespace ของคอนเทนเนอร์ และอนุญาตให้กระบวนการทำงานใช้งานอินเทอร์เฟซของโฮสต์ได้โดยตรง
services:
probe:
image: alpine:3.20
network_mode: host
command: sleep infinityมีเหตุผลที่สมเหตุสมผลในการเลือกใช้โหมดนี้ กระบวนการที่จำเป็นต้องมองเห็นทราฟฟิกแบบ broadcast หรือ multicast บนเครือข่ายท้องถิ่น เช่น การค้นหาอุปกรณ์สำหรับ media server หรือ home automation hub จะไม่สามารถมองเห็นทราฟฟิกดังกล่าวได้หากอยู่หลัง bridge เนื่องจาก bridge จะไม่ส่งต่อทราฟฟิกนั้นไปยังคอนเทนเนอร์ ส่วน monitoring agent ที่ต้องอ่านค่าตัวนับอินเทอร์เฟซของโฮสต์ก็จำเป็นต้องเข้าถึงอินเทอร์เฟซของโฮสต์โดยตรง นอกจากนี้ คุณยังข้ามขั้นตอนการแปลงที่อยู่ (address translation) ซึ่งมีความสำคัญเมื่อมีอัตราการส่งแพ็กเก็ตสูง
ผลกระทบที่ตามมามีประเด็นเฉพาะตัว
ports: จะหยุดทำงาน Docker จะแจ้งเตือนว่าพอร์ตที่เผยแพร่ (published ports) จะถูกละทิ้งเมื่อใช้โหมดเครือข่ายแบบ host และคอนเทนเนอร์จะผูกกับพอร์ตใดก็ตามที่กระบวนการภายในผูกไว้ หากคอนเทนเนอร์โหมด host สองตัวต้องการใช้พอร์ต 8080 จะเกิดการชนกัน และตัวที่สองจะหยุดทำงานพร้อมกับ bind: address already in use
การแก้ไขชื่อ (name resolution) ตามชื่อบริการจะใช้งานไม่ได้ทั้งสองทิศทาง คอนเทนเนอร์ไม่ได้อยู่ในเครือข่ายของโปรเจกต์ จึงไม่สามารถแก้ไขชื่อ db ได้ และบริการอื่นก็ไม่สามารถแก้ไขชื่อคอนเทนเนอร์นี้ได้เช่นกัน คอนเทนเนอร์จะเข้าถึงบริการอื่นได้ผ่านพอร์ตที่เผยแพร่บนโฮสต์เท่านั้น ซึ่งโดยปกติคือ 127.0.0.1
การแยกส่วน (isolation) จะหายไป กระบวนการที่ผูกกับ 0.0.0.0 ภายในคอนเทนเนอร์โหมด host จะรับฟังการเชื่อมต่อบนทุกอินเทอร์เฟซของเซิร์ฟเวอร์ รวมถึงอินเทอร์เฟซสาธารณะ เหมือนกับแพ็กเกจที่ติดตั้งผ่าน apt ทุกประการ ข้อดีประการหนึ่งคือทราฟฟิกนี้จะผ่านเส้นทาง input ปกติ ดังนั้นกฎของ UFW จึงมีผลบังคับใช้ ซึ่งต่างจากพอร์ตที่เผยแพร่แบบปกติ
โหมด host เป็นฟีเจอร์ของ Linux Docker Engine โดย Docker Desktop จะรองรับฟีเจอร์นี้ตั้งแต่เวอร์ชัน 4.34 เป็นต้นไปและต้องเปิดใช้งานก่อนเท่านั้น โดยมีข้อจำกัดเพิ่มเติมคือคอนเทนเนอร์ไม่สามารถผูกกับ IP address ของโฮสต์ได้ และรองรับเฉพาะโปรโตคอล TCP และ UDP เท่านั้น หากทีมของคุณครึ่งหนึ่งใช้เซิร์ฟเวอร์ Linux และอีกครึ่งใช้ Docker Desktop ให้คาดการณ์ไว้เลยว่าไฟล์เดียวกันจะมีพฤติกรรมการทำงานที่แตกต่างกัน
ควรเลือกใช้โหมด host เมื่อคุณจำเป็นต้องเข้าถึงอินเทอร์เฟซของโฮสต์เท่านั้น อย่าเลือกใช้เพื่อแก้ไขปัญหาการเชื่อมต่อ เนื่องจากมักจะเป็นการแทนที่ปัญหาเดิมด้วยปัญหาใหม่ที่ซับซ้อนกว่าเดิม
การเชื่อมต่อโปรเจกต์ Compose สองโปรเจกต์เข้ากับเครือข่ายภายนอก
เครือข่ายที่สร้างโดยโปรเจกต์หนึ่งจะไม่สามารถมองเห็นได้จากอีกโปรเจกต์หนึ่ง นี่คือเหตุผลที่ reverse proxy ใน proxy/compose.yaml ไม่สามารถมองเห็นแอปพลิเคชันใน app/compose.yaml ได้ แม้ว่าจะอยู่บนเซิร์ฟเวอร์เดียวกันก็ตาม วิธีแก้ไขคือการใช้เครือข่ายที่ไม่มีโปรเจกต์ใดเป็นเจ้าของ
สร้างเครือข่ายขึ้นมาหนึ่งครั้งด้วยตนเอง:
docker network create edgeจากนั้นประกาศเครือข่ายดังกล่าวว่าเป็น external ในแต่ละโปรเจกต์ สำหรับฝั่ง proxy:
services:
proxy:
image: traefik:v3.1
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- edge
networks:
edge:
name: edge
external: trueสำหรับฝั่งแอปพลิเคชัน:
services:
app:
image: nginx:1.27
networks:
- edge
- internal
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: example
networks:
- internal
networks:
edge:
name: edge
external: true
internal:external: true สั่งให้ Compose เชื่อมต่อเข้ากับเครือข่ายที่มีอยู่เดิมแทนที่จะสร้างเครือข่ายใหม่ และให้คงเครือข่ายนั้นไว้เมื่อใช้คำสั่ง docker compose down คีย์ name: ที่แยกออกมามีความสำคัญมากกว่าที่เห็น: หากไม่มีคีย์นี้ Compose จะมองหาเครือข่ายที่ชื่อ edge โดยตรง แต่เมื่อมีคีย์นี้ คุณสามารถตั้งชื่อเครือข่ายในไฟล์ของคุณอย่างหนึ่ง และใช้ชื่ออื่นบนโฮสต์ได้
หากเครือข่ายไม่มีอยู่จริง Compose จะปฏิเสธการเริ่มทำงานและแจ้งว่าเครือข่ายถูกประกาศว่าเป็น external แต่ไม่พบเครือข่ายดังกล่าว คุณต้องสร้างเครือข่ายก่อนเสมอ
สังเกตสิ่งที่ไฟล์แอปพลิเคชันทำกับ internal ฐานข้อมูลจะอยู่บนเครือข่ายเฉพาะของโปรเจกต์นั้นเท่านั้น ดังนั้น proxy จึงไม่สามารถเข้าถึงฐานข้อมูลได้ และมีเพียง app เท่านั้นที่เข้าถึงได้ การเพิ่ม internal: true ภายใต้เครือข่ายจะช่วยเพิ่มความปลอดภัยโดยการตัดเส้นทางออกสู่โลกภายนอกทั้งหมด นี่เป็นค่าเริ่มต้นที่ดีสำหรับฐานข้อมูล แต่มีข้อควรทราบก่อนตั้งค่าคือ คอนเทนเนอร์ที่อยู่บนเครือข่ายภายในจะไม่สามารถดาวน์โหลดสิ่งใดได้ ดังนั้น entrypoint ที่รัน apt-get update หรือ pip install ในระหว่างการเริ่มต้นระบบจะค้างและล้มเหลวเนื่องจากหมดเวลา (timeout)
สำหรับตัวอย่างการตั้งค่าที่สมบูรณ์พร้อมกฎการกำหนดเส้นทางและใบรับรอง โปรดดู การรันแอปพลิเคชันหลายตัวหลัง Traefik instance เดียวกัน
พอร์ตที่ถูกเผยแพร่ข้ามการทำงานของ UFW
นี่คือส่วนหนึ่งของระบบเครือข่ายใน Compose ที่อาจกลายเป็นเหตุการณ์ด้านความปลอดภัยได้ คุณเผยแพร่พอร์ต (publish) ตรวจสอบว่า UFW ทำงานอยู่และปฏิเสธการเชื่อมต่อทั้งหมดที่ไม่ใช่ SSH แต่บริการนั้นยังคงสามารถเข้าถึงได้จากอินเทอร์เน็ต
sudo ufw status
curl http://203.0.113.10:8080UFW แจ้งว่าพอร์ตถูกบล็อกไว้ แต่ curl กลับแสดงหน้าเว็บออกมาได้ตามปกติ ไม่มีสิ่งใดเสียหาย Docker เขียนกฎการแปลงที่อยู่ (NAT) และการส่งต่อข้อมูลลงใน iptables โดยตรง ทำให้ทราฟฟิกที่มุ่งหน้าไปยังพอร์ตของคอนเทนเนอร์ที่ถูกเผยแพร่จะถูกส่งต่อไปยังคอนเทนเนอร์แทนที่จะส่งมายังโฮสต์ ดังนั้นทราฟฟิกดังกล่าวจึงไม่ผ่านเชนที่ UFW จัดการสำหรับทราฟฟิกที่มุ่งหน้ามายังโฮสต์โดยตรง นอกจากนี้ กฎของ Docker ยังถูกตรวจสอบก่อนกฎของ UFW อีกด้วย
วิธีแก้ไขระยะสั้นคือการเผยแพร่พอร์ตเฉพาะในจุดที่จำเป็นเท่านั้น:
ports:
- "127.0.0.1:8080:80"การทำเช่นนี้จะผูกฝั่งโฮสต์เข้ากับ loopback ทำให้พอร์ตสามารถเข้าถึงได้จากตัวเซิร์ฟเวอร์เอง หรือผ่าน SSH tunnel เท่านั้น และไม่สามารถเข้าถึงจากที่อื่นได้ ให้วางจุดเชื่อมต่อสาธารณะไว้หลัง reverse proxy ที่เผยแพร่พอร์ต 80 และ 443 อย่างตั้งใจ คำอธิบายฉบับเต็ม รวมถึงเชน DOCKER-USER สำหรับกรณีที่คุณจำเป็นต้องกรองพอร์ตที่เผยแพร่อยู่ สามารถดูได้ที่ เหตุผลที่ Docker เผยแพร่พอร์ตโดยข้าม UFW และวิธีแก้ไข
วิธีการดีบั๊กด้วย 4 คำสั่ง
เริ่มต้นด้วยการตรวจสอบว่าแต่ละคอนเทนเนอร์เชื่อมต่ออยู่กับเครือข่ายใดจริง ๆ:
docker network inspect shop_defaultบล็อก Containers จะแสดงรายการคอนเทนเนอร์ทั้งหมดที่เชื่อมต่ออยู่พร้อมที่อยู่ IP หากบริการใดไม่อยู่ในรายการนี้ แสดงว่าบริการนั้นอยู่บนเครือข่ายอื่น อยู่ในโหมด host หรือไม่ได้ทำงานอยู่
ทดสอบการแปลงชื่อ (name resolution) จากคอนเทนเนอร์ชั่วคราวที่เชื่อมต่อกับเครือข่ายเดียวกัน เพื่อให้คุณไม่ต้องติดตั้งเครื่องมือใด ๆ เพิ่มเติมภายในอิมเมจของคุณ:
docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432หาก nslookup ล้มเหลว แสดงว่ามีปัญหาที่การแปลงชื่อหรือการเป็นสมาชิกในเครือข่าย หาก nslookup ทำงานได้สำเร็จแต่ nc ล้มเหลว แสดงว่าบริการกำลังทำงานอยู่แต่ไม่ได้รอรับการเชื่อมต่อที่พอร์ตนั้น หรืออาจกำลังรอรับการเชื่อมต่อที่ 127.0.0.1 ภายในคอนเทนเนอร์ของตัวเองแทนที่จะเป็น 0.0.0.0 กรณีหลังนี้มักพบได้บ่อยกับเซิร์ฟเวอร์สำหรับการพัฒนา ซึ่งวิธีแก้ไขคือการปรับค่า bind address ในตัวแอปพลิเคชัน ไม่ใช่ที่ Docker
อีกหนึ่งความล้มเหลวที่ดูเหมือนเป็นบั๊กของ Docker คือ หากคอนเทนเนอร์สามารถสื่อสารกันเองได้ แต่ไม่สามารถเข้าถึงเครื่องในเครือข่ายสำนักงานหรือ VPN ของคุณได้ เป็นไปได้ว่า Docker subnet มีการทับซ้อนกับเครือข่ายนั้น โดยปกติ Docker จะจัดสรรที่อยู่ IP เริ่มต้นจาก 172.17.0.0/16 ขึ้นไป ให้ย้าย pool ใน /etc/docker/daemon.json:
{
"default-address-pools": [
{ "base": "10.200.0.0/16", "size": 24 }
]
}จากนั้นให้รัน sudo systemctl restart docker และสร้างเครือข่ายที่ได้รับผลกระทบขึ้นมาใหม่ เนื่องจากเครือข่ายที่มีอยู่เดิมจะยังคงใช้ subnet เดิมที่ถูกกำหนดไว้ตอนสร้างเครือข่ายนั้น ๆ
FAQ
เหตุใดคอนเทนเนอร์ของฉันจึงไม่สามารถติดต่อกันผ่านชื่อเซอร์วิสได้?
คอนเทนเนอร์เหล่านั้นไม่ได้อยู่บนเครือข่ายเดียวกัน Compose จะนำทุกเซอร์วิสไปไว้บน <project>_default โดยอัตโนมัติ แต่ทันทีที่คุณเพิ่มรายการ networks: ให้กับเซอร์วิส รายการนั้นจะกลายเป็นชุดเครือข่ายทั้งหมดสำหรับเซอร์วิสนั้น และค่าเริ่มต้นจะไม่ถูกนำมาใช้โดยอัตโนมัติอีกต่อไป ให้รันคำสั่ง docker network inspect <network> และตรวจสอบว่าคอนเทนเนอร์ทั้งสองปรากฏอยู่ในบล็อก Containers นอกจากนี้ ให้ตรวจสอบว่าไม่มีเซอร์วิสใดใช้ network_mode: host เนื่องจากคอนเทนเนอร์ที่อยู่ในโหมด host จะไม่ได้อยู่บนเครือข่าย Docker ใดๆ และไม่สามารถแก้ไขชื่อเซอร์วิสได้
ฉันจำเป็นต้องเปิดพอร์ตเพื่อให้เซอร์วิสหนึ่งติดต่อกับอีกเซอร์วิสหนึ่งหรือไม่?
ไม่จำเป็น บนเครือข่ายของ Compose ทุกพอร์ตของทุกคอนเทนเนอร์สามารถเข้าถึงได้โดยคอนเทนเนอร์อื่นๆ ที่อยู่บนเครือข่ายเดียวกัน ports: มีไว้เพื่อเปิดให้คอนเทนเนอร์รับทราฟฟิกจากภายนอก Docker เท่านั้น ส่วน expose: เป็นเพียงการระบุเอกสารประกอบ การเปิดพอร์ตฐานข้อมูลเป็นนิสัยที่พบบ่อยและมีความเสี่ยงสูง เนื่องจากเป็นการนำฐานข้อมูลไปวางไว้บนอินเทอร์เฟซสาธารณะของเซิร์ฟเวอร์คุณ
ความแตกต่างระหว่างเครือข่ายแบบ bridge และ host คืออะไร?
Bridge จะให้เนมสเปซเครือข่ายและที่อยู่ของตัวเองแก่คอนเทนเนอร์บนสวิตช์เสมือน พร้อมการแก้ไขชื่อระหว่างคอนเทนเนอร์โดยอัตโนมัติและการแปลทราฟฟิกขาออก ส่วน Host จะให้คอนเทนเนอร์ใช้สแต็กเครือข่ายของโฮสต์โดยตรง: ไม่มีที่อยู่แยกต่างหาก ไม่มีการแก้ไขชื่อผ่านชื่อเซอร์วิส ไม่มีการเปิดพอร์ต และไม่มีการแยกส่วนจากผู้ฟัง (listener) อื่นๆ บนโฮสต์ Bridge เป็นค่าเริ่มต้นและเป็นตัวเลือกที่เหมาะสมที่สุด เว้นแต่ว่าโปรเซสของคุณจำเป็นต้องใช้อินเทอร์เฟซของโฮสต์โดยตรง
ฉันจะเชื่อมต่อคอนเทนเนอร์จากไฟล์ Compose สองไฟล์ที่แตกต่างกันได้อย่างไร?
สร้างเครือข่ายที่ใช้ร่วมกันด้วย docker network create edge จากนั้นประกาศเครือข่ายดังกล่าวในไฟล์ทั้งสองด้วย external: true และเชื่อมต่อเซอร์วิสที่ต้องการสื่อสารกันเข้ากับเครือข่ายนั้น Compose จะไม่สร้างหรือลบเครือข่ายนี้ หากคุณข้ามขั้นตอนการสร้าง Compose จะปฏิเสธการทำงานและแจ้งว่าเครือข่ายถูกประกาศเป็นแบบ external แต่ไม่พบเครือข่ายดังกล่าว
เหตุใดคอนเทนเนอร์ของฉันจึงเข้าถึงได้จากอินเทอร์เน็ตทั้งที่ UFW บล็อกพอร์ตนั้นไว้?
เนื่องจากพอร์ตที่ถูกเปิดใช้งาน (published port) จะถูกจัดการโดยกฎการส่งต่อ (forwarding rules) ที่ Docker เพิ่มเข้าไปใน iptables กฎเหล่านั้นจะถูกตรวจสอบก่อนกฎของ UFW และทราฟฟิกที่ถูกส่งต่อจะไม่ผ่านเชนที่ UFW กรองอยู่แล้ว ให้ผูก (bind) ฝั่งโฮสต์เข้ากับ loopback ด้วย "127.0.0.1:8080:80" และวางบริการที่ต้องการเปิดเผยต่อสาธารณะไว้หลัง reverse proxy บนพอร์ต 80 และ 443 แทน