คอนเทนเนอร์ที่มีสองเครือข่ายเลือกเกตเวย์ผิด
สองการเชื่อมต่อ หนึ่งเส้นทางเริ่มต้น และเครือข่ายที่ผิดชนะทุกครั้ง ปักหมุดทางออกด้วย Compose gw_priority และยืนยันจากภายในคอนเทนเนอร์
คอนเทนเนอร์ของคุณยังตอบสนองบนบริดจ์ควบคุม แต่ทุกแพ็กเก็ตขาออกออกผ่าน macvlan ของสำนักงาน ไม่มีอะไรล้มเหลว สองการเชื่อมต่อให้เกตเวย์แต่ละอัน และเส้นทางเริ่มต้นเพียงเส้นเดียวไปยังเครือข่ายที่คุณไม่ได้ตั้งใจ บริการจึงยังทำงานอยู่แต่การรับส่งข้อมูลต้องเดินทางไกลขึ้น เมื่อมีคนสังเกตเห็น หลักฐานคือตารางเส้นทาง ไม่ใช่ข้อความแสดงข้อผิดพลาด
คำอธิบายทั่วไปคือ Docker เลือกเครือข่ายโดยบังเอิญ ในทางปฏิบัติการตัดสินใจเดิมเป็นไปตามลำดับตัวอักษรของชื่อเครือข่ายที่เชื่อมต่อ ซึ่งทำให้การกำหนดเส้นทางเป็นผลข้างเคียงของป้ายชื่อ gw_priority แทนที่ด้วยตัวเลขที่คุณเลือกอย่างตั้งใจ และการนำมาใช้ใช้เวลาประมาณหนึ่งนาทีเมื่อเขียนผังเรียบร้อยแล้ว
ทำไมเส้นทางเริ่มต้นจึงไปตกบนเครือข่ายที่ผิด
ทุกเครือข่ายที่บริการเข้าร่วมสามารถเสนอเกตเวย์ของตนเองได้ แต่คอนเทนเนอร์ยังคงมีเส้นทางเริ่มต้นเพียงหนึ่งเดียวเท่านั้น ก่อน Compose 2.33.1 การเสมอกันถูกตัดสินด้วยการเรียงชื่อเครือข่าย ป้ายอย่าง control ที่มาก่อน office จึงเป็นตัวกำหนดว่าทราฟฟิกจะไปที่ไหน ไม่มีสิ่งใดภายในคอนเทนเนอร์บันทึกว่าการตัดสินใจนั้นเป็นไปตามอำเภอใจ จึงผ่านการรีวิวโค้ดและปรากฏภายหลังเป็นเส้นทางที่แปลก การวางนโยบายไว้ในไฟล์ compose เป็นวิธีเดียวที่จะทำให้การเลือกตรวจสอบได้
มีสองสิ่งที่มีผลจริงต่อว่าเครือข่ายใดจะชนะ: ค่า gw_priority ที่คุณกำหนด และเครือข่ายใดที่ถูกเชื่อมต่ออยู่จริง เพิ่มเครือข่ายที่สามชุดผู้สมัครก็ใหญ่ขึ้น ถอด macvlan ออกก็ไม่เหลือสิ่งใดให้แข่งกับบริดจ์ ทั้งสองอย่างไม่ปรากฏในล็อกของแอปพลิเคชัน เพราะเส้นทางเริ่มต้นที่ผิดแทบไม่ทำให้การเชื่อมต่อขาดหายทั้งหมด มันเพียงทำให้คำตอบมาจากที่อยู่ที่อีกฝ่ายอาจไม่คาดคิด
ปักหมุดเกตเวย์ด้วย gw_priority
Compose เปิดเผย gw_priority บนทุกการเชื่อมต่อบริการ-สู่-เครือข่ายตั้งแต่เวอร์ชัน 2.33.1 และตัวเลขที่สูงที่สุดชนะ ไม่มีคีย์เกตเวย์แยกตามบริการ ค่าจึงอยู่ในบล็อก networks ของบริการนั้น ตัวอย่างด้านล่างยกเส้นทางเริ่มต้นให้ control โดย office ยังเข้าถึงได้สำหรับ LAN ที่เชื่อมต่อโดยตรง
services:
vpn:
networks:
control:
gw_priority: 1
office:
gw_priority: 0
networks:
control:
driver: bridge
ipam:
config:
- subnet: 172.30.50.0/24
office:
driver: macvlan
driver_opts:
parent: eno1.120
macvlan_mode: bridge
ipam:
config:
- subnet: 192.168.120.0/24
ip_range: 192.168.120.192/27
gateway: 192.168.120.1
อ่านบล็อกนี้เป็นสองการควบคุมแยกกัน: gw_priority กำหนดเส้นทางเริ่มต้น และส่วน ipam กำหนดที่อยู่ การเปลี่ยนเฉพาะ subnet ทำให้การเลือกทางออกไม่ถูกแตะต้อง และนี่คือวิธีที่พบบ่อยที่สุดที่การแก้ไขนี้ถูกใช้เพียงครึ่งเดียว เก็บลำดับความสำคัญไว้ข้างเครือข่ายที่มันควบคุม เพื่อให้ผู้อ่านคนถัดไปไม่ต้องตามหาการตัดสินใจ
อย่าสับสน gw_priority กับคุณสมบัติ priority ธรรมดาที่อยู่ข้าง ๆ คุณสมบัตินั้นจัดลำดับการสร้างการเชื่อมต่อและไม่พูดถึงการกำหนดเส้นทางเลย จึงเลือกเกตเวย์เริ่มต้นไม่ได้และไม่ได้แก้ชื่ออินเทอร์เฟซ หากมีคนแนะนำให้เพิ่ม priority เพื่อบังคับทิศทางทราฟฟิก คำแนะนำนั้นผิดแม้ลำดับที่ได้จะดูถูกต้องโดยบังเอิญ
ตรวจสอบว่าเครือข่ายใดแบกเส้นทางเริ่มต้นจริง
ตรวจสอบภายในคอนเทนเนอร์ที่กำลังทำงาน เพราะตารางเส้นทางของโฮสต์อธิบายโฮสต์ ไม่ใช่เนมสเปซที่บริการใช้ รันการตรวจสอบคอนฟิกก่อนเพื่อให้พิมพ์ผิดล้มเหลวก่อนรีสตาร์ท แล้วอ่านเส้นทางที่คอนเทนเนอร์ติดตั้งจริง
docker compose config --quiet
docker exec vpn ip -4 route show default
docker exec vpn cat /proc/net/route
ผลลัพธ์ที่ถูกต้องระบุอุปกรณ์บริดจ์และ 172.30.50.1 ผลลัพธ์ที่ผิดระบุ 192.168.120.1 และอุปกรณ์ macvlan หากอิมเมจไม่มีแพ็กเกจ iproute2 ไฟล์ /proc ยังรายงานเส้นทางเริ่มต้น โดยปลายทางเป็น 00000000 และไบต์ของเกตเวย์กลับด้าน เปรียบเทียบคอลัมน์อินเทอร์เฟซกับ docker inspect เมื่อชื่ออุปกรณ์ไม่ชัดเจน
macvlan คือพอร์ตกายภาพ ไม่ใช่สำเนาของบริดจ์
macvlan ให้คอนเทนเนอร์มีอัตลักษณ์ที่สองบนสาย และนั่นคือสิ่งที่ทำให้การเข้าถึงอุปกรณ์ในเครื่องทำงานได้ นอกจากนี้ยังหมายความว่าพอร์ตสวิตช์และไฮเปอร์ไวเซอร์ต้องยอมรับที่อยู่ MAC เพิ่มเติม และเครือข่ายคลาวด์จำนวนมากปฏิเสธอย่างเงียบ ๆ ทดสอบคอนเทนเนอร์เดียว ก่อนวางแผนทั้งฝูง เพราะ MAC ที่ถูกปฏิเสธมักปรากฏเป็นลิงก์ที่ขึ้นอยู่แต่ไม่ผ่านอะไรเลย
การตั้งค่า macvlan_mode: bridge เป็นโหมดของไดรเวอร์ macvlan ไม่ใช่บริดจ์ซอฟต์แวร์ของ Docker และ passthru เป็นโหมดเฉพาะแยกต่างหาก ไม่ใช่ค่าเริ่มต้นลินุกซ์ยังป้องกันไม่ให้คอนเทนเนอร์ macvlan เข้าถึงโฮสต์ของตัวเอง ผ่านพาเรนต์เดียวกัน และนั่นคือเหตุผลที่เก็บบริดจ์ควบคุมไว้แทนที่จะคาดหวังให้การเชื่อมต่อเดียวทำทั้งสองหน้าที่
ตั้งชื่อพาเรนต์ VLAN ก่อนที่ Compose จะเห็นมัน
Docker ถือว่าพาเรนต์ที่มีจุดอย่าง eno1.120 เป็นซับอินเทอร์เฟซ 802.1Q และสร้างอุปกรณ์ VLAN เอง ความสะดวกนั้นมีขีดจำกัด: ชื่อที่ได้ขึ้นกับชื่ออินเทอร์เฟซกายภาพ และชื่อยาวอาจดันผลลัพธ์เกินกว่าที่เครื่องมือรอบข้างคาดหวัง การสร้างอินเทอร์เฟซ VLAN ที่มีชื่อในการกำหนดค่าเครือข่ายของโฮสต์และชี้ parent ไปที่มันทำให้ทั้งสองปลายคาดเดาได้
จำไว้ว่าคีย์ใต้ networks เป็นชื่อ Compose ไม่ใช่อุปกรณ์ลินุกซ์ การค้นหาอินเทอร์เฟซชื่อ office บนโฮสต์จะล้มเหลว เพราะเคอร์เนลเห็นเพียงอินเทอร์เฟซพาเรนต์และคู่ veth ที่อยู่หลังคอนเทนเนอร์
เผื่อที่ให้ VPN ไว้ด้านบน
ไคลเอนต์ VPN เชื่อมต่อหลังจากเครือข่ายเหล่านี้มีอยู่แล้ว จึงเพิ่มเส้นทางที่เฉพาะเจาะจงกว่า กฎนโยบาย และตัวกรองได้โดยไม่ขึ้นกับ gw_priority วางแผนพรีฟิกซ์ระยะไกลเทียบกับ subnet ทั้งสองภายในเครื่อง รวมถึงคำตอบที่เส้นทางควบคุมต้องการ เมื่อพรีฟิกซ์ระยะไกลทับซ้อนกับ LAN ของสำนักงาน ให้แก้แผนที่อยู่แทนการดึงช่วงส่วนตัวทั้งหมดออกจากอุโมงค์
ตรวจสอบที่อยู่ เส้นทาง และเส้นทางของบริการอีกครั้งหลัง VPN เริ่มทำงาน และอีกครั้งหลังเชื่อมต่อใหม่ เพราะการเชื่อมต่อใหม่คือจุดที่เส้นทางที่เพิ่มด้วยมือหายไป จดตารางที่คาดหวังไว้ก่อนการทดสอบครั้งแรก เพื่อให้การเปรียบเทียบภายหลังเป็น diff ไม่ใช่การฝึกความจำ เก็บความเป็นเจ้าของเครือข่ายถาวรไว้ใน Compose และปล่อยให้การกำหนดค่า VPN เป็นเจ้าของเฉพาะนโยบายของตัวเอง