当前位置:首页 > 技术 > 正文内容

Kubernetes 控制平面性能基准测试实践

访客 技术 2026年8月12日 1

随着容器化应用的日益普及,Kubernetes 已成为企业级容器编排的事实标准。然而,当业务规模不断增长,集群中的节点和 Pod 数量激增时,Kubernetes 控制面的性能和稳定性便面临严峻挑战。为确保集群在高负载下依然能够稳定运行,并提前评估其承载能力,进行系统的性能基准测试变得至关重要。

服务等级指标 (SLI) 与目标 (SLO)

在对 Kubernetes 控制面进行性能测试时,我们通常会参照服务等级指标(SLI)和服务等级目标(SLO)来衡量系统表现。SLI 是衡量服务稳定性的量化指标,而 SLO 则是基于 SLI 设定的具体目标值。以下是 Kubernetes 官方推荐的关键性能指标及其对应的目标:

性能指标 (SLI) 目标值 (SLO) 测试方法
单对象修改类 API 调用(例如:创建、更新、删除)的响应延迟,在过去 5 分钟内取第 99 百分位 99 百分位 <= 1 秒 Kubemark + Clusterloader2
非流式只读 API 调用(例如:获取、列举)的响应延迟,在过去 5 分钟内取第 99 百分位 (a) 单资源范围(scope=resource)<= 1 秒 (b) 命名空间或集群范围(scope=namespacescope=cluster)<= 30 秒 Kubemark + Clusterloader2
可调度无状态 Pod 的启动延迟(不含镜像拉取和 Init 容器执行时间),从 Pod 创建到所有容器启动并通过 watch 观察到的时间,在过去 5 分钟内取第 99 百分位 99 百分位 <= 5 秒 Kubemark + Clusterloader2

Kubernetes 性能测试工具

了解了这些关键的性能指标和目标后,下一步是选择合适的工具进行测试。Kubernetes 社区提供了强大的性能测试框架 Clusterloader2,它能够协助我们自动化测试流程并收集结果。此外,考虑到实际环境中搭建大规模物理集群的困难,Kubernetes 还提供了 Kubemark 项目,用于模拟大量虚拟节点,从而在资源有限的环境下模拟大规模集群场景。

Clusterloader2 主要提供两种测试场景:

  1. 密度测试 (Density Test):此测试主要评估集群在高密度节点和 Pod 负载下的性能表现。其核心逻辑是在一个包含 N 个节点的集群中,持续创建大约 30 * N 个 Pod,然后删除它们,并在此过程中监控上述 SLI 是否满足 SLO。

  2. 负载测试 (Load Test):此测试旨在模拟控制面接收大量不同类型的资源创建、删除、查询(LIST)及其他操作时的性能。测试过程中,同样会持续跟踪并判断 SLI 是否达到预设的 SLO。

使用 Kubemark 模拟 100 个虚拟节点

模拟大量 Kubernetes 节点以进行性能测试是常见的需求。Kubemark 项目允许我们在现有 Kubernetes 集群中创建"虚拟"节点。以下是配置和部署 100 个模拟节点的步骤。

环境准备:

  • 工作集群 (Work Cluster):用于运行性能测试的 Kubernetes 集群。
  • 测试集群 (Test Cluster):作为"空心节点(hollow-node)"提供方,即 Kubemark 虚拟节点运行所在的集群。

1. Kubemark 工具编译与镜像构建

首先,需要从 Kubernetes 源码构建 Kubemark 二进制文件,并制作 Docker 镜像。

# 克隆指定版本的 Kubernetes 源码仓库
git clone -b v1.18.10 https://github.com/kubernetes/kubernetes.git
cd kubernetes/

# 编译 Kubemark 二进制文件
./hack/build-go.sh cmd/kubemark/

# 将编译好的二进制文件复制到镜像构建目录
cp _output/bin/kubemark cluster/images/kubemark/
cd cluster/images/kubemark/

