江门营销型网站建设多少钱,网站建设类的职位,wordpress没有icp,做网站要自己租服务器吗作者 | 刘春明责编 | Carol出品 | CSDN 云计算#xff08;ID#xff1a;CSDNcloud#xff09;封图| CSDN下载于视觉中国目前公司为了降低机器使用成本#xff0c;对所有的AWS虚拟机进行了盘点#xff0c;发现利用率低的机器中#xff0c;有一部分是测试团队用作Jenkins S… 作者 | 刘春明责编 | Carol出品 | CSDN 云计算IDCSDNcloud封图| CSDN下载于视觉中国目前公司为了降低机器使用成本对所有的AWS虚拟机进行了盘点发现利用率低的机器中有一部分是测试团队用作Jenkins Slave的机器。这不出我们所料使用虚拟机作为Jenkins Slave一定会存在很大浪费因为测试Job运行完成后Slave 处于空闲状态时虚拟机资源并没有被释放掉。除了资源利用率不高外虚拟机作为Jenkins Slave还有其他方面的弊端比如资源分配不均衡有的 Slave 要运行的 job 出现排队等待而有的 Slave 可能正处于空闲状态。另外扩容不方便使用虚拟机作为Slave想要增加Jenkins Slave需要手动挂载虚拟机到Jenkins Master上并给Slave配置环境导致管理起来非常不方便维护起来也是比较耗时。在2019年运维团队搭建了Kubernetes容器云平台。为了实现公司降低机器使用成本的目标我所在的车联网测试团队考虑将Jenkins Slave全面迁移到Kubernetes容器云平台。主要是想提高Jenkins Slave资源利用率并且提供比较灵活的弹性扩容能力满足越来越多的测试Job对Slave的需求。本文就是我们的实践总结。整体架构我们知道Jenkins是采用的Master-Slave架构Master负责管理JobSlave负责运行Job。在我们公司Master搭建在一台虚拟机上Slave则来自Kubernetes平台每一个Slave都是Kubernetes平台中的一个PodPod是Kubernetes的原子调度单位更多Kubernetes的基础知识不做过多介绍在这篇文章中大家只要记住Pod就是Jenkins Slave就行了。基于 Kubernetes 搭建的 Jenkins Slave 集群示意图如下。在这个架构中Jenkins Master 负责管理测试Job为了能够利用Kubernetes平台上的资源需要在Master上安装Kubernetes-plugin。Kubernetes平台负责产生Pod用作Jenkins Slave执行Job任务。当Jenkins Master上有Job被调度时Jenkins Master通过Kubernetes-plugin向Kubernetes平台发起请求请Kubernetes根据Pod模板产生对应的Pod对象Pod对象会向Jenkins Master发起JNLP请求以便连接上Jenkins Master一旦连接成功就可以在Pod上面执行Job了。Pod中所用的容器镜像则来自Harbor在这里一个Pod中用到了三个镜像分别是Java镜像、Python镜像、JNLP镜像。Java镜像提供Java环境可用来进行编译、执行Java编写的测试代码Python镜像提供Python环境用来执行Python编写的测试代码JNLP镜像是Jenkins官方提供的Slave镜像。使用Kubernetes作为Jenkins Slave如何解决前面提到的使用虚拟机时的资源利用率低、资源分配不均的问题并且实现Slave动态弹性扩容的呢首先只有在Jenkins Master有Job被调度时才会向Kubernetes申请Pod创建Jenkins Slave测试Job执行完成后所用的Slave会被Kubernetes回收。不会像虚拟机作为Slave时有Slave闲置的情况出现从而提高了计算资源的利用率。其次资源分配不均衡的主要问题在于不同测试小组之间因为测试环境和依赖不同而不能共享Jenkins Slave。而Kubernetes平台打破了共享的障碍只要Kubernetes集群中有计算资源那么就可以从中申请到适合自己项目的Jenkins Slave从而不再会发生Job排队的现象。借助Kubernetes实现Slave动态弹性扩容就更加简单了。因为Kubernetes天生就支持弹性扩容。当监控到Kubernetes资源不够时只需要通过运维平台向其中增加Node节点即可。对于测试工作来讲这一步完全是透明的。配置Jenkins Master要想利用Kubernetes作为Jenkins Slave第一步是在Jenkins Master上安装Kubernetes插件。安装方法很简单用Jenkisn管理员账号登录Jenkins在Manage Plugin页面搜索Kubernetes勾选并安装即可。接下来就是在Jenkins Master上配置Kubernetes连接信息。Jenkins Master连接Kubernetes云需要配置三个关键信息名称、地址和证书。全部配置信息如下图所示。名称将会在Jenkins Pipeline中用到配置多个Kubernetes云时需要为每一个云都指定一个不同的名称。Kubernetes地址指的是Kubernetes API server的地址Jenkins Master正是通过Kubernetes plugin向这个地址发起调度Pod的请求。Kubernetes服务证书key是用来与Kubernetes API server建立连接的生成方法是从Kubernetes API server的/root/.kube/config文件中获取/root/.kube/config中certificate-authority-data的内容并转化成base64 编码的文件即可。# echo certificate-authority-data的内容 | base64 -D ~/ca.crt
ca.crt的内容就是Kubernetes服务证书key。上图中的凭据是使用客户端的证书和key生成的pxf文件。先将/root/.kube/config中client-certificate-data和client-key-data的内容分别转化成base64 编码的文件。# echo client-certificate-data的内容 | base64 -D ~/client.crt
# echo client-key-data的内容 | base64 -D ~/client.crt
根据这两个文件制作pxf文件# openssl pkcs12 -export -out ~/cert.pfx -inkey ~/client.key -in ~/client.crt -certfile ~/ca.crt
# Enter Export Password:
# Verifying - Enter Export Password:
自定义一个password并牢记。点击Add选择类型是Cetificate点击Upload certificate选取前面生成cert.pfx文件输入生成cert.pfx文件时的密码就完成了凭据的添加。接着再配置一下Jenkins URL和同时可以被调度的Pod数量。配置完毕可以点击 “Test Connection” 按钮测试是否能够连接到 Kubernetes如果显示 Connection test successful 则表示连接成功配置没有问题。配置完Kubernetes插件后在Jenkins Master上根据需要配置一些公共工具比如我这了配置了allure用来生成报告。这样在Jenkins Slave中用到这些工具时就会自动安装到Jenkins Slave中了。定制Jenkins Pipeline配置完成Kubernetes连接信息后就可以在测试Job的Pipeline中使用kubernetes作为agent了。与使用虚拟机作为Jenkins Slave的区别主要在于pipeline.agent部分。下面代码是完整的Jenkinsfile内容。pipeline {agent {kubernetes{cloud kubernetes-bj //Jenkins Master上配置的Kubernetes名称label SEQ-AUTOTEST-PYTHON36 //Jenkins slave的前缀defaultContainer python36 // stages和post步骤中默认用到的container。如需指定其他container可用语法 container(jnlp){...}idleMinutes 10 //所创建的pod在job结束后的空闲生存时间yamlFile jenkins/jenkins_pod_template.yaml // pod的yaml文件}}environment {git_url gitgithub.com:liuchunming033/seq_jenkins_template.gitgit_key c8615bc3-c995-40ed-92ba-d5b66git_branch masteremail_list liuchunming163.com}options {buildDiscarder(logRotator(numToKeepStr: 30)) //保存的job构建记录总数timeout(time: 30, unit: MINUTES) //job超时时间disableConcurrentBuilds() //不允许同时执行流水线}stages {stage(拉取测试代码) {steps {git branch: ${git_branch}, credentialsId: ${git_key}, url: ${git_url}}}stage(安装测试依赖) {steps {sh pipenv install}}stage(执行测试用例) {steps {sh pipenv run py.test}}}post {always{container(jnlp){ //在jnlp container中生成测试报告allure includeProperties: false, jdk: , report: jenkins-allure-report, results: [[path: allure-results]]} }}
}
上面的Pipeline中与本文相关的核心部分是agent.kubernetes一段这一段描述了如何在kubernetes 平台生成Jenkins Slave。cloud是Jenkins Master上配置的Kubernetes名称用来标识当前的Pipeline使用的是哪一个Kubernetes cloud。label是Jenkins Slave名称的前缀用来区分不同的Jenkins Slave当出现异常时可以根据这个名称到Kubernetes cloud中进行debug。defaultContainer在Jenkins Slave中我定义了是三个container在前面有介绍。defaultContainer表示在Pipeline中的stages和post阶段代码运行的默认container。也就是说如果在stages和post阶段不指定container那么代码都是默认运行在defaultContainer里面的。如果要用其他的container运行代码则需要通过类似container(“jnlp”){…}方式来指定。idleMinutes指定了Jenkins Slave上运行的测试job结束后Jenkins Slave可以保留的时长。在这段时间内Jenkins Slave不会被Kubernetes回收这段时间内如果有相同label的测试Job被调度那么可以继续使用这个空闲的Jenkins Slave。这样做的目的是提高Jenkins Slave的利用率避免Kubernetes进行频繁调度因为成功产生一个Jenkins Slave还是比较耗时的。yamlFile这个文件是标准的Kubernetes的Pod 模板文件。Kubernetes根据这个文件产生Pod对象用来作为Jenkins Slave。这个文件中定义了三个容器Container以及调度的规则和外部存储。这个文件是利用Kubernetes作为Jenkins Slave集群的核心文件下面将详细介绍这个文件的内容。至此测试Job的Pipeline就建立好了。定制Jenkins Slave模板使用虚拟机作为Jenkins Slave时如果新加入一台虚拟机我们需要对虚拟机进行初始化主要是安装工具软件、依赖包并连接到Jenkins Master上。使用Kubernetes cloud作为Jenkins Slave集群也是一样要定义Jenkins Slave使用的操作系统、依赖软件和外部磁盘等信息。只不过这些信息被写在了一个Yaml文件中这个文件是Kubernetes的Pod 对象的标准模板文件。Kubernetes会自根据这个Yaml文件产生Pod并连接到Jenkins Master上。这个Yaml文件内容如下apiVersion: v1
kind: Pod
metadata:# ① 指定 Pod 将产生在Kubernetes的哪个namespace下需要有这个namespace的权限namespace: sqe-test
spec:containers:# ② 必选负责连接Jenkins Master注意name一定要是jnlp- name: jnlpimage: swc-harbor.nioint.com/sqe/jnlp-slave:root_userimagePullPolicy: Always# 将Jenkins的WORKSPACE/home/jenkins/agent挂载到jenkins-slavevolumeMounts:- mountPath: /home/jenkins/agentname: jenkins-slave# ③ 可选python36环境已安装pipenv负责执行python编写的测试代码- name: python36image: swc-harbor.nioint.com/sqe/automation_python36:v1imagePullPolicy: Always# 通过cat命令让这个container保持持续运行command:- cattty: trueenv:# 设置pipenv的虚拟环境路径变量 WORKON_HOME- name: WORKON_HOME value: /home/jenkins/agent/.local/share/virtualenvs/# 创建/home/jenkins/agent目录并挂载到jenkins-slave Volume上volumeMounts: - mountPath: /home/jenkins/agentname: jenkins-slave# 可以对Pod使用的资源进行限定可调。尽量不要用太多够用即可。resources: limits:cpu: 300mmemory: 500Mi# ④ 可选Java8环境已安装maven负责执行Java编写的测试代码- name: java8image: swc-harbor.nioint.com/sqe/automation_java8:v2imagePullPolicy: Alwayscommand:- cattty: truevolumeMounts:- mountPath: /home/jenkins/agentname: jenkins-slave# ⑤ 声明一个名称为 jenkins-slave 的 NFS Volume多个container共享volumes:- name: jenkins-slavenfs:path: /data/jenkins-slave-nfs/server: 10.125.234.64# ⑥ 指定在Kubernetes的哪些Node节点上产生PodnodeSelector:node-app: normalnode-dept: sqe
通过上面的Yaml文件可以看到通过 spec.containers 在Pod中定义了三个容器分别是负责连接Jenkins Master的jnlp负责运行Python代码的python36负责运行Java代码的java8。我们可以把Jenkins Slave比喻成豆荚里面的容器比喻成豆荚中的豆粒每颗豆粒具有不同的职责。同时还声明了一个叫作jenkins-slave 的volumejnlp 容器将Jenkins WORKSPACE目录(/home/jenkins/agent )mount到jenkins-slave 上。同时python36和java8这两个容器也将目录/home/jenkins/agent mount到jenkins-slave 上。从而在任何一个容器中对/home/jenkins/agent 目录的修改在其他两个容器中都能读取到修改后的内容。挂载外部存储的主要好处是可以将测试结果、虚拟环境持久化下来特别是将虚拟环境持久化下来之后不用每次执行测试创建新的虚拟环境而是复用已有的虚拟环境加快了整个测试执行的过程。另外还指定了使用kubernetes的哪一个Namespace命名空间以及在哪些Node节点上产生Jenkins Slave。关于这个Yaml文件的其他细节说明我都写在了文件的注释上大家可以参考着理解。定制容器镜像前面介绍了Jenkins Slave中用到了三个容器下面我们分别来看下这三个容器的镜像。首先DockerHubhttps://hub.docker.com/r/jenkinsci/jnlp-slave提供了Jenkins Slave的官方镜像我们这里将官方镜像中的默认用户切换成root用户否则在执行测试用例时可能会出现权限问题。JNLP容器镜像的Dockerfile如下FROM jenkinsci/jnlp-slave:latest
LABEL maintainerliuchunming163.com
USER root
Python镜像是在官方的Python3.6.4镜像中安装了pipenv。因为我们团队目前的Python项目都是用pipenv管理项目依赖的。这里说一下pipenv是pip的升级版它既能为你项目创建独立的虚拟环境还能够自动维护和管理项目的依赖软件包。与pip使用requirements.txt管理依赖不同pipenv使用Pipefile管理依赖这里的好处不展开介绍有兴趣的朋友可以查看一下pipenv的官方文档https://github.com/pypa/pipenv。Python镜像的Dockerfile如下FROM python:3.6.4
LABEL maintainerxxx163.com
USER root
RUN pip install --upgrade pip
RUN pip3 install pipenv
Java镜像是根据DockerHub上的maven镜像扩展来的。主要改动则是将公司内部使用的maven配置文件settings.xml放到镜像里面。完整的Dockerfile如下FROM maven:3.6.3-jdk-8
LABEL maintainerxxx163.com
USER root# 设置系统时区为北京时间
RUN mv /etc/localtime /etc/localtime.bak \ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \echo Asia/Shanghai /etc/timezone # 解决JVM与linux系统时间不一致问题
# 支持中文
RUN apt-get update \apt-get install locales -y \echo zh_CN.UTF-8 UTF-8 /etc/locale.gen \locale-gen
# 更新资源地址
ADD settings.xml /root/.m2/# 安装jacococli
COPY jacoco-plugin/jacococli.jar /usr/bin
RUN chmod x /usr/bin/jacococli.jar
制作完容器镜像之后我们会将其push到公司内部的harbor上以便kubernetes能够快速的拉取镜像。大家可以根据自己实际情况按照项目需求制作自己的容器镜像。执行自动化测试通过前面的步骤我们使用Kubernetes作为Jenkins Slave的准备工作就全部完成了。接下来就是执行测试Job了。与使用虚拟机执行测试Job相比这一步其实完全相同。创建一个Pipeline风格的Job并进行如下配置配置完成后点击Build就可以开始测试了。性能优化跟虚拟机作为Jenkins Salve不同Kubernetes生成Jenkins Slave是个动态创建的过程因为是动态创建就涉及到效率问题。解决效率问题可以从两方面入手一方面是尽量利用已有的Jenkins Slave来运行测试Job另一方面是加快产生Jenkins Slave的效率。下面我们分别从这两方面看看具体的优化措施。7.1 充分利用已有的Jenkins Slave充分利用已有的Jenkins Slave可以从两方面入手。一方面设置idleMinutes让Jenkins Slave在执行完测试Job后不要被立即消毁而是可以空闲一段时间在这段时间内如果有测试Job启动则可以分配到上面来执行既提高了已有的Jenkins Slave的利用率也避免创建Jenkins Slave耗费时间。另一方面在更多的测试Job流水线中使用相同的label这样当前面的测试Job结束后所使用的Jenkins Slave也能被即将启动的使用相同lable的测试Job所使用。比如测试job1使用的jenkins Slave 的lable是DD-SEQ-AUTOTEST-PYTHON那么当测试job1结束后使用相同lable的测试job2启动后既可以直接使用测试job1使用过的Jenkins Slave了。7.2 加快Jenkins Slave的调度效率Kubernetes上产生Jenkins Slave并加入到Jenkins Master的完整流程是Jenkins Master计算现在的负载情况Jenkins Master根据负载情况按需通过Kubernetes Plugin向Kubernetes API server发起请求Kubernetes API server向Kubernetes集群调度PodPod产生后通过JNLP协议自动连接到Jenkins Master。后三个步骤都是很快的主要受网络影响。而第一个步骤Jenkins Master会经过一系列算法计算之后发现没有可用的Jenkins Slave才决定向Kubernetes API server发起请求。这个过程在Jenkins Master的默认启动配置下是不高效的。经常会导致一个新的测试Job启动后需要等一段时间才开始在Kubernetes上产生Pod。因此需求对Jenkins Master的启动项进行修改主要涉及以下几个参数-Dhudson.model.LoadStatistics.clock2000
-Dhudson.slaves.NodeProvisioner.recurrencePeriod5000
-Dhudson.slaves.NodeProvisioner.initialDelay0
-Dhudson.model.LoadStatistics.decay0.5
-Dhudson.slaves.NodeProvisioner.MARGIN50
-Dhudson.slaves.NodeProvisioner.MARGIN00.85
Jenkins Master每隔一段时间会计算集群负载时间间隔由hudson.model.LoadStatistics.clock决定默认是10秒我们将其调整到2秒以加快 Master计算集群负载的频率从而更快的知道负载的变化情况。比如原来最快需要10秒才知道目前有多少job需要被调度执行现在只需要2秒。当Jenkins Master计算得到集群负载后发现没有可用的Jenkins Slave。Jenkins master会通知Kubernetes Plugin的NodeProvisioner以recurrencePeriod间隔生产Pod。因此recurrencePeriod值不能比hudson.model.LoadStatistics.clock小否则会生成多个Jenkins slave。initialDelay是一个延迟时间原本用于确保让静态的Jenkins Slave和Master建立起来连接因为我们这里是使用Kubernetes插件动态产生Jenkins slave没有静态Jenkins Slave所以我们将参数设置成0。hudson.model.LoadStatistics.decay这个参数原本的意义是用于抑制评估master负载的抖动对于评估得到的负载值有很大影响。默认decay是0.9。我们把decay设成了0.5允许负载有比较大的波动Jenkins Master评估的负载就是在当前尽可能真实的负载之上评估的需要的Jenkins Slave的个数。hudson.slaves.NodeProvisioner.MARGIN 和hudson.slaves.NodeProvisioner.MARGIN0这两个参数使计算出来的负载做整数向上对齐从而可能多产生一个Slave以此来提高效率。将上面的参数加入到Jenkins Mater启动进程上重启Jenkins Master即生效。java -Dhudson.model.LoadStatistics.clock2000 -Dxxx -jar jenkins.war总结本文介绍了使用Kubernetes作为持续集成测试环境的优势并详细介绍了使用方法对其性能也进行了优化。通过这个方式完美解决虚拟机作为Jenkins Slave的弊端。除了自动化测试能够从Kubernetes中收益之外在性能测试环境搭建过程中借助Kubernetes动态弹性扩容的机制对于大规模压测集群的创建在效率、便捷性方面更具有明显优势。作者介绍刘春明软件测试技术布道者十年测试老兵CSDN博客专家MSTC大会讲师ArchSummit讲师运营“明说软件测试”公众号。擅长测试框架开发、测试平台开发、持续集成、测试环境治理等熟悉服务端测试、APP测试、Web测试和性能测试。同时欢迎所有开发者扫描下方二维码填写《开发者与AI大调研》只需2分钟便可收获价值299元的「AI开发者万人大会」在线直播门票!推荐阅读如何成功构建大规模 Web 搜索引擎架构
“出道” 5 年采用率达 78%Kubernetes 的成功秘诀是什么
一群阿里人如何用 10 年自研洛神云网络平台技术架构演进全揭秘拿下 Gartner 容器产品第一阿里云打赢云原生关键一战
大话卷积神经网络CNN小白也能看懂的深度学习算法教程全程干货建议收藏
朱广权李佳琦直播掉线1.2 亿人在线等
“抗疫”新战术世卫组织联合IBM、甲骨文、微软构建了一个开放数据的区块链项目
真香朕在看了