前言

现在各种业务都追求上云,通俗的讲,“XX即服务”,作为一名专职的性能测试调优人员的我,由于会点三脚猫的开发功夫,“性能测试即服务”这种开发大任就落到我头上了,先做一个能完成核心压测功能的基础版。

本着不再重复造轮子的思想,充分利用已有的优秀软件,性能测试要想上云的话,当然封装jmeter是不二选择,但是大佬的硬性要求是,所有要提供的交付物,必须是docker镜像。

jmeter貌似没有官方镜像啊。。有好多个人做的,也没啥详细介绍,算了,还是自己做吧。

最终,需要实现前端传入用户输入的压测相关配置,后端jmeter docker镜像+.netcore测试服务镜像,测试服务镜像调用jmeter镜像进行测试,然后分析生成的结果,生成报告。

本文只涉及后端,如果你是用的Jenkins镜像+jmeter镜像做的持续集成相关,可能也会遇见跟我一样的jmeter容器调用问题。

过程及一些坑

目前后端用.netcore开发的性能测试服务基本已经完成了,可以实现前端传入一个规定格式的json,后端解析,自动在某个路径下生成jmx脚本。

现在需要的就是,在我们的测试服务容器里,调用另一个容器里的jmeter,对当前路径下的脚本测试,生成结果。

创建一个jmeter docker镜像

首先下载linux版本的jmeter,推荐下载binary版的,拷贝完直接可用,source版部署麻烦不说,还可能有找不到jar的坑。

然后就是Dockerfile,由于容器只能读取容器内的文件,脚本肯定是在容器外的,所以需要把jmeter相关的脚本、结果、报告等路径挂载出来,这个根据自己的实际需求就行。

Dockerfile:

FROM java:8
ENV http_proxy ""
ENV https_proxy ""
RUN mkdir /jmeterspace
RUN mkdir -p /jmeterspace/test
RUN mkdir -p /jmeterspace/test/input/jmx
RUN mkdir -p /jmeterspace/test/input/testdata
RUN mkdir -p /jmeterspace/test/report/html
RUN mkdir -p /jmeterspace/test/report/jtl
RUN mkdir -p /jmeterspace/test/report/outputdata
RUN chmod -R 777 /jmeterspace
ENV JMETER_VERSION=5.1.1
ENV JMETER_HOME=/jmeterspace/apache-jmeter-${JMETER_VERSION}
ENV JMETER_PATH=${JMETER_HOME}/bin:${PATH}
ENV PATH=${JMETER_HOME}/bin:${PATH}
COPY apache-jmeter-5.1.1.tgz /jmeterspace
RUN cd /jmeterspace\
&& tar xvf apache-jmeter-5.1.1.tgz \
&& rm apache-jmeter-5.1.1.tgz

分的有点细,其实可能用不了这么多路径。

然后 docker build -t invokerr/jmeter . 生成镜像。接下来是运行了,把路径挂载出来:

docker run --name="jmeter" -v /jmeterspace/test/input/jmx:/jmeterspace/test/input/jmx \
-v /jmeterspace/test/input/testdata:/jmeterspace/test/input/testdata \
-v /jmeterspace/test/report/html:/jmeterspace/test/report/html \
-v /jmeterspace/test/report/jtl:/jmeterspace/test/report/jtl \
-v /jmeterspace/test/report/outputputdata:/jmeterspace/test/report/outputdata \
-v /etc/localtime:/etc/localtime \
-it -d invokerr/jmeter

运行起来后,docker exec -it jmeter /bin/bash 进入容器,jmeter -v 如果出来jmeter相关的信息,就表示ok了。当然如果需要运行脚本的话,目前是需要像这样进入容器后用指令运行的。

至此,jmeter镜像成功。

创建一个.net core docker镜像

这个网上有好多说明,而且官方也提供了docker支持。但是微软默认生成的Dockerfile是拷贝源码-编译-发布,感觉有点多余,而且我试过,这么做有时候会报nuget路径错误,所以还是发布出来自己搞吧。

首先发布工程,选择发布成linux64版本,基于框架,然后咱们就得到了基于.net core运行时环境的linux版本,在安装.net core sdk的linux上可直接运行。

接下来,基于.net core runtime镜像,制作我们自己的镜像,为了保证我们生成的脚本可以让jmeter容器读取到,这里挂载到了与jmeter镜像相同的路径:

FROM microsoft/dotnet:2.1-aspnetcore-runtime
RUN mkdir -p /jmeterspace
RUN mkdir -p /jmeterspace/test
RUN mkdir -p /jmeterspace/test/input/jmx
RUN mkdir -p /jmeterspace/test/input/testdata
RUN mkdir -p /jmeterspace/test/report/html
RUN mkdir -p /jmeterspace/test/report/jtl
RUN mkdir -p /jmeterspace/test/report/outputdata
RUN chmod -R 777 /jmeterspace
WORKDIR /app
COPY ApiPerftestService /app/
EXPOSE 5000
WORKDIR /app
ENTRYPOINT ["dotnet", "ApiPerftestService.dll"]