# make build 命令会根据 Dockerfile 构建镜像,如果需要可以先修改 Dockerfile 的基础镜像
make build

# 重新标记镜像并推送到自定义仓库,以便其他节点可以访问
docker tag staging-k8s.gcr.io/kubemark:latest your-registry/kubemark:v0.1.0
docker push your-registry/kubemark:v0.1.0

2. 配置虚拟节点运行环境(在 测试集群 上操作)

在测试集群中创建必要的命名空间、ConfigMap 和 Secret。kubeconfig 文件应从工作集群的 master 节点获取,确保它具有足够的权限访问工作集群的 API 服务器。

# 创建 Kubemark 专用的命名空间
kubectl create ns kubemark

# 创建一个 ConfigMap,用于传递节点配置类型
kubectl create configmap node-configmap -n kubemark --from-literal=content.type="test-cluster"

# 将工作集群 Master 节点的 .kube/config 文件复制到此处,并创建 Secret
# 假设文件名为 config,内容应包含对工作集群的访问凭证
kubectl create secret generic kubeconfig --type=Opaque --namespace=kubemark \
  --from-file=kubelet.kubeconfig=config --from-file=kubeproxy.kubeconfig=config

# 为运行 Kubemark 虚拟节点的物理节点打标签。
# 这里的 $NodeName 应该替换为实际运行 Kubemark Pod 的节点名称。
kubectl label node $NodeName kubemark-node=true

3. 部署 Kubemark 虚拟节点

接下来,通过 Deployment 在测试集群中启动 100 个模拟节点。将 replicas 字段设置为所需的虚拟节点数量。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hollow-node-deployment
  namespace: kubemark
  labels:
    app: hollow-node
spec:
  replicas: 100 # 启动的虚拟节点数量
  selector:
    matchLabels:
      app: hollow-node
  template:
    metadata:
      labels:
        app: hollow-node
    spec:
      # 将虚拟节点调度到带有 'kubemark-node=true' 标签的物理节点上
      nodeSelector:
        kubemark-node: "true"
      initContainers:
      - name: setup-inotify-limit
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ['sysctl', '-w', 'fs.inotify.max_user_instances=524288']
        securityContext:
          privileged: true
      volumes:
      - name: kubeconfig-volume
        secret:
          secretName: kubeconfig
      containers:
      - name: hollow-kubelet
        image: your-registry/kubemark:v0.1.0 # 使用你构建的 Kubemark 镜像
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 4194
        - containerPort: 10250
        - containerPort: 10255
        env:
        - name: CONTENT_TYPE
          valueFrom:
            configMapKeyRef:
              name: node-configmap
              key: content.type
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        command:
        - /bin/sh
        - -c
        # 启动 Kubemark 的 kubelet 模拟模式
        - /kubemark --morph=kubelet --name=$(NODE_NAME) --kubeconfig=/kubeconfig/kubelet.kubeconfig $(CONTENT_TYPE) --alsologtostderr --v=2
        volumeMounts:
        - name: kubeconfig-volume
          mountPath: /kubeconfig
          readOnly: true
        securityContext:
          privileged: true
      - name: hollow-proxy
        image: your-registry/kubemark:v0.1.0 # 使用你构建的 Kubemark 镜像
        imagePullPolicy: IfNotPresent
        env:
        - name: CONTENT_TYPE
          valueFrom:
            configMapKeyRef:
              name: node-configmap
              key: content.type
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        command:
        - /bin/sh
        - -c
        # 启动 Kubemark 的 kube-proxy 模拟模式
        - /kubemark --morph=proxy --name=$(NODE_NAME) --use-real-proxier=false --kubeconfig=/kubeconfig/kubeproxy.kubeconfig $(CONTENT_TYPE) --alsologtostderr --v=2
        volumeMounts:
        - name: kubeconfig-volume
          mountPath: /kubeconfig
          readOnly: true
        tolerations:
        - operator: "Exists"
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: kubemark-node
                  operator: In
                  values:
                  - "true"
