Jenkins基于k8s进行持续集成测试实践

背景

用jenkins来做持续集成测试相信在测试工作中大多数人都接触过,这里不过多赘述。简单来说,我们在Jenkins上配置了job(通常以Pipline的形式配置)后,Jenkins Master做两件事,1.选择要运行job的Jenkins Slave机器;2. 在选取的Slave机器上运行job。

本文主要关注第一点,如何准备待运行Job的Jenkins Slave机器。

基于k8s创建Jenkins Slave的优势

在k8s出现之前,我们常配置虚拟机来做Jenkins Slave机器。
通常做法是按照Job以及不同的业务组等准备不同环境的多台虚拟机,例如标签python,java,test_team, dev_team等的虚拟机群,跑job时,按需从特定标签的虚拟机群里选一台机器做Slave机器,跑完job后机器回收以备后用。

在k8s出现后,基于k8s动态创建pod来做Jenkins Slave有它的巨大优势,具体相对虚拟机做Slave(静态)这种方式来说,优势如下:

  1. 资源利用率方面
    虚拟机创建后就一直在那里,不管有没有Job在跑,它就一直在那。所以显然在没Job在运行是,虚拟机所占用的cpu,mem等资源可以说是闲置的。

    而在k8s中动态创建Jenkins Slave的方式时,只有要跑Job时,才会创建机器占用资源,Job结束后,机器回收,资源也被回收,达到随用随建的高效资源利用率。

  2. 资源分配情况
    虚拟机跑Job时,因为不同的Job需要的环境可能不同,常常会出现有些环境的虚拟机很忙,Job需要排队等待运行,资源不足。而另一些环境的虚拟机只被少数几个Job用,资源闲置,这种资源分配不均衡的情况。

    而基于k8s动态创建Jenkins Slave时,这种资源分配不均不会存在,整个k8s集群可以看作一个整体的资源池,每次是从资源池里动态申请所需的资源创建机器运行Job,Job运行后资源能被完全回收重新注入资源池。

  3. 扩容便利度
    随着业务的发展,常常会资源不足,满足不了日益增多的Job需求。此时需要扩容时,如果是新增虚拟机,则不可避免的涉及创建虚拟机,在Jenkins配置这台虚拟机做Slave等操作。

    而用k8s集群本身的扩容优势,当资源不足时,动态扩容方便简单,甚至对Jenkins来说不需要任何额外操作。

整体框架

Jenkins和k8s的集成整体框架如下:Jenkins基于k8s进行持续集成测试实践_第1张图片Jenkins中安装一个k8s插件Kubernetes-plugin,并配置了k8s的集群信息后,即打通了和k8s集群的通道。当需要运行Job时,Jenkins master将利用k8s集群提供的API创建Pod充作Jenkins Slave,然后正常运行Job即可。

这里的关键点是,Pod如何变成Jenkins的Slave的?以及如何根据不同的Job需求来配置Pod环境呢?这两个问题都是涉及到Pod选用的Image。

Jenkins已经很贴心的制作好了jnlp-slave Image,所以只要创建的Pod包含该Image,该Pod就化身为Jenkins Slave,可以和Jenkins Master通信,处理收取Job任务,汇报Job运行状态,运行结果等Slave的工作。

Job运行时需要的运行环境,例如Python环境,Java环境等,我们同样把它打包成不同的Image,需要哪个选取哪个。

所以,我们只需要在创建Pod时,将jnlp-slave image和环境相关的image组合成Pod的container,即可让Pod作为Jenkins Slave完成Job的运行。

落地实践

上面介绍的都是一些Jenkins和k8s集成的理论,下面我将介绍该如何落地。主要包括如下内容:

  1. Kubernetes-plugin插件安装与配置
  2. Jenkins Job的Pipline模板
  3. 在k8s中创建Pod的YAML模板
  4. 相关Image的Dockerfile模板
  5. Jenkins调度slave的性能优化

实践中涉及的项目代码可参考:jenkins_k8s_template

Kubernetes-plugin插件安装与配置

Jenkins Master上安装Kubernetes-plugin插件,然后配置好k8s集群信息如下:
Jenkins基于k8s进行持续集成测试实践_第2张图片

Jenkins Job的Pipeline模板

配置好k8s集群信息后,接下来就是在Pipeline中配置k8s Pod相关信息,声明创建k8s Pod来做Jenkins Slave运行Job。
配置如下:

