L2 模式下 MetalLB 的微調路由

L2 模式下 MetalLB 的微調路由
不久前,我面臨著一項非常不尋常的任務,即為 MetalLB 設定路由。一切都會好起來的,因為…通常 MetalLB 不需要任何額外的操作,但在我們的例子中,我們有一個相當大的集群,網路配置非常簡單。

在本文中,我將告訴您如何為叢集的外部網路配置基於來源和基於策略的路由。

我不會詳細介紹 MetalLB 的安裝和配置,因為我假設您已經有一些經驗。我建議開門見山,即設定路由。所以我們有四種情況:

情況一:無需配置時

我們來看一個簡單的案例。

L2 模式下 MetalLB 的微調路由

當 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:需要額外客製化時

L2 模式下 MetalLB 的微調路由

只要您的節點沒有配置 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

在這種情況下,僅當介面明確包含特定 IP 位址時才會傳送 arp 回應。如果您打算使用 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 服務。

L2 模式下 MetalLB 的微調路由

聯繫時 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 從您的 pod 中:

L2 模式下 MetalLB 的微調路由

特殊之處在於,當訪問任何地址時 1.2.3.0/24,響應資料包到達節點並且來源位址在範圍內 1.2.3.0/24 會乖乖的送到 eth0.100,但我們希望 Kubernetes 將其重定向到我們的第一個 pod,該 pod 產生了原始請求。

解決這個問題被證明是困難的,但是由於基於策略的路由,它變得可能:

為了更好地理解該過程,以下是 netfilter 框圖:
L2 模式下 MetalLB 的微調路由

首先,像前面的範例一樣,讓我們建立一個額外的路由表:

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 的狀態。

為了不完全限制過濾器的操作,我們可以使用netfilter的rp_filter實作。使用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.

來源: www.habr.com

添加評論