然后 docker build -t invokerr/apiperftestservice . 生成镜像。

运行:

docker run --name="perftest" -p 5000:5000 -v /jmeterspace:/jmeterspace\
-v /jmeterspace/test:/jmeterspace/test \
-v /jmeterspace/test/input/jmx:/jmeterspace/test/input/jmx \
-v /jmeterspace/test/input/testdata:/jmeterspace/test/input/testdata \
-v /jmeterspace/test/report/html:/jmeterspace/test/report/html \
-v /jmeterspace/test/report/jtl:/jmeterspace/test/report/jtl \
-v /jmeterspace/test/report/outputdata:/jmeterspace/test/report/outputdata \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
-v /usr/lib64/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7 \
-v /etc/localtime:/etc/localtime \
-d invokerr/apiperftestservice

注意几行加粗的,下文会提及。目前这个容器已经成功运行了,并且可以完成在指定路径下生成脚本。

容器互相调用及一些问题

接下来,就是容器互相调用了,测试服务容器需要调用jmeter容器实现压测。

要想完成调用,最简单的办法,就是docker in docker的方式,即在某个容器里,可以访问宿主机的其他容器。

这就需要在启动容器的时候,把宿主机的docker及docker.sock文件挂载进容器,也就是

-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \

这两句,路径根据自己的实际情况,一般linux文件就是这俩路径。

坑1:找不到文件libltdl.so.7。

不知道为啥会有这种问题,简单粗暴的方式就是缺什么补什么,从宿主机挂载,-v /usr/lib64/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7

坑2:容器能访问了,怎么调用另一个容器

如果是能docker run方式调用还好,现在是需要进入容器,然后调用,如果用docker exec&&jmeter&&exit这种方式,连续发三个命令,你会发现这三个指令都是针对当前容器的,是没法用第一个指令进入jmeter容器,然后在jmeter的容器中执行第二个jmeter指令的。

既然这样,得用一个指令一步到位啊,进入容器后直接执行指令,docker是有相关语法的,在/bin/bash后直接跟命令:

docker exec -it jmeter /bin/bash jmeter -n -t {filePath.scriptPath}{Path.DirectorySeparatorChar}script.jmx -l {filePath.resultPath}{Path.DirectorySeparatorChar}result.jtl

坑3:找不到ApacheJmeter.jar

用上述命令执行的时候,报了个找不到ApacheJmeter.jar的问题,真是奇怪,在jmeter容器中执行压测命令是没问题的,不知道为啥会有这个问题,猜测可能是执行的时候,jmeter path相关的锅。

灵机一动,我直接写死执行文件不就行了,于是命令就成了这样:

docker exec -it jmeter /bin/bash /jmeterspace/apache-jmeter-5.1.1/bin/jmeter -n -t {filePath.scriptPath}{Path.DirectorySeparatorChar}script.jmx -l {filePath.resultPath}{Path.DirectorySeparatorChar}result.jtl

直接把jmeter执行路径写上,果然解决了问题。

坑4:the input device is not a TTY

为了方便,以上的执行我都是在linux环境下直接用dotnet启动的测试服务,然后测试服务里调用的jmeter命令,并没有将测试服务打包到容器里调用,我认为应该是一样的。

结果打脸了,同样的应用程序,在linux下用dotnet启动后直接调用jmeter指令没问题,但是打包成镜像,在容器里调用,就报了the input device is not a TTY。

搜了下,说是-it 的问题,去掉 -it ,把指令改成:

docker exec jmeter /bin/bash /jmeterspace/apache-jmeter-5.1.1/bin/jmeter -n -t {filePath.scriptPath}{Path.DirectorySeparatorChar}script.jmx -l {filePath.resultPath}{Path.DirectorySeparatorChar}result.jtl

果然解决了问题。

最后,附上.netcore 中调用jmeter容器的代码吧,执行压测并读取控制台log:

public static string RunJmeterInDocker(FilePath filePath)
{
  string result = $"result path:{filePath.resultPath},log:";
  //创建一个ProcessStartInfo对象 使用系统shell 指定命令和参数 设置标准输出
  var psi = new ProcessStartInfo("docker", $"exec jmeter /bin/bash /jmeterspace/apache-jmeter-5.1.1/bin/jmeter -n -t {filePath.scriptPath}      {Path.DirectorySeparatorChar}script.jmx -l {filePath.resultPath}{Path.DirectorySeparatorChar}result.jtl") { RedirectStandardOutput = true };
  //启动
  try
  {
    var proc = Process.Start(psi);
    if (proc == null)
    {
      return "Process start failed!";
    }
    else
    {
    //开始读取
      using (var sr = proc.StandardOutput)
      {
        while (!proc.HasExited)
        {
          result += sr.ReadLine();
        }  
      }
    return result;
    }
  }
  catch (Exception ee)
  {
    return ee.Message;
  }
}

