K8s 运维系列 | 第 24 天:性能调优——节点与集群性能优化实战

在 Kubernetes 集群真正投入生产之后,绝大多数运维团队最先遇到的问题并不是”功能用不起来”,而是”性能不够用”和”成本下不来”。CPU 被申请了一大堆却长期闲置、内存申请远超实际需求、节点利用率长期停留在 20% 以下——这些都是 Kubernetes 性能调优中最典型的痛点。本篇将从节点层、Pod 层、调度层和集群层四个维度,系统讲解一套可落地的 Kubernetes 性能优化方法论,帮助你把集群资源利用率提升到合理水平,同时保证业务稳定性。

K8s 运维 第24天

一、为什么 Kubernetes 需要专项性能调优

Kubernetes 的性能瓶颈,绝大多数不是硬件本身不够强,而是资源请求(Request)与资源限制(Limit)设置不合理造成的。

在 Kubernetes 调度模型中,Pod 的调度依据是 request,而不是实际用量。如果每个 Pod 的 request 都设得很大,调度器就会认为节点资源不足,于是把 Pod 分散到很多节点上。结果就是:大量节点被”占位”,但实际 CPU 和内存使用率很低,整体利用率严重浪费。反之,如果 request 设置过小,Pod 会被过度打包到少数节点,一旦业务流量突增,就会出现节点资源争抢、OOM Kill 甚至 Pod 驱逐。

因此,Kubernetes 性能调优的核心目标只有一个:让 request 尽量贴近实际用量,让 Limit 为突发留出安全边界,再配合弹性伸缩与调度策略让资源动态流动

二、性能调优的整体框架

一套完整的 Kubernetes 性能优化方案通常包含四个层次:

  1. 应用层调优:Profile 应用本身,减少不必要的 CPU、内存、IO 消耗。
  2. 资源声明层调优:合理设置 requests/limits,启用资源度量工具。
  3. 调度层调优:通过污点容忍、亲和性、拓扑分布等控制 Pod 分布。
  4. 集群层调优:节点池分层、HPA/Cluster Autoscaler、组件参数调优。

下面逐层展开,并给出对应的命令与配置示例。

三、第一步:测量应用的真实资源消耗

优化的前提是测量。没有真实数据就调 requests,等于凭感觉猜。推荐使用 VPA(Vertical Pod Autoscaler)在测试环境里跑一段时间,让 VPA 统计出推荐值,再把这个推荐值作为生产 requests 的参考。

3.1 查看当前资源声明

# 列出所有 Pod 的资源请求与限制
kubectl get pods -A -o custom-columns=
NAMESPACE:.metadata.namespace,
NAME:.metadata.name,
REQ_CPU:.spec.containers[*].resources.requests.cpu,
REQ_MEM:.spec.containers[*].resources.requests.memory,
LIM_CPU:.spec.containers[*].resources.limits.cpu,
LIM_MEM:.spec.containers[*].resources.limits.memory

3.2 统计集群资源水位

# 节点整体用量(含实际与请求)
kubectl top nodes

# 全集群 Pod 用量,按内存排序
kubectl top pods -A --sort-by=memory

注意:kubectl top 依赖 Metrics Server,需先确认其已部署:kubectl -n kube-system get ds metrics-server

3.3 用 VPA 生成推荐值

# vpa-recommender.yaml:仅推荐,不自动调整(模式 Off)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: vpa-web
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  updatePolicy:
    updateMode: "Off"   # 只推荐不动手,先观察一段时间
# 查看 VPA 给出的推荐值
kubectl get vpa vpa-web -o yaml
# 关注 status.recommendation.containers[].target 与 .lowerBound

VPA 给出的 target 是过去一段时间实际用量的统计值,是设置 requests 的最佳起点。建议将 requests 设为 target 的 1.1~1.3 倍,为偶发峰值留出余量。

四、第二步:设置合理的 Requests 与 Limits

4.1 Requests 与 Limits 的原则差异

  • Requests 影响调度与配额,应贴近实际中位数用量。
  • Limits 影响运行时保护,CPU limit 建议设为 requests 的 2~4 倍;内存 limit 建议略高于 requests,避免 OOM。

4.2 生产推荐配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  replicas: 6
  template:
    spec:
      containers:
      - name: app
        image: api:1.8.0
        resources:
          requests:
            cpu: "250m"      # VPA 推荐值附近
            memory: "512Mi"
          limits:
            cpu: "1"          # 突发可到 1 核
            memory: "768Mi"   # 留 256Mi 缓冲,防 OOM
        terminationGracePeriodSeconds: 30

4.3 启用 LimitRange 兜底

对没有显式声明资源的 Pod,LimitRange 会自动补默认值,避免”裸奔” Pod 拖垮节点:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
spec:
  limits:
  - defaultRequest:
      cpu: "100m"
      memory: "128Mi"
    default:
      cpu: "500m"
      memory: "512Mi"
    type: Container

4.4 用 ResourceQuota 控制命名空间总量

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
  namespace: team-a
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "50"
    limits.memory: 80Gi
    pods: "200"