pipeline {
	// 运行job所用的机器
	agent {
	    kubernetes{ // 连接k8s,并利用yamlFile创建jenkins slave
	        cloud 'kubernetes-test' //k8s集群关联
	        label 'SEQ-AUTOTEST-PYTHON36' //Pod前缀名,可用它来区分不同环境的Slave
	        defaultContainer 'python36' // [*] stages和post步骤中默认用到的container。如需指定其他container,可用语法 container("java8"){...}
	        idleMinutes 10 //所创建的pod在job结束后直到销毁前的等待时间
	        yamlFile "jenkins/jenkins_pod_template.yaml" // 指定创建pod时的yaml配置文件
	    }
	}
...
}

完整模版请参考:Jenkinsfile

在k8s中创建Pod的YAML模板

k8s具体如何创建Pod主要就是根据上文中jenkins_pod_template.yaml的YAML模板来创建,模板具体如下:

apiVersion: v1
kind: Pod
metadata:
  # 可部署pod的k8s namespace
 namespace: sqe-test
spec:
 containers:
 # jnlp环境,必选,注意此处name=jnlp不能变,jenkins才能认出来
 - name: jnlp
 image: swc-harbor.nioint.com/sqe/jnlp-slave:root_user
 imagePullPolicy: Always
 # mount的路径保持为jenkins的默认工作路径。jenkins 2.2版本默认工作路径/home/jenkins/agent
 volumeMounts:
 - mountPath: /home/jenkins/agent
 name: jenkins-slave

 # python36环境,可选
 - name: python36
 image: swc-harbor.nioint.com/sqe/automation_python36:v1
 imagePullPolicy: Always
 env:
 - name: WORKON_HOME # 设置pipenv的虚拟环境路径变量 WORKON_HOME
 value: /home/jenkins/agent/.local/share/virtualenvs/
 command:
 - cat
 tty: true
 volumeMounts: # mount的路径保持为jenkins的默认工作路径。
 - mountPath: /home/jenkins/agent
 name: jenkins-slave
 resources: # 资源限定,可调。尽量不要用太多
 limits:
 cpu: 300m
 memory: 500Mi

 # nfs远程磁盘,用于共享公共库,复用资源等
 volumes:
 - name: jenkins-slave
 nfs:
 path: /data/jenkins-slave-nfs/
 server: 10.10.129.178
 # node select 选择sqe可以使用的node机器
 nodeSelector:
 node-app: normal
 node-dept: sqe

  1. Pod中必须包含jnlp-slave container用于和Jenkins Master通信,且container名必须为jnlp
  2. Job需要的运行环境可提前制作成镜像例如python36, java8 等作为container引入Pod中。环境可堆叠,Pipeline中agent.kubernetes下可配置defaultContainer指向container名,作为Job的默认运行环境。如运行Job需切换container时,可用语法如container(“java8”){…}进行切换
  3. 挂载远程磁盘作为工作目录可以方便让Job保持项目环境不用重复创建,但jenkins 2.2以上版本注意mount到/home/jenkins/agent目录下。且最好让各个container都挂载且挂载到该目录下,不然会有很多匪夷所思的错误。jenkins 2.2以下版本mount的路径是/home/jenkins。

相关Image的Dockerfile模板

  1. jnlp-slave image 的优化
    在实践中发现,最好是把jnlp image默认user修改成root权限,否则非常不利于工作的展开。
    FROM swc-harbor.nioint.com/sqe/jnlp-slave:latest
    LABEL maintainer="[email protected]"
    USER root
    
  2. python 3.6 image Dockerfile模板
    FROM python:3.6.4
    LABEL maintainer="[email protected]"
    USER root
    # 加入国内源
    ADD ./sources.list /etc/apt/
    # 更新
    RUN apt-get update
    RUN apt-get upgrade -y
    RUN apt-get dist-upgrade -y
    # 安装工具
    RUN apt-get -y install \
           vim \
           net-tools \
           zip
    # 安装python包
    RUN pip install --upgrade pip
    RUN pip3 install pipenv
    

Jenkins调度slave的性能优化

可在jenkins master启动时,优化调度相关的一些配置信息如下,在此不做详述。

-Dhudson.model.LoadStatistics.clock=2000
-Dhudson.slaves.NodeProvisioner.recurrencePeriod=5000
-Dhudson.slaves.NodeProvisioner.initialDelay=0
-Dhudson.model.LoadStatistics.decay=0.5
-Dhudson.slaves.NodeProvisioner.MARGIN=50
-Dhudson.slaves.NodeProvisioner.MARGIN0=0.85

你可能感兴趣的:(Jenkins基于k8s进行持续集成测试实践)