一、背景介绍
传统多节点Jmeter压测环境,存在配置、维护复杂,无法并行运行测试,需要更改配置启动额外进程,难以支持云环境下测试资源的伸缩。
利用Kubernetes部署Jmeter分布式环境,可实现集群一键安装,多个项目、测试任务并行使用同一个测试资源池,提高资源利用率,对接 Kubernetes HPA 自动启动、释放压测执行节点。
二、实现原理
从 master 节点启动测试,master 节点把对应的测试脚本,发送到对应的 slaves 节点,slave 节点的 pod执行压测任务。

利用influxdb数据库存储jmeter测试结果,再通过grafana采集influxdb的数据,进行性能测试结果实时可视化展示。
三、部署准备
1、前置条件
Kubernetes集群: 1.19.16
docker环境:20.10.17
image仓库:registry私库,如reg.chebai.org
2、构建docker镜像
编写setenv.sh(修改jvm配置):
# This is the file bin/setenv.sh,
# it will be sourced in by bin/jmeter
# Use a bigger heap, but a smaller metaspace, than the default
export HEAP="-Xms8g -Xmx8g -XX:MaxMetaspaceSize=2g"
编写Dockerfile-base(构建Jmeter基础镜像):
FROM openjdk:11-jdk-slim
MAINTAINER Kubernauts-lab
ARG JMETER_VERSION=5.5
RUN apt-get clean && \
apt-get update && \
apt-get -qy install \
wget \
telnet \
iputils-ping \
unzip
RUN mkdir /jmeter \
&& cd /jmeter/ \
&& wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-$JMETER_VERSION.tgz \
&& tar -xzf apache-jmeter-$JMETER_VERSION.tgz \
&& rm apache-jmeter-$JMETER_VERSION.tgz
RUN cd /jmeter/apache-jmeter-$JMETER_VERSION/ && wget -q -O /tmp/JMeterPlugins-Standard-1.4.0.zip https://jmeter-plugins.org/downloads/file/JMeterPlugins-Standard-1.4.0.zip && unzip -n /tmp/JMeterPlugins-Standard-1.4.0.zip && rm /tmp/JMeterPlugins-Standard-1.4.0.zip
#RUN wget -q -O /jmeter/apache-jmeter-$JMETER_VERSION/lib/ext/pepper-box-1.0.jar https://github.com/raladev/load/blob/master/JARs/pepper-box-1.0.jar?raw=true
ADD pepper-box-1.0.jar /jmeter/apache-jmeter-$JMETER_VERSION/lib/ext/pepper-box-1.0.jar
ADD setenv.sh /jmeter/apache-jmeter-$JMETER_VERSION/bin/setenv.sh
RUN cd /jmeter/apache-jmeter-$JMETER_VERSION/ && wget -q -O /tmp/bzm-parallel-0.7.zip https://jmeter-plugins.org/files/packages/bzm-parallel-0.7.zip && unzip -n /tmp/bzm-parallel-0.7.zip && rm /tmp/bzm-parallel-0.7.zip
ENV JMETER_HOME /jmeter/apache-jmeter-$JMETER_VERSION/
ENV PATH $JMETER_HOME/bin:$PATH
编写Dockerfile-master(构建 Jmeter master 镜像):
FROM reg.chebai.org/kubernautslabs/jmeter-base:5.5
MAINTAINER Kubernauts-lab
EXPOSE 60000
编写Dockerfile-slave(构建 Jmeter slave 镜像):
FROM reg.chebai.org/kubernautslabs/jmeter-base:5.5
MAINTAINER Kubernauts-lab
EXPOSE 1099 50000
ENTRYPOINT $JMETER_HOME/bin/jmeter-server \
-Dserver.rmi.ssl.disable=true \
-Dserver.rmi.localport=50000 \
-Dserver_port=1099
构建jmeter镜像:
# docker build --tag="reg.chebai.org/kubernautslabs/jmeter-base:5.5" -f Dockerfile-base .
# docker build --tag="reg.chebai.org/kubernautslabs/jmeter-master:5.5" -f Dockerfile-master .
# docker build --tag="reg.chebai.org/kubernautslabs/jmeter-slave:5.5" -f Dockerfile-slave .
将镜像推送到 Registry:
# docker push reg.chebai.org/kubernautslabs/jmeter-base:5.5
# docker push reg.chebai.org/kubernautslabs/jmeter-master:5.5
# docker push reg.chebai.org/kubernautslabs/jmeter-slave:5.5
四、Kubernetes部署
1、创建jmeter配置文件
jmeter_slaves_deploy.yaml(Jmeter slave 的部署清单):
apiVersion: apps/v1
kind: Deployment
metadata:
name: jmeter-slaves
labels:
jmeter_mode: slave
spec:
replicas: 4
selector:
matchLabels:
jmeter_mode: slave
template:
metadata:
labels:
jmeter_mode: slave
spec:
containers:
- name: jmslave
image: reg.chebai.org/kubernautslabs/jmeter-slave:5.5
imagePullPolicy: IfNotPresent
ports:
- containerPort: 1099
- containerPort: 50000
jmeter_slaves_svc.yaml( Jmeter slave 服务清单):
apiVersion: v1
kind: Service
metadata:
name: jmeter-slaves-svc
labels:
jmeter_mode: slave
spec:
clusterIP: None
ports:
- port: 1099
name: first
targetPort: 1099
- port: 50000
name: second
targetPort: 50000
selector:
jmeter_mode: slave
jmeter_master_configmap.yaml(jmeter_master 配置清单):
apiVersion: v1
kind: ConfigMap
metadata:
name: jmeter-load-test
labels:
app: influxdb-jmeter
data:
load_test: |
#!/bin/bash
#Script created to invoke jmeter test script with the slave POD IP addresses
#Script should be run like: ./load_test "path to the test script in jmx format"
/jmeter/apache-jmeter-*/bin/jmeter -n -t $1 -Dserver.rmi.ssl.disable=true -R `getent ahostsv4 jmeter-slaves-svc | cut -d' ' -f1 | sort -u | awk -v ORS=, '{print $1}' | sed 's/,$//'`
jmeter_master_deploy.yaml(jmeter_master 部署清单):
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: jmeter-master
labels:
jmeter_mode: master
spec:
replicas: 1
selector:
matchLabels:
jmeter_mode: master
template:
metadata:
labels:
jmeter_mode: master
spec:
containers:
- name: jmmaster
image: reg.chebai.org/kubernautslabs/jmeter-master:5.5
imagePullPolicy: IfNotPresent
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
volumeMounts:
- name: loadtest
mountPath: /load_test
subPath: "load_test"
ports:
- containerPort: 60000
volumes:
- name: loadtest
configMap:
name: jmeter-load-test
2、创建influx配置文件
jmeter_influxdb_configmap.yaml(influxdb 配置清单):
apiVersion: v1
kind: ConfigMap
metadata:
name: influxdb-config
labels:
app: influxdb-jmeter
data:
influxdb.conf: |
[meta]
dir = "/var/lib/influxdb/meta"
[data]
dir = "/var/lib/influxdb/data"
engine = "tsm1"
wal-dir = "/var/lib/influxdb/wal"
# Configure the graphite api
[[graphite]]
enabled = true
bind-address = ":2003" # If not set, is actually set to bind-address.
database = "jmeter" # store graphite data in this database
jmeter_influxdb_deploy.yaml(influxdb 部署清单):
apiVersion: apps/v1
kind: Deployment
metadata:
name: influxdb-jmeter
labels:
app: influxdb-jmeter
spec:
replicas: 1
selector:
matchLabels:
app: influxdb-jmeter
template:
metadata:
labels:
app: influxdb-jmeter
spec:
containers:
- image: influxdb:1.8.3
imagePullPolicy: IfNotPresent
name: influxdb
volumeMounts:
- name: config-volume
mountPath: /etc/influxdb
ports:
- containerPort: 8083
name: influx
- containerPort: 8086
name: api
- containerPort: 2003
name: graphite
volumes:
- name: config-volume
configMap:
name: influxdb-config
jmeter_influxdb_svc.yaml(influxdb服务清单):
apiVersion: v1
kind: Service
metadata:
name: jmeter-influxdb
labels:
app: influxdb-jmeter
spec:
ports:
- port: 8083
name: http
targetPort: 8083
- port: 8086
name: api
targetPort: 8086
- port: 2003
name: graphite
targetPort: 2003
selector:
app: influxdb-jmeter
3、创建grafana配置文件
jmeter_grafana_deploy.yaml(grafana 部署清单):
apiVersion: apps/v1
kind: Deployment
metadata:
name: jmeter-grafana
labels:
app: jmeter-grafana
spec:
replicas: 1
selector:
matchLabels:
app: jmeter-grafana
template:
metadata:
labels:
app: jmeter-grafana
spec:
containers:
- name: grafana
image: grafana/grafana:5.2.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
protocol: TCP
env:
- name: GF_AUTH_BASIC_ENABLED
value: "true"
- name: GF_USERS_ALLOW_ORG_CREATE
value: "true"
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "true"
- name: GF_AUTH_ANONYMOUS_ORG_ROLE
value: Admin
- name: GF_SERVER_ROOT_URL
# If you're only using the API Server proxy, set this value instead:
# value: /api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
value: /
jmeter_grafana_svc.yaml(grafana服务清单):
apiVersion: v1
kind: Service
metadata:
name: jmeter-grafana
labels:
app: jmeter-grafana
spec:
ports:
- port: 3000
targetPort: 3000
selector:
app: jmeter-grafana
type: NodePort
jmeter_grafana_reporter.yaml(grafana_reporter配置清单):
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: jmeter-reporter
labels:
jmeter_mode: reporter
spec:
replicas: 1
selector:
matchLabels:
jmeter_mode: reporter
template:
metadata:
labels:
jmeter_mode: reporter
spec:
containers:
- name: jmreporter
image: kubernautslabs/jmeter-reporter:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8686
---
apiVersion: v1
kind: Service
metadata:
name: jmeter-reporter
labels:
jmeter_mode: reporter
spec:
ports:
- port: 8686
targetPort: 8686
selector:
jmeter_mode: reporter
type: NodePort
4、部署jmeter+grafana+influx集群
编写jmeter_cluster_create.sh执行脚本:
#!/usr/bin/env bash
#Create multiple Jmeter namespaces on an existing kuberntes cluster
#Started On January 23, 2018
working_dir=`pwd`
echo "checking if kubectl is present"
if ! hash kubectl 2>/dev/null
then
echo "'kubectl' was not found in PATH"
echo "Kindly ensure that you can acces an existing kubernetes cluster via kubectl"
exit
fi
kubectl version --short
echo "Current list of namespaces on the kubernetes cluster:"
echo
kubectl get namespaces | grep -v NAME | awk '{print $1}'
echo
tenant="$1"
if [ -z "$tenant" ]
then
echo "Enter the name of the new tenant unique name, this will be used to create the namespace"
read tenant
fi
echo
#Check If namespace exists
kubectl get namespace $tenant > /dev/null 2>&1
if [ $? -eq 0 ]
then
echo "Namespace $tenant already exists, please select a unique name"
echo "Current list of namespaces on the kubernetes cluster"
sleep 2
kubectl get namespaces | grep -v NAME | awk '{print $1}'
exit 1
fi
echo
echo "Creating Namespace: $tenant"
kubectl create namespace $tenant
echo "Namspace $tenant has been created"
echo
echo "Creating Jmeter slave nodes"
nodes=`kubectl get no | egrep -v "master|NAME" | wc -l`
echo
echo "Number of worker nodes on this cluster is " $nodes
echo
#echo "Creating $nodes Jmeter slave replicas and service"
echo
kubectl create -n $tenant -f $working_dir/jmeter_slaves_deploy.yaml
kubectl create -n $tenant -f $working_dir/jmeter_slaves_svc.yaml
echo "Creating Jmeter Master"
kubectl create -n $tenant -f $working_dir/jmeter_master_configmap.yaml
kubectl create -n $tenant -f $working_dir/jmeter_master_deploy.yaml
echo "Creating Influxdb and the service"
kubectl create -n $tenant -f $working_dir/jmeter_influxdb_configmap.yaml
kubectl create -n $tenant -f $working_dir/jmeter_influxdb_deploy.yaml
kubectl create -n $tenant -f $working_dir/jmeter_influxdb_svc.yaml
echo "Creating Grafana Deployment"
kubectl create -n $tenant -f $working_dir/jmeter_grafana_deploy.yaml
kubectl create -n $tenant -f $working_dir/jmeter_grafana_svc.yaml
echo "Creating Grafana Reporter"
kubectl create -n $tenant -f $working_dir/jmeter_grafana_reporter.yaml
echo "Printout Of the $tenant Objects"
echo
kubectl get -n $tenant all
echo namespace = $tenant > $working_dir/tenant_export
执行jmeter_cluster_create.sh部署脚本,并输入namespace名称jmeter-kubernetes
:
# ./jmeter_cluster_create.sh
等待一会,查看pods状态,完全ready表示成功:
# kubectl get pod -n jmeter-kubernetes -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
influxdb-jmeter-7b9f756fd8-zqpp5 1/1 Running 0 6d2h 10.42.4.113 192.168.211.24 <none> <none>
jmeter-grafana-5856f7b855-t7sn2 1/1 Running 0 6d2h 10.42.4.114 192.168.211.24 <none> <none>
jmeter-master-69764cb445-9mw5l 1/1 Running 0 22h 10.42.21.12 192.168.211.36 <none> <none>
jmeter-reporter-7c559568d9-gdgkw 1/1 Running 0 6d2h 10.42.4.112 192.168.211.24 <none> <none>
jmeter-slaves-6778c5ddb6-6l5zk 1/1 Running 0 7h15m 10.42.5.168 192.168.211.25 <none> <none>
jmeter-slaves-6778c5ddb6-tq6hb 1/1 Running 0 22h 10.42.21.13 192.168.211.36 <none> <none>
五、初始化grafana监控
1、创建初始化配置
创建GrafanaJMeterTemplate.json模板:
{
"__inputs": [
{
"name": "DS_JMETERDB",
"label": "jmeterdb",
"description": "",
"type": "datasource",
"pluginId": "influxdb",
"pluginName": "InfluxDB"
}
],
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "5.2.0"
},
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": "5.0.0"
},
{
"type": "datasource",
"id": "influxdb",
"name": "InfluxDB",
"version": "5.0.0"
},
{
"type": "panel",
"id": "singlestat",
"name": "Singlestat",
"version": "5.0.0"
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
},
{
"datasource": "${DS_JMETERDB}",
"enable": true,
"iconColor": "rgb(237, 18, 18)",
"iconSize": 17,
"lineColor": "rgb(0, 21, 255)",
"name": "Annotation",
"query": "select text,tags,title from \"$retention\".\"events\" where application =~ /$app/ AND $timeFilter",
"showLine": true,
"tagsColumn": "tags",
"textColumn": "text",
"titleColumn": "title"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 1,
"id": null,
"iteration": 1552478455724,
"links": [
{
"asDropdown": true,
"icon": "dashboard",
"includeVars": true,
"keepTime": true,
"tags": [],
"targetBlank": true,
"tooltip": "",
"type": "dashboards",
"url": ""
}
],
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 35,
"panels": [],
"repeat": null,
"title": "Jmeter Metrics",
"type": "row"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 4,
"w": 8,
"x": 0,
"y": 1
},
"id": 19,
"interval": "$granularity",
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": " users",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$granularity"
],
"type": "time"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT last(\"startedT\") FROM \"jmeter\" WHERE \"application\" =~ /$app$/ AND $timeFilter GROUP BY time($granularity) fill(null)",
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"meanAT"
],
"type": "field"
},
{
"params": [],
"type": "last"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
}
]
}
],
"thresholds": "",
"title": "Active Users",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "0",
"value": "null"
}
],
"valueName": "current"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 4,
"w": 8,
"x": 8,
"y": 1
},
"id": 17,
"interval": "",
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": " TPS",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$granularity"
],
"type": "time"
}
],
"measurement": "jmeter",
"policy": "default",
"query": "SELECT sum(\"hit\") / 30 FROM \"$retention\".\"jmeter\" WHERE \"application\" = '$app' AND \"transaction\" = 'all' AND $timeFilter GROUP BY time(30s)",
"rawQuery": true,
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"hit"
],
"type": "field"
},
{
"params": [],
"type": "last"
},
{
"params": [
" / 5"
],
"type": "math"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
},
{
"condition": "AND",
"key": "transaction",
"operator": "=",
"value": "all"
}
]
}
],
"thresholds": "",
"title": "Currents hits per Second",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "0",
"value": "null"
}
],
"valueName": "current"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": true,
"colors": [
"rgba(50, 172, 45, 0.97)",
"rgba(237, 129, 40, 0.89)",
"rgba(245, 54, 54, 0.9)"
],
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"format": "percentunit",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 4,
"w": 8,
"x": 16,
"y": 1
},
"id": 21,
"interval": "$granularity",
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"dsType": "influxdb",
"groupBy": [],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT sum(\"countError\") / sum(\"count\") FROM \"$retention\".\"jmeter\" WHERE \"application\" =~ /$app$/ AND \"transaction\" = 'all' AND $timeFilter",
"rawQuery": true,
"refId": "B",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"countError"
],
"type": "field"
},
{
"params": [],
"type": "sum"
},
{
"params": [
" / sum(\"count\")"
],
"type": "math"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
},
{
"condition": "AND",
"key": "transaction",
"operator": "=",
"value": "all"
}
]
}
],
"thresholds": "0.1,0.2",
"title": "% Errors",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "0",
"value": "null"
}
],
"valueName": "total"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 4,
"w": 8,
"x": 0,
"y": 5
},
"id": 27,
"interval": "$granularity",
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": false,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null as zero",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": true,
"targets": [
{
"alias": "Hits",
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$granularity"
],
"type": "time"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT last(\"hit\") / 5 FROM \"jmeter\" WHERE \"application\" =~ /$app$/ AND $timeFilter GROUP BY time($granularity) fill(null)",
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"hit"
],
"type": "field"
},
{
"params": [],
"type": "last"
},
{
"params": [
" / 5"
],
"type": "math"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
}
]
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Hits per Second",
"tooltip": {
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": false,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": 0,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 4,
"w": 8,
"x": 8,
"y": 5
},
"id": 22,
"interval": "$granularity",
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"dsType": "influxdb",
"groupBy": [],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT \"hit\" FROM \"jmeter\" WHERE \"application\" =~ /$app$/ AND \"statut\" = 'all' AND $timeFilter",
"rawQuery": false,
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"hit"
],
"type": "field"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
},
{
"condition": "AND",
"key": "statut",
"operator": "=",
"value": "all"
}
]
}
],
"thresholds": "",
"title": "Total Hits",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "0",
"value": "null"
}
],
"valueName": "total"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 4,
"w": 8,
"x": 16,
"y": 5
},
"id": 28,
"interval": "$granularity",
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": false,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": true,
"targets": [
{
"alias": "Errors",
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$granularity"
],
"type": "time"
},
{
"params": [
"0"
],
"type": "fill"
}
],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT mean(\"countError\") / 5 FROM \"jmeter\" WHERE \"application\" =~ /$app$/ AND $timeFilter GROUP BY time($granularity) fill(0)",
"rawQuery": false,
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"countError"
],
"type": "field"
},
{
"params": [],
"type": "mean"
},
{
"params": [
" / 5"
],
"type": "math"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
}
]
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Errors per Second",
"tooltip": {
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": false,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": 0,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 9
},
"id": 36,
"panels": [],
"repeat": null,
"title": "Application Metrics",
"type": "row"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 18,
"w": 24,
"x": 0,
"y": 10
},
"height": "",
"id": 25,
"interval": "$granularity",
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"hideEmpty": false,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"minSpan": 24,
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": true,
"targets": [
{
"alias": "$tag_transaction",
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$granularity"
],
"type": "time"
},
{
"params": [
"transaction"
],
"type": "tag"
}
],
"hide": false,
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT mean(\"avg\") FROM \"jmeter\" WHERE \"application\" =~ /$app$/ AND $timeFilter GROUP BY time($granularity), \"transaction\"",
"rawQuery": false,
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"avg"
],
"type": "field"
},
{
"params": [],
"type": "mean"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
},
{
"condition": "AND",
"key": "statut",
"operator": "=",
"value": "all"
}
]
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Average Response Time",
"tooltip": {
"msResolution": false,
"shared": false,
"sort": 0,
"value_type": "cumulative"
},
"transparent": false,
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ms",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 18,
"w": 24,
"x": 0,
"y": 28
},
"height": "",
"id": 26,
"interval": "$granularity",
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"hideEmpty": false,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"sort": "current",
"sortDesc": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"minSpan": 24,
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": true,
"targets": [
{
"alias": "$tag_transaction",
"dsType": "influxdb",
"groupBy": [
{
"params": [
"30s"
],
"type": "time"
},
{
"params": [
"transaction"
],
"type": "tag"
}
],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT mean(\"count\") / 5 FROM \"jmeter\" WHERE \"application\" =~ /$app$/ AND \"transaction\" <> 'all' AND $timeFilter GROUP BY time($granularity), \"transaction\"",
"rawQuery": false,
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"count"
],
"type": "field"
},
{
"params": [],
"type": "sum"
},
{
"params": [
" / 30"
],
"type": "math"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
},
{
"condition": "AND",
"key": "transaction",
"operator": "<>",
"value": "all"
},
{
"condition": "AND",
"key": "statut",
"operator": "=",
"value": "all"
}
]
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Transaction Per Second",
"tooltip": {
"msResolution": false,
"shared": false,
"sort": 0,
"value_type": "cumulative"
},
"transparent": false,
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": "",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 18,
"w": 24,
"x": 0,
"y": 46
},
"height": "",
"id": 29,
"interval": "$granularity",
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"hideEmpty": false,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"minSpan": 24,
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": true,
"targets": [
{
"alias": "$tag_transaction",
"dsType": "influxdb",
"groupBy": [
{
"params": [
"30s"
],
"type": "time"
},
{
"params": [
"transaction"
],
"type": "tag"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT last(\"count\") / 30 FROM \"$retention\".\"jmeter\" WHERE \"application\" =~ /$app$/ AND \"statut\" = 'ko' AND $timeFilter GROUP BY time(30s), \"transaction\" fill(null)",
"rawQuery": false,
"refId": "B",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"count"
],
"type": "field"
},
{
"params": [],
"type": "sum"
},
{
"params": [
" / 30"
],
"type": "math"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
},
{
"condition": "AND",
"key": "statut",
"operator": "=",
"value": "ko"
}
]
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Error Per Second",
"tooltip": {
"msResolution": false,
"shared": false,
"sort": 0,
"value_type": "cumulative"
},
"transparent": false,
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": "",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_JMETERDB}",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 18,
"w": 24,
"x": 0,
"y": 64
},
"height": "",
"id": 34,
"interval": "",
"legend": {
"alignAsTable": true,
"avg": true,
"current": true,
"hideEmpty": true,
"hideZero": true,
"max": true,
"min": true,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"minSpan": 24,
"nullPointMode": "null",
"percentage": false,
"pointradius": 1,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": true,
"targets": [
{
"alias": "$tag_transaction - $tag_responseCode : $tag_responseMessage",
"dsType": "influxdb",
"groupBy": [
{
"params": [
"30s"
],
"type": "time"
},
{
"params": [
"responseMessage"
],
"type": "tag"
},
{
"params": [
"responseCode"
],
"type": "tag"
},
{
"params": [
"transaction"
],
"type": "tag"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "jmeter",
"policy": "$retention",
"query": "SELECT sum(\"count\") / 5 FROM \"jmeter\" WHERE \"application\" =~ /$app$/ AND \"statut\" = 'ko' AND $timeFilter GROUP BY time($granularity), \"responseCode\" fill(null)",
"rawQuery": false,
"refId": "B",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"count"
],
"type": "field"
},
{
"params": [],
"type": "sum"
},
{
"params": [
" / 30"
],
"type": "math"
}
]
],
"tags": [
{
"key": "application",
"operator": "=~",
"value": "/$app$/"
},
{
"condition": "AND",
"key": "responseCode",
"operator": "!~",
"value": "/^0$|^$/"
},
{
"condition": "AND",
"key": "transaction",
"operator": "=~",
"value": "/$transaction/"
}
]
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Error detail",
"tooltip": {
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"transparent": false,
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"label": "",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"refresh": "30s",
"schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": ".*",
"current": {},
"datasource": "${DS_JMETERDB}",
"hide": 0,
"includeAll": false,
"label": null,
"multi": true,
"name": "app",
"options": [],
"query": "SHOW TAG VALUES FROM \"process\" WITH KEY = \"application\"",
"refresh": 2,
"regex": "",
"sort": 1,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "SHOW TAG VALUES FROM \"events\" WITH KEY = \"tags\"",
"type": "query",
"useTags": false
},
{
"allFormat": "regex wildcard",
"auto": false,
"auto_count": 10,
"auto_min": "10s",
"current": {
"text": "1m",
"value": "1m"
},
"datasource": "jmeterdb",
"hide": 0,
"includeAll": true,
"label": "",
"multi": false,
"multiFormat": "glob",
"name": "granularity",
"options": [
{
"selected": true,
"text": "1m",
"value": "1m"
},
{
"selected": false,
"text": "5m",
"value": "5m"
},
{
"selected": false,
"text": "1h",
"value": "1h"
},
{
"selected": false,
"text": "5s",
"value": "5s"
},
{
"selected": false,
"text": "15s",
"value": "15s"
},
{
"selected": false,
"text": "30s",
"value": "30s"
}
],
"query": "1m,5m,1h,5s,15s,30s",
"refresh": 2,
"regex": "",
"type": "interval"
},
{
"allValue": null,
"current": {},
"datasource": "${DS_JMETERDB}",
"hide": 0,
"includeAll": false,
"label": null,
"multi": false,
"name": "retention",
"options": [],
"query": "SHOW RETENTION POLICIES ON \"jmeterdb\"",
"refresh": 1,
"regex": "",
"sort": 0,
"tagValuesQuery": null,
"tags": [],
"tagsQuery": null,
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {},
"datasource": "${DS_JMETERDB}",
"hide": 0,
"includeAll": true,
"label": null,
"multi": true,
"name": "transaction",
"options": [],
"query": "SHOW TAG VALUES FROM \"jmeter\" WITH KEY IN (\"transaction\",\"application\") where application =~ /$app/ and transaction !~ /all/",
"refresh": 2,
"regex": "",
"sort": 0,
"tagValuesQuery": null,
"tags": [],
"tagsQuery": null,
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-30m",
"to": "now"
},
"timepicker": {
"now": true,
"refresh_intervals": [
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "browser",
"title": "JMeter Metric Template",
"uid": "ltaas",
"version": 1
}
编写dashboard.sh,初始化脚本:
#!/usr/bin/env bash
working_dir=`pwd`
#Get namesapce variable
tenant=`awk '{print $NF}' $working_dir/tenant_export`
## Create jmeter database automatically in Influxdb
echo "Creating Influxdb jmeter Database"
##Wait until Influxdb Deployment is up and running
##influxdb_status=`kubectl get po -n $tenant | grep influxdb-jmeter | awk '{print $2}' | grep Running
influxdb_pod=`kubectl get po -n $tenant | grep influxdb-jmeter | awk '{print $1}'`
kubectl exec -ti -n $tenant $influxdb_pod -- influx -execute 'CREATE DATABASE jmeter'
## Create the influxdb datasource in Grafana
echo "Creating the Influxdb data source"
grafana_pod=`kubectl get po -n $tenant | grep jmeter-grafana | awk '{print $1}'`
##kubectl cp $working_dir/influxdb-jmeter-datasource.json -n $tenant $grafana_pod:/influxdb-jmeter-datasource.json
kubectl exec -ti -n $tenant $grafana_pod -- curl 'http://admin:admin@127.0.0.1:3000/api/datasources' -X POST -H 'Content-Type: application/json;charset=UTF-8' --data-binary '{"name":"jmeterdb","type":"influxdb","url":"http://jmeter-influxdb:8086","access":"proxy","isDefault":true,"database":"jmeter","user":"admin","password":"admin"}'
2、执行grafana初始化
执行dashboard.sh脚本,初始化配置:
# ./dashboard.sh
检查 service 部署情况,全部创建表示成功:
# kubectl get svc -n jmeter-kubernetes
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jmeter-grafana NodePort 10.43.125.75 <none> 3000:30550/TCP 8d
jmeter-influxdb ClusterIP 10.43.146.255 <none> 8083/TCP,8086/TCP,2003/TCP 8d
jmeter-reporter NodePort 10.43.249.250 <none> 8686:30757/TCP 7d23h
jmeter-slaves-svc ClusterIP None <none> 1099/TCP,50000/TCP 22h
通过任意node_ip和端口30550,如 http://192.168.211.24:30550/ ,即可访问 grafana界面。
3、配置grafana界面
在“配置-》数据源”界面,点击初始化的jmeterdb数据源,测试连接成功如下:

在“添加-》导入”界面,上传GrafanaJMeterTemplate.json文件导入dashboard模板:

在JMeter Metric Template面板,“设置-链接”界面添加报告导出http://node_ip:port/api/v5/report/ltaas链接,如http://192.168.211.24:30757/api/v5/report/ltaas:

测试结果数据,可实现报告预览、下载功能:

六、执行jmeter测试
通过执行shell脚本,无需进入Jmeter节点,它将询问 Jmeter 测试脚本的位置,将其复制到master pod并启动slave进行测试。
1、无CSV参数化测试
编写脚本start_test.sh内容如下:
#!/usr/bin/env bash
#Script created to launch Jmeter tests directly from the current terminal without accessing the jmeter master pod.
#It requires that you supply the path to the jmx file
#After execution, test script jmx file may be deleted from the pod itself but not locally.
working_dir="`pwd`"
#Get namesapce variable
tenant=`awk '{print $NF}' "$working_dir/tenant_export"`
jmx="$1"
[ -n "$jmx" ] || read -p 'Enter path to the jmx file ' jmx
if [ ! -f "$jmx" ];
then
echo "Test script file was not found in PATH"
echo "Kindly check and input the correct file path"
exit
fi
test_name="$(basename "$jmx")"
#Get Master pod details
master_pod=`kubectl get po -n $tenant | grep jmeter-master | awk '{print $1}'`
kubectl cp "$jmx" -n $tenant "$master_pod:/$test_name"
## Echo Starting Jmeter load test
kubectl exec -ti -n $tenant $master_pod -- /bin/bash /load_test "$test_name"
执行start_test.sh脚本,指定测试jmx文件,启动测试:
# ./start_test.sh
2、带TXT参数化文件测试
编写start_test_txt.sh脚本如下:
#!/usr/bin/env bash
# Script created to launch Jmeter tests with txt data files directly from the current terminal without accessing the jmeter master pod.
# It requires that you supply the path to the directory with jmx file and txt files
# Directory structure of jmx with txt supposed to be:
# _test_name_/
# _test_name_/_test_name_.jmx
# _test_name_/test_data1.txt
# _test_name_/test_data2.txt
# i.e. jmx file name have to be the same as directory name.
# After execution, test script jmx file may be deleted from the pod itself but not locally.
working_dir=$(pwd)
# Get namesapce variable
tenant=$(awk '{print $NF}' "$working_dir"/tenant_export)
jmx_dir=$1
if [ ! -d "$jmx_dir" ];
then
echo "Test script dir was not found"
echo "Kindly check and input the correct file path"
exit
fi
# Get Master pod details
printf "Copy %s to master\n" "${jmx_dir}.jmx"
master_pod=$(kubectl get po -n "$tenant" | grep jmeter-master | awk '{print $1}')
kubectl cp "${jmx_dir}/${jmx_dir}.jmx" -n "$tenant" "$master_pod":/
# Get slaves
printf "Get number of slaves\n"
slave_pods=($(kubectl get po -n "$tenant" | grep jmeter-slave | awk '{print $1}'))
# for array iteration
slavesnum=${#slave_pods[@]}
# for split command suffix and seq generator
slavedigits="${#slavesnum}"
printf "Number of slaves is %s\n" "${slavesnum}"
# Split and upload txt files
for txtfilefull in "${jmx_dir}"/*.txt
do
txtfile="${txtfilefull##*/}"
printf "Processing %s file..\n" "$txtfile"
split --suffix-length="${slavedigits}" --additional-suffix=.txt -d --number="l/${slavesnum}" "${jmx_dir}/${txtfile}" "$jmx_dir"/
j=0
for i in $(seq -f "%0${slavedigits}g" 0 $((slavesnum-1)))
do
printf "Copy %s to %s on %s\n" "${i}.txt" "${txtfile}" "${slave_pods[j]}"
kubectl -n "$tenant" cp "${jmx_dir}/${i}.txt" "${slave_pods[j]}":/
kubectl -n "$tenant" exec "${slave_pods[j]}" -- mv -v /"${i}.txt" /"${txtfile}"
rm -v "${jmx_dir}/${i}.txt"
let j=j+1
done # for i in "${slave_pods[@]}"
done # for txtfile in "${jmx_dir}/*.txt"
## Echo Starting Jmeter load test
kubectl exec -ti -n $tenant $master_pod -- /bin/bash /load_test "/${jmx_dir}.jmx"
执行start_test_txt.sh脚本,传入测试jmx和txt文件目录,如jmx_dir
,启动测试:
# ./start_test_txt.sh jmx_dir
3、停止jmeter测试
编写jmeter_stop.sh脚本如下:
#!/usr/bin/env bash
#Script writtent to stop a running jmeter master test
#Kindly ensure you have the necessary kubeconfig
working_dir=`pwd`
#Get namesapce variable
tenant=`awk '{print $NF}' $working_dir/tenant_export`
master_pod=`kubectl get po -n $tenant | grep jmeter-master | awk '{print $1}'`
kubectl -n $tenant exec -ti $master_pod bash /jmeter/apache-jmeter-5.5/bin/stoptest.sh
若需要中途停止测试,可执行jmeter_stop.sh脚本:
# ./jmeter_stop.sh
网友评论