ResourceQuota 结合 LimitRange,可以让资源在集群内有序分配,防止单一业务吃光节点。

五、第三步:调度层优化,控制 Pod 分布

资源声明合理后,还需要让调度器把 Pod 摆到合适的位置。核心手段是亲和性与拓扑分布约束。

5.1 拓扑分布约束(避免单点)

spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: api-server

该配置能让 6 个副本尽量均匀分散到不同节点,单节点宕机时最多只损失 1 个副本,是高可用的关键保障。

5.2 污点与容忍度隔离特殊节点

# 给高性能节点打污点,只允许特定 Pod 调度
kubectl taint nodes high-perf-01 dedicated=true:NoSchedule
spec:
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

5.3 节点分层(Node Pool)

生产集群应把节点按用途分层:

节点池 用途 特征
通用计算池 普通微服务 标准机型,可弹性伸缩
高内存池 大数据、缓存 大内存机型,打污点隔离
GPU 池 AI 推理 配 NVIDIA 驱动,专用调度
系统节点池 有状态组件 静态 PV,禁止驱逐

通过污点与亲和性,把不同 workload 引导到对应节点池,性能与隔离性都会更好。

六、第四步:弹性伸缩与集群层调优

静态优化只能解决”平均情况”,业务波峰波谷需要弹性能力补齐。

6.1 HPA 自动伸缩副本数

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 3
  maxReplicas: 30
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 65

建议同时配置基于 QPS 或自定义指标(pod 内暴露的自定义 metric)的 HPA,CPU 利用率的响应存在 1~2 分钟的滞后。

6.2 Cluster Autoscaler 自动扩缩节点

HPA 只是增加 Pod,真正扩容节点要靠 Cluster Autoscaler。它根据 Pending Pod 自动申请新节点:

# 查看当前各节点池容量与可扩容空间
kubectl describe cluster-autoscaler --namespace kube-system

关键经验:给节点池配置合理的 min/max size,并为有状态工作负载准备独立的、不参与自动缩容的节点池,避免自动缩容误删运行数据库的节点。

6.3 关键组件参数调优

控制平面在高规模集群下也会成为瓶颈,常见调优项:

# 查看 etcd 集群健康度(性能基线)
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 
  endpoint health

# 查看 etcd 的 leader 与延迟
ETCDCTL_API=3 etcdctl endpoint status -w table

etcd 的 db sizeleader changesapply latency 是判断集群是否过载的核心指标。当 etcd 压力上升时,应优先减少 Watch 数量、降低 Ingress Controller 的同步频率,而不是盲目扩容 etcd 数据节点。

七、性能调优常见问题

问题 1:Pod 频繁 OOMKilled 怎么办?

先看 kubectl describe pod 里的 Last State,确认是内存超限。若 limit 设置过低,适当上调;若是内存泄漏,需在应用层修复。生产环境建议把内存 limit 设为 requests 的 1.2~1.5 倍,并开启 PodDisruptionBudget 防止抖动。

问题 2:为什么 Pod 一直 Pending?

Pending 通常意味着请求资源找不到匹配节点。用 kubectl describe pod 查看 Events,常见原因有三:CPU/内存 request 过大导致无节点可调度、污点没有对应容忍度、PVC 未绑定。用 kubectl describe nodes 核对节点剩余可调度容量。

问题 3:requests 与 limits 应该设一样吗?

不应相等。request 决定调度,limit 决定保护。相等会导致突发流量时 Pod 立即被 CPU Throttling 限制,延迟飙升。推荐 CPU limit 显著大于 request,内存 limit 适度大于 request。

问题 4:CPU Throttling 如何检测与缓解?

通过 cAdvisor 暴露的 container_cpu_cfs_throttled_periods_total 指标判断。若长期被节流,说明 CPU limit 过低,需上调 limit 或减少单 Pod 并发。

八、总结

Kubernetes 性能调优不是单点魔法,而是一套完整的度量—声明—调度—弹性体系。核心行动顺序是:

  1. 用 VPA 和 metrics 度量真实用量,拒绝凭感觉设置资源;
  2. requests 贴近实际、limits 留出缓冲,配合 LimitRange 与 ResourceQuota 兜底;
  3. 用拓扑分布与污点亲和把 Pod 摆到正确的节点,做好隔离与高可用;
  4. 用 HPA + Cluster Autoscaler 让集群随业务自动伸缩,节点池分层管理;
  5. 关注 etcd 与控制平面健康,避免底层成为隐性瓶颈。

把这套方法论应用到生产后,大多数集群都能把平均资源利用率从 20% 提升到 50% 以上,同时业务稳定性不下降——这才是性能调优的真正价值。

下期预告

第 25 天,我们将进入「故障排查」专题,系统讲解常见 Kubernetes 集群故障的定位方法与处理流程,包括 Pod 无法启动、节点异常、网络不通、控制平面故障等实战场景,帮你建立一套标准化的故障定位思维。

微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容