

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

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

IP 虚拟服务器 (IPVS) 模式下的 EKS 解决了运行拥有 1,000 多个服务的大型集群时经常出现的[网络延迟问题](https://docs.aws.amazon.com/eks/latest/best-practices/control-plane.html#reliability_cprunning_large_clusters)，kube-proxy 在传统 iptables 模式下运行。此性能问题是按顺序处理每个数据包的 iptables 数据包过滤规则所致。这个延迟问题已在 iptables 的继任者 nftables 中得到解决。但是，截至撰写本文时，[kube-proxy 仍在开发中](https://kubernetes.io/docs/reference/networking/virtual-ips/#proxy-mode-nftables)，以利用 nftables。要解决此问题，您可以将集群配置为`kube-proxy`在 IPVS 模式下运行。

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

IPVS 自 [Kubernetes 1.11 版本](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)中找到，但下面显示了一个简单的列表。循环和最少连接是 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 虚拟服务器管理`ipvsadm`软件包。要在基于 Fedora 的映像（例如 Amazon Linux 2023）上安装此软件包，您可以在工作节点实例上运行以下命令。

```
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 模式下运行。这是通过将 to `ipvs` 和 to 设置`kube-proxy``mode`为上面列出的负载平衡选项之一`ipvs scheduler`来完成的，`rr`例如：对于 Round Robin。

**警告**  
这是一种破坏性的更改，应在非工作时间执行。我们建议在初始创建 EKS 集群时进行这些更改，以最大限度地减少影响。

您可以通过更新 E `kube-proxy` KS 插件来发出 AWS CLI 命令来启用 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 DaemonSet-proxy。

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

### 验证
<a name="_validation"></a>

您可以通过在其中一个工作节点上发出以下命令来验证您的集群和工作节点是否在 IPVS 模式下运行。

```
sudo ipvsadm -L
```

至少，您应该会看到与以下结果相似的结果，其中显示了 Kubernetes API 服务器服务的条目，网址为 CoreDNS 服务的条目。`10.100.0.1` `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`。