4. 编写第一个压测Chart:定义Deployment、Service、ConfigMap,实现压测工具的容器化部署
在容量基线校准流程中,压测工具的容器化部署是获取可靠压测数据的起点。本章将带领你从零编写一个完整的 Helm Chart,将压测工具(以 Apache JMeter 为例)打包为 Kubernetes 原生资源,实现一键部署、配置分离与弹性伸缩。
4.1 Chart 目录结构与核心文件
一个标准的 Helm Chart 遵循固定目录约定。以下是为压测工具定制的 Chart 结构:
jmeter-loadtest/
├── Chart.yaml # Chart 元数据
├── values.yaml # 默认配置值
├── templates/
│ ├── _helpers.tpl # 模板辅助函数
│ ├── deployment.yaml # Deployment 定义
│ ├── service.yaml # Service 定义
│ ├── configmap.yaml # ConfigMap 定义
│ └── NOTES.txt # 部署后提示信息
└── .helmignore # 忽略文件列表
| 文件/目录 | 作用 | 压测场景关键点 |
|---|---|---|
Chart.yaml |
定义 Chart 名称、版本、API 版本 | 建议将压测场景版本号与 Chart 版本绑定 |
values.yaml |
集中管理所有可配置参数 | 线程数、循环次数、目标服务地址、资源限制 |
templates/deployment.yaml |
定义 Pod 副本、容器镜像、环境变量 | 挂载 ConfigMap 中的压测脚本,设置资源 requests/limits |
templates/service.yaml |
暴露压测工具的监控端口或控制端口 | 通常使用 ClusterIP 类型,仅内部访问 |
templates/configmap.yaml |
存储压测脚本、配置文件等非敏感数据 | JMX 脚本、CSV 数据文件、属性配置 |
容量规划提示: 在
values.yaml 中预留 replicaCount、resources.requests、resources.limits 三个字段,后续压测基线校准时可直接通过 --set 参数调整,无需修改模板。
4.2 定义 ConfigMap:压测脚本与配置分离
ConfigMap 负责将压测脚本(.jmx)和参数配置从容器镜像中解耦。这样,更换压测场景时只需更新 ConfigMap,无需重新构建镜像。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "jmeter-loadtest.fullname" . }}-scripts
labels:
{{- include "jmeter-loadtest.labels" . | nindent 4 }}
data:
test-plan.jmx: |
{{- .Files.Get "scripts/test-plan.jmx" | nindent 4 }}
user.properties: |
{{- .Files.Get "scripts/user.properties" | nindent 4 }}
test-data.csv: |
{{- .Files.Get "scripts/test-data.csv" | nindent 4 }}
关键设计: 使用
.Files.Get 函数将本地脚本文件直接注入 ConfigMap,避免在 values.yaml 中嵌入大段脚本内容。脚本文件应放在 Chart 根目录的 scripts/ 子目录中,并在 .helmignore 中排除非必要文件。
4.3 定义 Deployment:压测容器的运行时编排
Deployment 是压测 Pod 的核心控制器。以下模板实现了压测工具的完整容器化部署:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "jmeter-loadtest.fullname" . }}
labels:
{{- include "jmeter-loadtest.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "jmeter-loadtest.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "jmeter-loadtest.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: jmeter
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: TARGET_HOST
value: "{{ .Values.target.host }}"
- name: TARGET_PORT
value: "{{ .Values.target.port }}"
- name: THREAD_COUNT
value: "{{ .Values.test.threadCount }}"
- name: LOOP_COUNT
value: "{{ .Values.test.loopCount }}"
- name: RAMP_UP
value: "{{ .Values.test.rampUp }}"
volumeMounts:
- name: scripts-volume
mountPath: /opt/jmeter/scripts
readOnly: true
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumes:
- name: scripts-volume
configMap:
name: {{ include "jmeter-loadtest.fullname" . }}-scripts
资源隔离警告: 压测 Pod 的
resources.requests 和 resources.limits 必须显式设置。未设置资源限制时,压测进程可能抢占集群资源,影响其他业务 Pod。建议 requests 与 limits 保持一致(Guaranteed QoS),确保压测结果可复现。
4.4 定义 Service:暴露监控与结果收集端口
Service 用于暴露压测工具的监控端口(如 JMeter Prometheus 插件端口 9270)或控制端口(如分布式压测时的 Server 端口 1099)。
apiVersion: v1
kind: Service
metadata:
name: {{ include "jmeter-loadtest.fullname" . }}
labels:
{{- include "jmeter-loadtest.labels" . | nindent 4 }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "{{ .Values.service.metricsPort }}"
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.metricsPort }}
targetPort: metrics
protocol: TCP
name: metrics
- port: {{ .Values.service.serverPort }}
targetPort: server
protocol: TCP
name: server
selector:
{{- include "jmeter-loadtest.selectorLabels" . | nindent 4 }}
| 端口名称 | 默认端口 | 用途 | 容量规划关注点 |
|---|---|---|---|
metrics |
9270 | Prometheus 指标暴露 | 用于实时采集 TPS、响应时间、错误率 |
server |
1099 | JMeter 分布式控制 | Master-Slave 模式下控制通信 |
4.5 压测部署架构总览
下图展示了 Helm Chart 部署后,ConfigMap、Deployment、Service 三者的协作关系:
4.6 values.yaml 参数化设计
将所有可变参数抽取到 values.yaml,实现压测场景的快速切换:
# 镜像配置
image:
repository: registry.example.com/jmeter
tag: "5.6.3"
pullPolicy: IfNotPresent
# 副本数(分布式压测时使用)
replicaCount: 1
# 目标服务
target:
host: "service-b.default.svc.cluster.local"
port: 8080
# 压测参数
test:
threadCount: 100
loopCount: 10
rampUp: 30
# 资源限制(容量基线校准核心参数)
resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "2"
memory: "4Gi"
# 服务配置
service:
type: ClusterIP
metricsPort: 9270
serverPort: 1099
容量基线校准最佳实践: 在
values.yaml 中为 resources.requests 和 resources.limits 设置相同值(Guaranteed QoS),确保每次压测 Pod 获得稳定的 CPU 和内存配额,消除资源争抢对压测结果的干扰。
4.7 部署验证与常用命令
完成 Chart 编写后,通过以下命令验证模板渲染正确性并执行部署:
# 1. 模板渲染验证(不实际部署)
helm template jmeter-loadtest ./jmeter-loadtest
# 2. 语法检查
helm lint ./jmeter-loadtest
# 3. 安装 Chart(指定压测参数)
helm install loadtest-run-001 ./jmeter-loadtest \
--set test.threadCount=200 \
--set test.loopCount=5 \
--set target.host=service-b.prod.svc.cluster.local
# 4. 查看 Pod 日志
kubectl logs -l app.kubernetes.io/instance=loadtest-run-001
# 5. 卸载压测任务
helm uninstall loadtest-run-001
4.8 压测脚本挂载与执行流程
下图展示了从 ConfigMap 挂载到 JMeter 容器执行压测的完整数据流:
4.9 常见问题与避坑指南
- ConfigMap 大小限制: ConfigMap 单个条目最大 1MB。大型压测数据文件(如 CSV 超过 1MB)应使用 PVC 或对象存储挂载,而非 ConfigMap。
- 脚本路径硬编码: 确保 JMeter 容器的启动命令(ENTRYPOINT)指向挂载路径
/opt/jmeter/scripts/test-plan.jmx,而非镜像内的默认路径。 - 分布式压测网络: 当
replicaCount > 1时,需额外定义 Headless Service 用于 Master-Slave 通信,并在 values.yaml 中配置 Slave 地址列表。 - 资源超分风险: 压测 Pod 的
limits.cpu不应超过集群单节点可用 CPU 的 80%,避免因 CPU Throttling 导致压测结果失真。
下一阶段准备: 完成第一个压测 Chart 后,建议在测试环境执行
helm install 并观察 Pod 日志,确认 JMeter 成功加载脚本并开始发送请求。这是后续第 5 章“压测数据采集与 Prometheus 集成”的基础。