# 应用部署文件以启动虚拟节点
kubectl apply -f deploy-hollow-nodes.yaml # 假设上述 YAML 保存为此文件

使用 Clusterloader2 进行性能测试

虚拟节点部署完成后,我们可以在工作集群上运行 Clusterloader2 进行性能测试。此过程将配置测试场景、集成 Prometheus 进行指标收集,并执行实际的性能测试。

# 进入 GOPATH 目录或自定义的合适路径
mkdir -p ~/go/src/k8s.io
cd ~/go/src/k8s.io

# 克隆 Clusterloader2 性能测试仓库
git clone -b release-1.18 https://github.com/kubernetes/perf-tests.git --depth 1
cd perf-tests/clusterloader2/

# 构建 Clusterloader2 工具
go env -w GO111MODULE=off # 确保模块支持被关闭,如果 Go 版本较旧
go build -o clusterloader ./cmd/

# 定制密度测试配置
# 切换到密度测试用例目录
cd testing/density/
cp config.yaml custom-density-config.yaml

# 修改定制的 config.yaml 文件,调整测试参数
# 例如,将每个命名空间的节点数 (NODES_PER_NAMESPACE) 修改为 10
# 同时,检查并更新 pkg/execservice/manifest/exec_deployment.yaml 和
# testing/density/deployment.yaml 中使用的镜像地址,确保它们可用。
# vim custom-density-config.yaml
# ... (进行修改) ...

# 设置 Prometheus 监控系统(可选但推荐)
# 返回 perf-tests 根目录
cd ../../ 
git clone https://github.com/prometheus-operator/kube-prometheus.git --depth 1

# 部署 Prometheus Operator 相关组件
kubectl create -f kube-prometheus/manifests/setup/
kubectl create -f kube-prometheus/manifests/

# 根据实际网络环境和测试需求,移除或修改 Prometheus 的默认配置
# 例如,删除可能导致网络不通或与测试冲突的网络策略和服务监控
kubectl -n monitoring delete networkpolicies.networking.k8s.io prometheus-k8s grafana || true
kubectl -n monitoring delete servicemonitors.monitoring.coreos.com kubelet node-exporter || true
kubectl -n monitoring delete daemonsets.apps node-exporter || true

# 导入 Kubernetes SLI dashboard 并应用性能测试相关的 Prometheus 规则
# 这些规则通常定义了如何计算和记录 SLI 指标
kubectl apply -f pkg/prometheus/manifests/prometheus-rules.yaml

# 定义 Clusterloader2 运行参数
KUBE_CONFIG="${HOME}/.kube/config" # 工作集群 kubeconfig 路径
PROVIDER='kubemark'               # 指定提供者为 kubemark
MASTER_SSH_IP='your_master_ssh_ip' # 替换为工作集群 Master 节点的 SSH IP
KUBE_SSH_KEY_PATH="${HOME}/.ssh/id_rsa" # SSH 私钥路径
MASTER_SSH_USER_NAME='root'         # SSH 用户名
TEST_CONFIG='./testing/density/custom-density-config.yaml' # 使用定制的测试配置文件

# 执行 Clusterloader2 性能测试
# --enable-prometheus-server=true 启用 Prometheus 收集指标
# --tear-down-prometheus-server=false 测试结束后不删除 Prometheus 部署
# --kubemark-root-kubeconfig=$KUBE_CONFIG 指定 Kubemark 所需的 kubeconfig
./clusterloader --kubeconfig="${KUBE_CONFIG}" \
                --provider="${PROVIDER}" \
                --masterip="${MASTER_SSH_IP}" \
                --testconfig="${TEST_CONFIG}" \
                --report-dir="./performance-reports" \
                --alsologtostderr \
                --enable-prometheus-server=true \
                --tear-down-prometheus-server=false \
                --kubemark-root-kubeconfig="${KUBE_CONFIG}" \
                2>&1 | tee clusterloader_test_output.log

分析性能报告

