Apache JMeter 是一个纯 Java 开发的用于负载测试或者性能测试的开源软件. 这篇文章介绍一下如何使用 Alpine 基础镜像将 JMeter 的压测能力进行容器化, 并结合具体的示例来演示此镜像从构建到使用的整体过程.
以 Alpine 为基础构建 JMeter 镜像
Alpine 镜像的特点就是小, 在 Alpine 镜像之上安装 jre, 并下载 JMeter 并解压, 设定环境变量就完成了 JMeter 的镜像.
Dockerfile
示例的 Dockerfile 如下所示
- [[email protected] jmeter]# ls
- Dockerfile
- [[email protected] jmeter]# cat Dockerfile
- FROM alpine:3.10.2
- ARG VERSION_JMETER="5.1.1"
- ENV FILENAME_JMETER apache-jmeter-${
- VERSION_JMETER
- }
- ENV HOME_JMETER /usr/local/${
- FILENAME_JMETER
- }
- ENV DOWNLOAD_URL_JMETER https://archive.apache.org/dist/jmeter/binaries/${
- FILENAME_JMETER
- }.tgz
- ENV DOWNLOAD_DIR_LOCAL /tmp/download
- RUN apk update && apk upgrade && apk add --update openjdk8-jre curl unzip bash && mkdir -p /tmp/download && curl -L --silent ${
- DOWNLOAD_URL_JMETER
- }> ${
- DOWNLOAD_DIR_LOCAL
- }/${
- FILENAME_JMETER
- }.tgz && mkdir -p /opt ${
- DOWNLOAD_DIR_LOCAL
- } && tar -xzf ${
- DOWNLOAD_DIR_LOCAL
- }/${
- FILENAME_JMETER
- }.tgz -C /usr/local && rm -rf /var/cache/apk/* && rm -rf ${
- DOWNLOAD_DIR_LOCAL
- }
- ENV PATH $PATH:${
- HOME_JMETER
- }/bin
- WORKDIR ${
- HOME_JMETER
- }/bin
- [[email protected] jmeter]#
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
注: 此处为了减小 size 使用的 JRE, 但是由于 JMeter 一部分功能是在 keytool 基础上的, 所以实际使用的时候还是根据情况换成 jdk, 或者选择相关的 apk 包进行安装达到要求.
构建 JMeter 镜像
使用 docker build 构建 JMeter 的镜像, 输入日志如下所示
- [[email protected] jmeter]# docker build -t jmeter:5.1.1 .
- Sending build context to Docker daemon 2.56 kB
- Step 1/9 : FROM alpine:3.10.2
- ---> 961769676411
- Step 2/9 : ARG VERSION_JMETER="5.1.1"
- ---> Using cache
- ---> f4f342eab6ba
- Step 3/9 : ENV FILENAME_JMETER apache-jmeter-${VERSION_JMETER}
- ---> Using cache
- ---> f8ca701c741b
- Step 4/9 : ENV HOME_JMETER /usr/local/${FILENAME_JMETER}
- ---> Using cache
- ---> 056cc7e91e6f
- Step 5/9 : ENV DOWNLOAD_URL_JMETER https://archive.apache.org/dist/jmeter/binaries/${FILENAME_JMETER}.tgz
- ---> Using cache
- ---> 49e87f232d91
- Step 6/9 : ENV DOWNLOAD_DIR_LOCAL /tmp/download
- ---> Using cache
- ---> 58cb1fc2f1f3
- Step 7/9 : RUN apk update && apk upgrade && apk add --update openjdk8-jre curl unzip bash && mkdir -p /tmp/download && curl -L --silent ${DOWNLOAD_URL_JMETER} -o ${DOWNLOAD_DIR_LOCAL}/${FILENAME_JMETER}.tgz && mkdir -p /opt ${DOWNLOAD_DIR_LOCAL} && tar -xzf ${DOWNLOAD_DIR_LOCAL}/${FILENAME_JMETER}.tgz -C /usr/local && rm -rf /var/cache/apk/* && rm -rf ${DOWNLOAD_DIR_LOCAL}
- ---> Running in 908fac559368
- fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
- fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
- v3.10.2-80-g68e4e4a13a [http://dl-cdn.alpinelinux.org/alpine/v3.10/main]
- v3.10.2-83-g64319a6606 [http://dl-cdn.alpinelinux.org/alpine/v3.10/community]
- OK: 10336 distinct packages available
- (1/2) Upgrading libcrypto1.1 (1.1.1c-r0 -> 1.1.1d-r0)
- (2/2) Upgrading libssl1.1 (1.1.1c-r0 -> 1.1.1d-r0)
- OK: 6 MiB in 14 packages
- (1/48) Installing ncurses-terminfo-base (6.1_p20190518-r0)
... 省略
- (48/48) Installing unzip (6.0-r4)
- Executing busybox-1.30.1-r2.trigger
- Executing ca-certificates-20190108-r0.trigger
- Executing java-common-0.2-r0.trigger
- OK: 95 MiB in 62 packages
- ---> 655fe0283c8d
- Removing intermediate container 908fac559368
- Step 8/9 : ENV PATH $PATH:${HOME_JMETER}/bin
- ---> Running in 9c731c259c57
- ---> e32e05b622a9
- Removing intermediate container 9c731c259c57
- Step 9/9 : WORKDIR ${HOME_JMETER}/bin
- ---> 45f070d75ce2
- Removing intermediate container 958b82eaf6e0
- Successfully built 45f070d75ce2
- [[email protected] jmeter]#
- [[email protected] jmeter]# docker images |grep jmeter |grep 5.1.1
- jmeter 5.1.1 45f070d75ce2 16 seconds ago 190 MB
- [[email protected] jmeter]#
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
测试准备
压力测试应用准备
在本地机器的 8088 端口使用 Docker 启动一个 Nginx 应用 (使用其他方式也可), 示例如下所示:
- liumiaocn:~ liumiao$ docker images |grep nginx |grep latest
- nginx latest e445ab08b2be 2 months ago 126MB
- liumiaocn:~ liumiao$ docker run -p 8088:80 -d --name=nginx-test nginx:latest
- a80fb1a4fc20627891a6bd7394fd79ae9aefb7dc8cf72c12967bc2673a815308
- liumiaocn:~ liumiao$
- 1
- 2
- 3
- 4
- 5
使用 curl 命令或者直接使用浏览器确认 nginx 已正常运行
liumiaocn:~ liumiao$ curl http://localhost:8088/
- <!DOCTYPE HTML>
- <HTML>
- <head>
- <title>
- Welcome to nginx!
- </title>
- <style>
- body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial,
- sans-serif; }
- </style>
- </head>
- <body>
- <h1>
- Welcome to nginx!
- </h1>
- <p>
- If you see this page, the nginx Web server is successfully installed and
- working. Further configuration is required.
- </p>
- <p>
- For online documentation and support please refer to
- <a href="http://nginx.org/">
- nginx.org
- </a>
- .
- <br/>
- Commercial support is available at
- <a href="http://nginx.com/">
- nginx.com
- </a>
- .
- </p>
- <p>
- <em>
- Thank you for using nginx.
- </em>
- </p>
- </body>
- </HTML>
- liumiaocn:~ liumiao$
准备 jmx 文件
jmx 文件信息如下所示
- liumiaocn:data liumiao$ ls
- jmeter-nongui-test.jmx
- liumiaocn:data liumiao$ cat jmeter-nongui-test.jmx
- <?xml version="1.0" encoding="UTF-8"?>
- <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.1.1 r1855137">
- <hashTree>
- <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="测试计划" enabled="true">
- <stringProp name="TestPlan.comments"></stringProp>
- <boolProp name="TestPlan.functional_mode">false</boolProp>
- <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
- <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
- <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
- <collectionProp name="Arguments.arguments"/>
- </elementProp>
- <stringProp name="TestPlan.user_define_classpath"></stringProp>
- </TestPlan>
- <hashTree>
- <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="线程组" enabled="true">
- <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
- <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
- <boolProp name="LoopController.continue_forever">false</boolProp>
- <stringProp name="LoopController.loops">10</stringProp>
- </elementProp>
- <stringProp name="ThreadGroup.num_threads">100</stringProp>
- <stringProp name="ThreadGroup.ramp_time">1</stringProp>
- <boolProp name="ThreadGroup.scheduler">false</boolProp>
- <stringProp name="ThreadGroup.duration"></stringProp>
- <stringProp name="ThreadGroup.delay"></stringProp>
- </ThreadGroup>
- <hashTree>
- <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP 请求" enabled="true">
- <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
- <collectionProp name="Arguments.arguments"/>
- </elementProp>
- <stringProp name="HTTPSampler.domain">192.168.31.242</stringProp>
- <stringProp name="HTTPSampler.port">8088</stringProp>
- <stringProp name="HTTPSampler.protocol">http</stringProp>
- <stringProp name="HTTPSampler.contentEncoding"></stringProp>
- <stringProp name="HTTPSampler.path">/</stringProp>
- <stringProp name="HTTPSampler.method">GET</stringProp>
- <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
- <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
- <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
- <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
- <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
- <stringProp name="HTTPSampler.connect_timeout"></stringProp>
- <stringProp name="HTTPSampler.response_timeout"></stringProp>
- </HTTPSamplerProxy>
- <hashTree/>
- </hashTree>
- </hashTree>
- </hashTree>
- </jmeterTestPlan>
- liumiaocn:data liumiao$
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
注: 关于此 jmx 的生成步骤和说明请参看
https://liumiaocn.blog.csdn.net/article/details/101904948
注意事项: 前面示例中关于本地 Web 应用的压测, hostname 设定的为 localhost, 但是由于 jmeter 在容器中运行, 此 localhost 不同于彼 localhost, 所以此处改为了 IP(192.168.31.242), 请实际验证时修改为自己的 IP.
执行测试
启动容器 & 确认版本
- liumiaocn:tmp liumiao$ docker run -it -v $(pwd)/data:/data jmeter:5.1.1 sh
- /usr/local/apache-jmeter-5.1.1/bin # cd /data
- /data # ls
- jmeter-nongui-test.jmx
- /data # which jmeter
- /usr/local/apache-jmeter-5.1.1/bin/jmeter
- /data # jmeter -v
- _ ____ _ ____ _ _ _____ _ __ __ _____ _____ _____ ____
- / \ | _ \ / \ / ___| | | | ____| | | \/ | ____|_ _| ____| _ \
- / _ \ | |_) / _ \| | | |_| | _| _ | | |\/| | _| | | | _| | |_) |
- / ___ \| __/ ___ \ |___| _ | |___ | |_| | | | | |___ | | | |___| _ </_/ \_\_| /_/ \_\____|_| |_|_____| \___/|_| |_|_____| |_| |_____|_| \_\ 5.1.1 r1855137
- Copyright (c) 1999-2019 The Apache Software Foundation
- /data #
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
执行测试并生成结果
- /data # jmeter -n -t jmeter-nongui-test.jmx -l result.jtl -e -o jmeter-nongui-rpt
- Creating summariser <summary>
- Created the tree successfully using jmeter-nongui-test.jmx
- Starting the test @ Wed Oct 02 07:39:06 GMT 2019 (1570001946517)
- Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
- summary = 1000 in 00:00:02 = 538.5/s Avg: 55 Min: 2 Max: 393 Err: 0 (0.00%)
- Tidying up ... @ Wed Oct 02 07:39:09 GMT 2019 (1570001949228)
- ... end of run
- /data #
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
压测报告确认
来源: http://www.bubuko.com/infodetail-3384743.html