ไม่นานมานี้ ฉันต้องเผชิญกับงานที่ผิดปกติอย่างมากในการตั้งค่าการกำหนดเส้นทางสำหรับ MetalLB ทุกอย่างคงจะดีเพราะ... โดยปกติแล้ว MetalLB ไม่ต้องการการดำเนินการใดๆ เพิ่มเติม แต่ในกรณีของเรา เรามีคลัสเตอร์ที่ค่อนข้างใหญ่และมีการกำหนดค่าเครือข่ายที่ง่ายมาก
ในบทความนี้ ฉันจะบอกวิธีกำหนดค่าการกำหนดเส้นทางตามแหล่งที่มาและตามนโยบายสำหรับเครือข่ายภายนอกของคลัสเตอร์ของคุณ
ฉันจะไม่ลงรายละเอียดเกี่ยวกับการติดตั้งและกำหนดค่า MetalLB เนื่องจากฉันคิดว่าคุณมีประสบการณ์มาบ้างแล้ว ฉันแนะนำให้ตรงไปตรงประเด็นคือการตั้งค่าเส้นทาง ดังนั้นเราจึงมีสี่กรณี:
กรณีที่ 1: เมื่อไม่จำเป็นต้องกำหนดค่าใดๆ
ลองดูกรณีง่ายๆ
ไม่จำเป็นต้องมีการกำหนดค่าการกำหนดเส้นทางเพิ่มเติมเมื่อที่อยู่ที่ออกโดย MetalLB อยู่ในเครือข่ายย่อยเดียวกันกับที่อยู่ของโหนดของคุณ
ตัวอย่างเช่น คุณมีซับเน็ต 192.168.1.0/24
มันมีเราเตอร์ 192.168.1.1
และโหนดของคุณได้รับที่อยู่: 192.168.1.10-30
จากนั้นสำหรับ MetalLB คุณสามารถปรับช่วงได้ 192.168.1.100-120
และตรวจสอบให้แน่ใจว่าจะทำงานโดยไม่มีการกำหนดค่าเพิ่มเติม
ทำไมเป็นอย่างนั้น? เนื่องจากโหนดของคุณมีเส้นทางที่กำหนดค่าไว้แล้ว:
# ip route
default via 192.168.1.1 dev eth0 onlink
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10
และที่อยู่จากช่วงเดียวกันจะถูกนำมาใช้ซ้ำโดยไม่ต้องดำเนินการใดๆ เพิ่มเติม
กรณีที่ 2: เมื่อจำเป็นต้องปรับแต่งเพิ่มเติม
คุณควรกำหนดค่าเส้นทางเพิ่มเติมทุกครั้งที่โหนดของคุณไม่มีที่อยู่ IP ที่กำหนดค่าไว้ หรือกำหนดเส้นทางไปยังเครือข่ายย่อยที่ MetalLB ออกที่อยู่
ฉันจะอธิบายรายละเอียดเพิ่มเติมเล็กน้อย เมื่อใดก็ตามที่ MetalLB ส่งออกที่อยู่ ก็สามารถเปรียบเทียบได้กับการมอบหมายง่ายๆ เช่น:
ip addr add 10.9.8.7/32 dev lo
ให้ความสนใจกับ:
- a) ที่อยู่ถูกกำหนดด้วยคำนำหน้า
/32
นั่นคือเส้นทางจะไม่ถูกเพิ่มลงในเครือข่ายย่อยโดยอัตโนมัติ (เป็นเพียงที่อยู่) - b) ที่อยู่จะแนบไปกับอินเทอร์เฟซของโหนดใดๆ (เช่น ลูปแบ็ค) เป็นมูลค่าการกล่าวขวัญถึงคุณสมบัติของสแต็กเครือข่าย Linux ที่นี่ ไม่ว่าคุณจะเพิ่มที่อยู่ให้กับอินเทอร์เฟซใด เคอร์เนลจะประมวลผลคำขอ arp และส่งการตอบสนอง arp ไปยังคำขอใด ๆ เสมอ ลักษณะการทำงานนี้ถือว่าถูกต้องและยิ่งไปกว่านั้นยังใช้กันอย่างแพร่หลายในสภาพแวดล้อมแบบไดนามิกเช่น Kubernetes
พฤติกรรมนี้สามารถปรับแต่งได้ เช่น โดยการเปิดใช้งาน arp แบบเข้มงวด:
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
ในกรณีนี้ การตอบสนอง arp จะถูกส่งก็ต่อเมื่ออินเทอร์เฟซมีที่อยู่ IP ที่ระบุอย่างชัดเจนเท่านั้น จำเป็นต้องมีการตั้งค่านี้หากคุณวางแผนที่จะใช้ MetalLB และ kube-proxy ของคุณทำงานในโหมด IPVS
อย่างไรก็ตาม MetalLB ไม่ได้ใช้เคอร์เนลเพื่อประมวลผลคำขอ arp แต่ใช้เคอร์เนลเองในพื้นที่ผู้ใช้ ดังนั้นตัวเลือกนี้จะไม่ส่งผลต่อการทำงานของ MetalLB
กลับมาที่งานของเรากันดีกว่า หากไม่มีเส้นทางสำหรับที่อยู่ที่ออกไว้บนโหนดของคุณ ให้เพิ่มเส้นทางล่วงหน้าให้กับโหนดทั้งหมด:
ip route add 10.9.8.0/24 dev eth1
กรณีที่ 3: เมื่อคุณต้องการการกำหนดเส้นทางตามแหล่งที่มา
คุณจะต้องกำหนดค่าการกำหนดเส้นทางตามแหล่งที่มาเมื่อคุณได้รับแพ็กเก็ตผ่านเกตเวย์ที่แยกต่างหาก ไม่ใช่ที่กำหนดค่าไว้ตามค่าเริ่มต้น ดังนั้นแพ็กเก็ตการตอบกลับควรผ่านเกตเวย์เดียวกันด้วย
ตัวอย่างเช่น คุณมีเครือข่ายย่อยเดียวกัน 192.168.1.0/24
เฉพาะสำหรับโหนดของคุณ แต่คุณต้องการออกที่อยู่ภายนอกโดยใช้ MetalLB สมมติว่าคุณมีที่อยู่หลายแห่งจากเครือข่ายย่อย 1.2.3.0/24
ตั้งอยู่ใน VLAN 100 และคุณต้องการใช้เพื่อเข้าถึงบริการ Kubernetes จากภายนอก
เมื่อติดต่อ 1.2.3.4
คุณจะทำการร้องขอจากซับเน็ตอื่นที่ไม่ใช่ 1.2.3.0/24
และรอคำตอบ โหนดที่เป็นโหนดหลักในปัจจุบันสำหรับที่อยู่ที่ออกโดย MetalLB 1.2.3.4
จะได้รับแพ็กเก็ตจากเราเตอร์ 1.2.3.1
แต่คำตอบสำหรับเขาจะต้องไปในเส้นทางเดียวกันโดยผ่าน 1.2.3.1
.
เนื่องจากโหนดของเรามีเกตเวย์เริ่มต้นที่กำหนดค่าไว้แล้ว 192.168.1.1
จากนั้นตามค่าเริ่มต้นการตอบกลับจะไปหาเขา ไม่ใช่ไปที่ 1.2.3.1
ซึ่งเราได้รับพัสดุผ่านทางนั้น
จะรับมือกับสถานการณ์นี้ได้อย่างไร?
ในกรณีนี้ คุณต้องเตรียมโหนดทั้งหมดของคุณในลักษณะที่พร้อมให้บริการที่อยู่ภายนอกโดยไม่ต้องกำหนดค่าเพิ่มเติม นั่นคือ สำหรับตัวอย่างข้างต้น คุณต้องสร้างอินเทอร์เฟซ VLAN บนโหนดล่วงหน้า:
ip link add link eth0 name eth0.100 type vlan id 100
ip link set eth0.100 up
จากนั้นเพิ่มเส้นทาง:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100
โปรดทราบว่าเราได้เพิ่มเส้นทางลงในตารางเส้นทางแยกต่างหาก 100
จะมีเพียงสองเส้นทางที่จำเป็นในการส่งแพ็กเก็ตตอบกลับผ่านเกตเวย์ 1.2.3.1
ซึ่งอยู่ด้านหลังอินเทอร์เฟซ eth0.100
.
ตอนนี้เราต้องเพิ่มกฎง่ายๆ:
ip rule add from 1.2.3.0/24 lookup 100
ซึ่งระบุอย่างชัดเจนว่า: หากที่อยู่ต้นทางของแพ็กเก็ตอยู่ 1.2.3.0/24
จากนั้นคุณจะต้องใช้ตารางเส้นทาง 100
. ในนั้นเราได้บรรยายถึงเส้นทางที่จะส่งพระองค์ผ่านไปแล้ว 1.2.3.1
กรณีที่ 4: เมื่อคุณต้องการการกำหนดเส้นทางตามนโยบาย
โทโพโลยีเครือข่ายเหมือนกับในตัวอย่างก่อนหน้านี้ แต่สมมติว่าคุณต้องการเข้าถึงที่อยู่พูลภายนอกด้วย 1.2.3.0/24
จากพ็อดของคุณ:
ลักษณะเฉพาะคือเมื่อเข้าถึงที่อยู่ใด ๆ 1.2.3.0/24
แพ็กเก็ตตอบกลับจะไปถึงโหนดและมีที่อยู่ต้นทางในช่วง 1.2.3.0/24
จะถูกส่งไปอย่างเชื่อฟัง eth0.100
แต่เราต้องการให้ Kubernetes เปลี่ยนเส้นทางไปยังพ็อดแรกของเรา ซึ่งสร้างคำขอดั้งเดิม
การแก้ปัญหานี้กลายเป็นเรื่องยาก แต่ก็เป็นไปได้ด้วยการกำหนดเส้นทางตามนโยบาย:
เพื่อความเข้าใจที่ดีขึ้นของกระบวนการ นี่คือแผนภาพบล็อก netfilter:
ขั้นแรก ดังตัวอย่างก่อนหน้านี้ เรามาสร้างตารางเส้นทางเพิ่มเติมกัน:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100
ตอนนี้เรามาเพิ่มกฎสองสามข้อใน iptables:
iptables -t mangle -A PREROUTING -i eth0.100 -j CONNMARK --set-mark 0x100
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j RETURN
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
กฎเหล่านี้จะทำเครื่องหมายการเชื่อมต่อขาเข้าไปยังอินเทอร์เฟซ eth0.100
โดยทำเครื่องหมายแพ็กเก็ตทั้งหมดด้วยแท็ก 0x100
การตอบสนองภายในการเชื่อมต่อเดียวกันจะถูกทำเครื่องหมายด้วยแท็กเดียวกันด้วย
ตอนนี้เราสามารถเพิ่มกฎการกำหนดเส้นทางได้:
ip rule add from 1.2.3.0/24 fwmark 0x100 lookup 100
นั่นคือแพ็กเก็ตทั้งหมดที่มีที่อยู่ต้นทาง 1.2.3.0/24
และแท็ก 0x100
จะต้องกำหนดเส้นทางโดยใช้ตาราง 100
.
ดังนั้นแพ็กเก็ตอื่นๆ ที่ได้รับบนอินเทอร์เฟซอื่นจึงไม่อยู่ภายใต้กฎนี้ ซึ่งจะช่วยให้สามารถกำหนดเส้นทางโดยใช้เครื่องมือ Kubernetes มาตรฐานได้
มีอีกอย่างหนึ่ง ใน Linux มีสิ่งที่เรียกว่าตัวกรองเส้นทางย้อนกลับ ซึ่งทำให้เสียสิ่งทั้งหมด โดยทำการตรวจสอบง่ายๆ: สำหรับแพ็กเก็ตที่เข้ามาทั้งหมด มันจะเปลี่ยนที่อยู่ต้นทางของแพ็กเก็ตด้วยที่อยู่ผู้ส่งและตรวจสอบว่า แพ็กเก็ตสามารถออกจากอินเทอร์เฟซเดียวกันกับที่ได้รับ หากไม่เป็นเช่นนั้นก็จะกรองออก
ปัญหาคือในกรณีของเรามันจะทำงานไม่ถูกต้อง แต่เราสามารถปิดการใช้งานได้:
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0.100/rp_filter
โปรดทราบว่าคำสั่งแรกควบคุมลักษณะการทำงานทั่วโลกของ rp_filter หากไม่ได้ปิดใช้งาน คำสั่งที่สองจะไม่มีผลใดๆ อย่างไรก็ตาม อินเทอร์เฟซที่เหลือจะยังคงอยู่โดยเปิดใช้งาน rp_filter
เพื่อไม่ให้จำกัดการทำงานของตัวกรองอย่างสมบูรณ์ เราสามารถใช้ rp_filter การใช้งานสำหรับ netfilter การใช้ rpfilter เป็นโมดูล iptables คุณสามารถกำหนดค่ากฎที่ค่อนข้างยืดหยุ่นได้ เช่น:
iptables -t raw -A PREROUTING -i eth0.100 -d 1.2.3.0/24 -j RETURN
iptables -t raw -A PREROUTING -i eth0.100 -m rpfilter --invert -j DROP
เปิดใช้งาน rp_filter บนอินเทอร์เฟซ eth0.100
สำหรับที่อยู่ทั้งหมดยกเว้น 1.2.3.0/24
.
ที่มา: will.com