测试执行完成后,Clusterloader2 会在 --report-dir 指定的目录下生成详细的性能报告。我们可以通过分析这些 JSON 格式的报告来评估控制面的表现。

1. API 响应延迟分析 (APIResponsivenessPrometheus_*.json)

该报告文件记录了各类 API 请求的响应延迟数据。重点关注 Perc99(99th percentile)值,它代表了绝大多数请求(99%)的响应时间上限,是衡量服务稳定性的关键指标。

# 过滤并查看 API 响应延迟报告中 99 百分位超过 0 的数据
cat performance-reports/APIResponsivenessPrometheus_density_*.json | grep Perc99 | grep -v '"Perc99": 0'

示例输出片段(注意 Perc99 值及对应的资源和操作):

    {
      "data": {
        "Perc50": 34.48,
        "Perc90": 95.66,
        "Perc99": 14323
      },
      "unit": "ms",
      "labels": {
        "Count": "1493",
        "Resource": "pods",
        "Scope": "cluster",
        "SlowCount": "1490",
        "Subresource": "",
        "Verb": "LIST"
      }
    },
    {
      "data": {
        "Perc50": 35.49,
        "Perc90": 1844.54,
        "Perc99": 4349
      },
      "unit": "ms",
      "labels": {
        "Count": "4634",
        "Resource": "nodes",
        "Scope": "cluster",
        "SlowCount": "4629",
        "Subresource": "",
        "Verb": "LIST"
      }
    }

从上述示例中,我们可以发现 podsnodesLIST 操作的 99 百分位延迟较高(分别为 14323 ms 和 4349 ms),这可能意味着在大规模集群下,列举这些资源会成为性能瓶颈,超过了官方的 SLO 目标(集群范围 LIST <= 30 秒)。

2. Pod 启动延迟分析 (PodStartupLatency_*.json)

该报告详细分解了 Pod 从创建到完全运行各个阶段的延迟。

# 查看 Pod 启动延迟报告
cat performance-reports/PodStartupLatency_SaturationPodStartupLatency_density_*.json

示例输出片段(重点关注 Metric 字段及其 Perc99 值):

{
  "version": "1.0",
  "dataItems": [
    {
      "data": {
        "Perc50": 0, "Perc90": 0, "Perc99": 1000
      },
      "unit": "ms",
      "labels": { "Metric": "create_to_schedule" }
    },
    {
      "data": {
        "Perc50": 0, "Perc90": 1000, "Perc99": 3000
      },
      "unit": "ms",
      "labels": { "Metric": "schedule_to_run" }
    },
    {
      "data>: {
        "Perc50": 212966.46, "Perc90": 396976.21, "Perc99": 445981.78
      },
      "unit": "ms",
      "labels": { "Metric": "run_to_watch" }
    },
    {
      "data": {
        "Perc50": 212973.35, "Perc90": 396985.06, "Perc99": 446977.29
      },
      "unit": "ms",
      "labels": { "Metric": "schedule_to_watch" }
    },
    {
      "data": {
        "Perc50": 212975.33, "Perc90": 396985.23, "Perc99": 446979.92
      },
      "unit": "ms",
      "labels": { "Metric": "pod_startup" }
    }
  ]
}

从报告中可以看出:

  • create_to_schedule (Pod 创建到调度器处理) 和 schedule_to_run (调度到 kubelet 运行) 的延迟相对较低,说明调度器和 kubelet 接收调度的性能良好。
  • run_to_watch (Pod 容器启动到状态通过 API Server 被观察到) 的延迟高达约 445 秒 (445981.78 ms),这显著高于官方 SLO 的 5 秒目标。这通常意味着 API Server 处理 Watch 事件或汇报 Pod 状态的效率低下,或者 kubelet 本身汇报状态有延迟。
  • pod_startup 是整个 Pod 启动过程的总延迟,其高值与 run_to_watch 的高延迟密切相关。

通过对这些指标的详细分析,可以识别 Kubernetes 控制面的潜在性能瓶颈,为后续的优化提供依据。

相关文章

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。