性能测试即服务-docker部署jmeter及.netcore应用的更多相关文章

  1. SpringCloud微服务Docker部署

    前两写了两篇,都是为SpringCloud+Docker部署做准备,在部署的时候,不同服务器,不同的Docker容器之间的通信,还好没有掉到坑里去,在公司里用了新技术,还是很开心的,小有成就感,之前一 ...

  2. 基于Docker 部署Jmeter + Grafana + InfluxDB 性能测试监控配置(亲测可用)

    工具介绍: InfluxDB:是一款用Go语言编写的开源分布式时序.事件和指标数据库,无需外部依赖.该数据库现在主要用于存储涉及大量的时间戳数据,如DevOps监控数据,APP metrics, lo ...

  3. 服务上部署jmeter远程机

    1.首先连接服务器 2.在/home下新创建一个自己的文件夹 ]#useradd zhuxiao ]#ls 显示新的用户并在home下创建zhuxiao文件夹 ①切换到用户zhuxiao目录下 ]#s ...

  4. NetCore的Docker部署

    NetCore的Docker部署 一.NetCore与Docker Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或 ...

  5. 教你使用docker部署淘宝rap2服务

    什么是rap2 先来说说起因,在上一个星期的分享会上,谈到前后端联调上,有同事提到了rap2,特意去了解了一下,觉得使用这个东西来进行前后端的接口联调来真是太方便了,对比我们之前公司内部开发的API ...

  6. 【docker】docker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志

    如题: docker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志 场景再现: docker部署并启动 ...

  7. Docker部署微服务

    部署时需要注!意!: 打开防火墙对应的应用端口!!用于外部访问!!内部互访问则不需要. 和对应数据库,缓存,消息中间件服务等的端口(当然这些服务必须先开启,它们也可使用docker部署开启) ,用于容 ...

  8. 零基础用Docker部署微服务

    1. docker架构 这里的Client和DOCKER_HOST(docker server)都是在本地的,docker仓库Registry是在远程的: Client的docker命令通过Docke ...

  9. Docker部署golang微服务项目

    这篇博客是为了记录一下部署步骤. 因为实训需要,我要在服务器上用docker部署我们小组的微服务项目.我们的微服务有Gateway,User,Scene,Device四个部分,分别占用不同的端口,其中 ...

随机推荐

  1. Quickreport不用数据字段,如何实现多页打印?

    用QRCompositeReport控件,所谓复合报表,可把不同的报表加在一起,Example procedure TForm1.QRCompositeReport1AddReports( Sende ...

  2. ABP框架——单表实体流程

    实体实体配置文件菜单本地化语言:xml文件权限配置领域服务应用层CRUDDTOSPA路由:app.js视图生成:.html,.js

  3. IIS运行WCF服务报错

    试图加载格式不正确的程序   image 解决方法   image HTTP 错误 500.19   image 解决方法在控制面板————>程序————>启用或关闭windows功能—— ...

  4. 欢迎订阅AI科技导读微信公众号,获取人工智能的最新技术解读教程!

    微信扫一扫关注,获取最新AI技术教程!

  5. UWP开发-获取设备唯一ID

    EasClientDeviceInformation deviceInfo = new EasClientDeviceInformation(); this.showDeviceInfo.Items. ...

  6. 把滚动箱的样式做如下调整来模拟 TPanel

    程序中用 TPanel 做了容器, 需要给它一个背景图片; 发现这竟是个难题! 发现我经常使用的滚动箱控件 TScrollBox, 是一个很好的替代品. 本例需要先添加两个图片资源, 添加方法可以参考 ...

  7. QT 文件拖放事件dropEvent和dragEnterEvent

    重载以下两个函数,可以实现将文本文件拖放进文本编辑器 void MainWindow::dragEnterEvent(QDragEnterEvent *event)//拖进事件 { if(event- ...

  8. uva11038_How Many O's?_数位DP

    问m-n之间的数中共有多少个0,过程稍稍麻烦了一些,半天的时间才搞定. 直接上码吧 /********************************************************* ...

  9. Spark之json数据处理

    -- 默认情况下,SparkContext对象在spark-shell启动时用namesc初始化.使用以下命令创建SQLContext. val sqlcontext = new org.apache ...

  10. Linux上整数和浮点数的运算

    一:shell中对整数和浮点数的运算     常用的运算符号         加法+    减法 -     乘法*     除法/     求余%              +=        -= ...