|
1 | 1 | # 单台物理机最大运行 pod 数量的最佳实践
|
2 | 2 |
|
3 |
| -本文介绍了如何为集群上运行的节点配置最大运行 pod 数量的最佳实践。包括资源规划、配置更改、测试过程及结果、节点故障迁移问题和实施建议。 |
4 |
| - |
5 |
| -# 资源规划 |
| 3 | +本文介绍了如何为集群上运行的节点配置最大运行 Pod 数量的最佳实践。包括资源规划、配置更改、测试过程及结果、节点故障迁移问题和实施建议。 |
6 | 4 |
|
7 | 5 | ## 硬件配置
|
8 | 6 |
|
9 |
| -- 3vm作为工作集群k8s主节点规格:8C 16G 硬盘100G |
10 |
| - |
11 |
| -- 1台物理机作为工作集群k8s节点:80C 512G |
12 |
| - |
| 7 | +- 3vm 作为工作集群 k8s 主节点规格:8C 16G 硬盘 100G |
| 8 | +- 1 台物理机作为工作集群 k8s 节点:80C 512G |
13 | 9 | - os: oracle Linux 9.5
|
14 | 10 |
|
15 | 11 | ## 其他配置调优
|
16 | 12 |
|
17 | 13 | ### 系统参数
|
18 | 14 |
|
19 |
| -``` |
| 15 | +```bash |
20 | 16 | sysctl -w fs.inotify.max_user_watches=655360
|
21 | 17 | sysctl -w fs.inotify.max_user_instances=81920
|
22 | 18 | sysctl -w fs.inotify.max_queued_events=655360
|
23 | 19 | ```
|
| 20 | + |
24 | 21 | ### kubelet
|
25 | 22 |
|
| 23 | +```yaml |
| 24 | +- eventBurst: 100 # 默认 100 |
| 25 | +- eventRecordQPS: 50 # 默认 50 |
| 26 | +- maxPods: 800 # 默认 110 |
| 27 | +- podsPerCore: 10 # 默认值 0,每个核心的最大 Pod 数量 |
| 28 | +- serializeImagePulls: false # 关闭串行拉取镜像 |
| 29 | +- maxParallelImagePulls: 10 # 最大并行拉取镜像数量,是作为提高创建 Pod QPS |
26 | 30 | ```
|
27 |
| -- eventBurst: 100 #默认100 |
28 |
| -- eventRecordQPS: 50 #默认50 |
29 |
| -- maxPods: 800 #默认110 |
30 |
| -- podsPerCore: 10 #默认值0,每个核心的最大 Pod 数量 |
31 |
| -- serializeImagePulls: false #关闭串行拉取镜像 |
32 |
| -- maxParallelImagePulls: 10 #最大并行拉取镜像数量,是作为提高创建Pod QPS |
33 | 31 |
|
34 |
| -``` |
35 |
| -### Containerd |
| 32 | +### containerd |
36 | 33 |
|
37 | 34 | ```
|
38 | 35 | # /etc/containerd/config.toml
|
39 | 36 | [plugins."io.containerd.grpc.v1.cri"]
|
40 | 37 | max_concurrent_downloads = 10 #并发镜像下载数 (默认 3),需要合理评估
|
41 | 38 | ```
|
| 39 | + |
42 | 40 | ### kube-apiserver
|
43 | 41 |
|
44 |
| -``` |
45 |
| ---max-requests-inflight=4000 #提升并发请求数 (默认 400) |
46 |
| ---max-mutating-requests-inflight=2000 #提升写请求并发 (默认 200) |
47 |
| ---watch-cache=true #开启watch 缓存 |
48 |
| ---watch-cache-sizes=pod#1000 #提高 watch 缓存容量 |
49 |
| ---http2-max-streams-per-connection=1000 #提升 HTTP/2 流数量,golang 默认值是250 |
| 42 | +```yaml |
| 43 | +--max-requests-inflight=4000 # 提升并发请求数 (默认 400) |
| 44 | +--max-mutating-requests-inflight=2000 # 提升写请求并发 (默认 200) |
| 45 | +--watch-cache=true # 开启watch 缓存 |
| 46 | +--watch-cache-sizes=pod#1000 # 提高 watch 缓存容量 |
| 47 | +--http2-max-streams-per-connection=1000 # 提升 HTTP/2 流数量,golang 默认值是250 |
50 | 48 | ```
|
51 | 49 |
|
52 | 50 | ### kube-controller-manager
|
53 | 51 |
|
54 |
| -``` |
55 |
| ---concurrent-service-syncs=10 #默认值1 |
56 |
| ---concurrent-deployment-syncs=50 #默认值5 |
57 |
| ---concurrent-replicaset-syncs=50 #默认值5 |
| 52 | +```yaml |
| 53 | +--concurrent-service-syncs=10 # 默认值1 |
| 54 | +--concurrent-deployment-syncs=50 # 默认值5 |
| 55 | +--concurrent-replicaset-syncs=50 # 默认值5 |
58 | 56 | --http2-max-streams-per-connection=1000 # 提升 HTTP/2 流数量(非必须)
|
59 | 57 | ```
|
60 | 58 |
|
61 | 59 | ### kube-scheduler
|
62 | 60 |
|
63 |
| -``` |
64 |
| ---http2-max-streams-per-connection=1000 #提升 HTTP/2 流数量(非必须) |
| 61 | +```yaml |
| 62 | +--http2-max-streams-per-connection=1000 # 提升 HTTP/2 流数量(非必须) |
65 | 63 | ```
|
66 | 64 |
|
67 | 65 | ### 网络配置
|
68 | 66 |
|
69 | 67 | #### Calico 调优
|
70 | 68 |
|
71 | 69 | 1. 配置 IPPool 中 ipipMode 为 CrossSubnet,vxlanMode 为 Never
|
72 |
| - |
73 |
| -2. 设置 Calico-node 资源限制: CPU 2C,Memory 1G |
74 |
| - |
75 |
| -3. Calico 基于周期触发和事件触发两种机制来更新 Iptables 和 ipset 规则,建议做如下调整,减少 CPU 消耗增大 iptabels 周期触发更新策略间隔 iptablesRefreshInterval=30s (默认为 10 s)增大 ipset 周期触发更新策略间隔 ipsetsRefreshInterval=120s (默认为 90 s) |
76 |
| - |
77 |
| -4. 确保 calico-node 环境变量 IPTABLES_BACKEND=Auto, calico-node 在高内核下(> 3.13)会使用正确的 iptables-nft 模式 |
78 |
| - |
79 |
| -5. 设置 IP 池子网大小为 16 位掩码, BlockSize 为 26,避免 IP 不够分配 |
80 |
| - |
| 70 | + |
| 71 | + ```bash |
| 72 | + calicoctl patch ippool default-ippool -p '{"spec": {"ipipMode": "CrossSubnet","vxlanMode": "Never"}}' |
| 73 | + ``` |
| 74 | + |
| 75 | +2. 设置 Calico-node 的最低资源限制:CPU 2C,Memory 1G |
| 76 | + |
| 77 | +3. Calico 基于周期触发和事件触发两种机制来更新 Iptables 和 ipset 规则,建议做如下调整, |
| 78 | + 减少 CPU 消耗增大 iptabels 周期触发更新策略间隔 iptablesRefreshInterval=30s |
| 79 | + (默认为 10 s)增大 ipset 周期触发更新策略间隔 ipsetsRefreshInterval=120s (默认为 90s) |
| 80 | + |
| 81 | + ```bash |
| 82 | + calicoctl patch felixconfiguration default -p '{"spec": {"iptablesRefreshInterval": "30s","ipsetsRefreshInterval": "120s"}}' |
| 83 | + ``` |
| 84 | + |
| 85 | +4. 确保 calico-node 环境变量 IPTABLES_BACKEND=Auto,calico-node 在高内核下(> 3.13)会使用正确的 iptables-nft 模式 |
| 86 | + |
| 87 | + ```bash |
| 88 | + kubectl set env daemonSet/calico-node -n kube-system FELIX_IPTABLESBACKEND=Auto |
| 89 | + ``` |
| 90 | + |
| 91 | +5. 设置 IP 池子网大小为 16 位掩码,BlockSize 为 26,避免 IP 不够分配。 |
| 92 | + |
| 93 | + > 必须在安装集群时设置,IP 池创建后子网大小和 BlockSize 不可更改。 |
| 94 | + |
81 | 95 | 6. 大规模下节点主机内核网络参数调优
|
82 |
| - |
83 |
| - 在大规模 Kubernetes 集群中,节点配置的优化对于确保集群的稳定性、性能和可扩展性至关重要 |
84 |
| - |
85 | 96 |
|
86 |
| -| Sysctl | node | |
87 |
| -| -------- | -------- | |
88 |
| -| net.ipv4.neigh.default.gc_thresh1=0 <br> net.ipv4.neigh.default.gc_thresh2=512 <br> net.ipv4.neigh.default.gc_thresh3=8192 <br> net.ipv6.neigh.default.gc_thresh1=0 <br> net.ipv6.neigh.default.gc_thresh2=512 <br> net.ipv6.neigh.default.gc_thresh3=8192 | arp邻居表最小保留数目。Underlay 场景中, Spiderpool 会自动调整 | |
89 |
| -| net.ipv4.ip_local_port_range=1024 65535 | 设置本地源端口范围 | |
90 |
| -| net.netfilter.nf_conntrack_max=1048576 | netfilter 最大连接跟踪条目数量 | |
91 |
| -|net.core.somaxconn=32768 |设置系统中每个监听套接字的最大连接数 | |
| 97 | +在大规模 Kubernetes 集群中,节点配置的优化对于确保集群的稳定性、性能和可扩展性至关重要 |
| 98 | + |
| 99 | +| Sysctl | Node | |
| 100 | +| ------ | ---- | |
| 101 | +| net.ipv4.neigh.default.gc_thresh1=0 <br> net.ipv4.neigh.default.gc_thresh2=512 <br> net.ipv4.neigh.default.gc_thresh3=8192 <br> net.ipv6.neigh.default.gc_thresh1=0 <br> net.ipv6.neigh.default.gc_thresh2=512 <br> net.ipv6.neigh.default.gc_thresh3=8192 | arp 邻居表最小保留数目。Underlay 场景中,Spiderpool 会自动调整 | |
| 102 | +| net.ipv4.ip_local_port_range=1024 65535 | 设置本地源端口范围 | |
| 103 | +| net.netfilter.nf_conntrack_max=1048576 | netfilter 最大连接跟踪条目数量 | |
| 104 | +| net.core.somaxconn=32768 | 设置系统中每个监听套接字的最大连接数 | |
92 | 105 |
|
93 |
| -#### Kube-proxy 调优 |
| 106 | +#### kube-proxy 调优 |
94 | 107 |
|
95 |
| -1. mode 切换到 IPVS 模式 |
96 |
| - |
97 |
| -2. 优化规则同步策略(sync): minSyncPeriod 为 1s。 |
| 108 | +1. 编辑 kube-proxy configMap,设置 mode 为 ipvs |
98 | 109 |
|
99 |
| - |
| 110 | +2. 编辑 kube-proxy configMap,设置 ipvs 的 minSyncPeriod 为 1s。 |
| 111 | + |
| 112 | +  |
100 | 113 |
|
101 | 114 | !!! note
|
102 | 115 |
|
103 |
| - 作用:minSyncPeriod 尝试同步 iptables 规则与内核之间的最短时长。 默认值: 0s,则任何 Service 和 Endpoint 发送变化, kube-proxy 都会马上更新规则。 |
| 116 | + 作用:minSyncPeriod 尝试同步 iptables 规则与内核之间的最短时长。 默认值:0s, |
| 117 | + 则任何 Service 和 Endpoint 发送变化,kube-proxy 都会马上更新规则。 |
| 118 | + |
104 | 119 | 建议值:默认值 1s 适用于大多数集群,在大型集群中,可能需要将其设置为更大的值。
|
105 |
| - 调优依据:观察 kube-proxy 的 sync_proxy_rules_duration_seconds 指标表明平均时间远大于 1 秒, 那么提高 minSyncPeriod 可能会更有意义。 |
| 120 | + |
| 121 | + 调优依据:观察 kube-proxy 的 sync_proxy_rules_duration_seconds 指标表明平均时间远大于 1 秒, |
| 122 | + 那么提高 minSyncPeriod 可能会更有意义。 |
106 | 123 |
|
107 | 124 | ## 测试过程及结果
|
108 | 125 |
|
109 |
| -多个ns(平均每个ns下5个pod)下逐步创建400-800个nginx pod。测试每批 pod 的创建到就绪的时长,以及创建完成后整个平台的稳定性和性能。 |
| 126 | +多个 ns(平均每个 ns 下 5 个 Pod)下逐步创建 400-800 个 nginx Pod。 |
| 127 | +测试每批 Pod 的创建到就绪的时长,以及创建完成后整个平台的稳定性和性能。 |
110 | 128 |
|
111 |
| -- 操作系统优化参数:Kubelet 、ETCD、kube-apiserver、kube-controller-manager、kube-scheduler、Containerd、fluent-bit、Prometheus 等K8S组件参数调优 |
112 |
| - |
113 |
| -- Kube-proxy、calico 等网络组件调优参数 |
| 129 | +- 操作系统优化参数:kubelet、ETCD、kube-apiserver、kube-controller-manager、kube-scheduler、containerd、fluent-bit、Prometheus 等 K8s 组件参数调优 |
| 130 | +- kube-proxy、calico 等网络组件调优参数 |
114 | 131 |
|
115 | 132 | ### 测试脚本
|
116 | 133 |
|
117 |
| -deploy-to-ns.sh 部署脚本,控制每个deployment的replicas即可。 |
| 134 | +部署以下脚本,控制每个 Deployment 的 Replicas。 |
118 | 135 |
|
119 |
| - |
120 |
| -``` |
| 136 | +```bash title="deploy-to-ns.sh" |
121 | 137 | #!/bin/bash
|
122 | 138 |
|
123 | 139 | # 定义命名空间前缀和数量
|
@@ -209,45 +225,46 @@ done
|
209 | 225 |
|
210 | 226 | echo "操作完成!"
|
211 | 227 | ```
|
| 228 | + |
212 | 229 | ### 系统负载变化
|
213 | 230 |
|
214 |
| -从400-800pod的系统负载变化,在800pod的时候系统负载很高。 |
| 231 | +从 400-800 Pod 的系统负载变化,在 800 Pod 的时候系统负载很高。 |
215 | 232 |
|
216 | 233 | 
|
217 | 234 |
|
218 | 235 | ### kube-apiserver
|
219 | 236 |
|
220 |
| -在400到800pod的资源消耗对比、并发对比。800pod的是机器负载变高,QPS就降低了。 |
| 237 | +在 400 到 800 Pod 的资源消耗对比、并发对比。800 Pod 的是机器负载变高,QPS 就降低了。 |
221 | 238 |
|
222 | 239 | 
|
223 | 240 |
|
224 | 241 | ### kubelet
|
225 | 242 |
|
226 |
| -Kubelet 组件在400-800的cpu-memoy使用情况 |
| 243 | +kubelet 组件在 400-800 的 cpu-memoy 使用情况 |
227 | 244 |
|
228 | 245 | 
|
229 | 246 |
|
230 |
| -kubelet pod创建的 QPS,400pod QPS 最高25左右,负载升高,QPS逐步下降。 |
| 247 | +kubelet Pod 创建的 QPS,400 Pod QPS 最高 25 左右,负载升高,QPS 逐步下降。 |
231 | 248 |
|
232 | 249 | 
|
233 | 250 |
|
234 |
| -### 测试结果 |
| 251 | +## 测试结果 |
235 | 252 |
|
236 |
| -800 Pod Per Node节点运行正常,kube-apiserver没有错误⽇志。 |
237 |
| -1000Pod Per Node,节点卡顿,创建pod 也很慢。Prometheus等组件有重启现象。 |
| 253 | +800 Pod Per Node 节点运行正常,kube-apiserver 没有错误⽇志。 |
| 254 | +1000Pod Per Node,节点卡顿,创建 Pod 也很慢。Prometheus 等组件有重启现象。 |
238 | 255 |
|
239 |
| -### 测试结论 |
| 256 | +## 测试结论 |
240 | 257 |
|
241 |
| -在该配置下,建议每台最好运行600 pod,避免滚动更新时触发的pod上限,或者节点故障导致的大量调度。 |
| 258 | +在该配置下,建议每台最好运行 600 Pod,避免滚动更新时触发的 Pod 上限,或者节点故障导致的大量调度。 |
242 | 259 |
|
243 |
| -## 节点故障之后迁移-可能存在的问题 |
| 260 | +## 节点故障之后迁移可能存在的问题 |
244 | 261 |
|
245 |
| -在一个集群中加入每个节点运行 600+ pod,可能存在节点故障,故障半径影响较大问题。 |
| 262 | +在一个集群中加入每个节点运行 600+ Pod,可能存在节点故障,故障半径影响较大问题。 |
| 263 | + |
| 264 | +1. 节点迁移时,这几百个 Pod 对应的镜像可能有几百个,同时在新节点进行拉取的时候,会出现影响原有节点的情况。 |
| 265 | + |
| 266 | +2. 节点上运行 600+ Pod,deployment 如果是滚动更新的时候,就会出现接近 1000 个 Pod,节点压力就会变得很高。 |
246 | 267 |
|
247 |
| -1. 节点迁移时,这几百个pod对应的镜像可能有几百个,同时在新节点进行拉取的时候,会出现影响原有节点的情况。 |
248 |
| - |
249 |
| -2. 节点上运行600+pod,deployment如果是滚动更新的时候,就会出现接近1000个pod,节点压力就会变得很高。 |
250 |
| - |
251 | 268 | 3. 节点故障之后恢复时间较长。
|
252 |
| - |
253 |
| -4. 节点上Pod过多之后,kubelet的探针执行不过来,会出现系统组件探活失败自动重启的情况。 |
| 269 | + |
| 270 | +4. 节点上 Pod 过多之后,kubelet 的探针执行不过来,会出现系统组件探活失败自动重启的情况。 |
0 commit comments