

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在 IPVS 模式下執行 kube-proxy
<a name="ipvs"></a>

IP Virtual Server (IPVS) 模式下的 EKS 解決了在舊版 iptables 模式下執行超過 1，000 個 kube-proxy 服務的大型叢集時常見的[網路延遲問題](https://docs.aws.amazon.com/eks/latest/best-practices/control-plane.html#reliability_cprunning_large_clusters)。此效能問題是針對每個封包依序處理 iptables 封包篩選規則的結果。此延遲問題已在 nftables 中解決，這是 iptable 的後繼。不過，截至撰寫本文時，[kube-proxy 仍在開發](https://kubernetes.io/docs/reference/networking/virtual-ips/#proxy-mode-nftables)中，以利用 nftable。若要解決此問題，您可以將叢集設定為`kube-proxy`在 IPVS 模式下執行。

## 概觀
<a name="_overview"></a>

IPVS 自 [Kubernetes 1.11 版起即為 GA](https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive/)，使用雜湊表而非線性搜尋來處理封包，為具有數千個節點和服務的叢集提供效率。IPVS 專為負載平衡而設計，使其成為 Kubernetes 網路效能問題的適當解決方案。

IPVS 提供多種選項，可將流量分配到後端 Pod。您可以在[官方 Kubernetes 文件](https://kubernetes.io/docs/reference/networking/virtual-ips/#proxy-mode-ipvs)中找到每個選項的詳細資訊，但簡單的清單如下所示。Round Robin 和 Least Connections 是 Kubernetes 中 IPVS 負載平衡選項最常見的選項之一。

```
- rr (Round Robin)
- wrr (Weighted Round Robin)
- lc (Least Connections)
- wlc (Weighted Least Connections)
- lblc (Locality Based Least Connections)
- lblcr (Locality Based Least Connections with Replication)
- sh (Source Hashing)
- dh (Destination Hashing)
- sed (Shortest Expected Delay)
- nq (Never Queue)
```

### 實作
<a name="_implementation"></a>

在 EKS 叢集中啟用 IPVS 只需要幾個步驟。您需要做的第一件事是確保您的 EKS 工作者節點映像已安裝 Linux Virtual Server 管理`ipvsadm`套件。若要在 Amazon Linux 2023 等以 Fedora 為基礎的映像上安裝此套件，您可以在工作者節點執行個體上執行下列命令。

```
sudo dnf install -y ipvsadm
```

在以 Debian 為基礎的映像上，例如 Ubuntu，安裝命令看起來會像這樣。

```
sudo apt-get install ipvsadm
```

接著，您需要載入上列 IPVS 組態選項的核心模組。我們建議將這些模組寫入 `/etc/modules-load.d/`目錄內的檔案，使其在重新開機後仍然存活。

```
sudo sh -c 'cat << EOF > /etc/modules-load.d/ipvs.conf
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_lc
ip_vs_wlc
ip_vs_lblc
ip_vs_lblcr
ip_vs_sh
ip_vs_dh
ip_vs_sed
ip_vs_nq
nf_conntrack
EOF'
```

您可以執行下列命令，在已執行 的機器上載入這些模組。

```
sudo modprobe ip_vs
sudo modprobe ip_vs_rr
sudo modprobe ip_vs_wrr
sudo modprobe ip_vs_lc
sudo modprobe ip_vs_wlc
sudo modprobe ip_vs_lblc
sudo modprobe ip_vs_lblcr
sudo modprobe ip_vs_sh
sudo modprobe ip_vs_dh
sudo modprobe ip_vs_sed
sudo modprobe ip_vs_nq
sudo modprobe nf_conntrack
```

**注意**  
強烈建議您透過[使用者資料指令碼](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html)或執行的任何建置指令碼執行這些工作者節點步驟，做為工作者節點引導程序的一部分，以建置自訂工作者節點 AMI。

接著，您將設定叢集的 `kube-proxy` DaemonSet 以 IPVS 模式執行。方法是將 `kube-proxy` `mode` 設定為 ，`ipvs`並將 `ipvs scheduler`設定為上述其中一個負載平衡選項，例如：`rr`適用於 Round Robin。

**警告**  
這是破壞性變更，應該在非上班時間執行。我們建議在初始 EKS 叢集建立期間進行這些變更，以將影響降至最低。

您可以更新 EKS 附加元件，發出 AWS CLI `kube-proxy` 命令來啟用 IPVS。

```
aws eks update-addon --cluster-name $CLUSTER_NAME --addon-name kube-proxy \
  --configuration-values '{"ipvs": {"scheduler": "rr"}, "mode": "ipvs"}' \
  --resolve-conflicts OVERWRITE
```

或者，您也可以修改叢集中的 `kube-proxy-config` ConfigMap 來執行此操作。

```
kubectl -n kube-system edit cm kube-proxy-config
```

尋找下方的`scheduler`設定`ipvs`，並將 值設定為上述其中一個 ipvs 負載平衡選項，例如：`rr`適用於 Round Robin。尋找預設為 `mode`的設定`iptables`，並將值變更為 `ipvs`。任一選項的結果都應該類似於以下組態。

```
  iptables:
    masqueradeAll: false
    masqueradeBit: 14
    minSyncPeriod: 0s
    syncPeriod: 30s
  ipvs:
    excludeCIDRs: null
    minSyncPeriod: 0s
    scheduler: "rr"
    syncPeriod: 30s
  kind: KubeProxyConfiguration
  metricsBindAddress: 0.0.0.0:10249
  mode: "ipvs"
  nodePortAddresses: null
  oomScoreAdj: -998
  portRange: ""
  udpIdleTimeout: 250ms
```

如果您的工作者節點在進行這些變更之前已加入叢集，您將需要重新啟動 kube-proxy DaemonSet。

```
kubectl -n kube-system rollout restart ds kube-proxy
```

### 驗證
<a name="_validation"></a>

您可以在其中一個工作者節點上發出下列命令，以驗證叢集和工作者節點是否在 IPVS 模式下執行。

```
sudo ipvsadm -L
```

您至少應該會看到類似以下的結果，顯示位於 的 Kubernetes API Server 服務項目，`10.100.0.1`以及位於 的 CoreDNS 服務項目`10.100.0.10`。

```
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  ip-10-100-0-1.us-east-1. rr
  -> ip-192-168-113-81.us-eas Masq        1      0          0
  -> ip-192-168-162-166.us-ea Masq        1      1          0
TCP  ip-10-100-0-10.us-east-1 rr
  -> ip-192-168-104-215.us-ea Masq        1      0          0
  -> ip-192-168-123-227.us-ea Masq        1      0          0
UDP  ip-10-100-0-10.us-east-1 rr
  -> ip-192-168-104-215.us-ea Masq        1      0          0
  -> ip-192-168-123-227.us-ea Masq        1      0          0
```

**注意**  
此範例輸出來自服務 IP 地址範圍為 的 EKS 叢集`10.100.0.0/16`。