用jenkins来做持续集成测试相信在测试工作中大多数人都接触过,这里不过多赘述。简单来说,我们在Jenkins上配置了job(通常以Pipline的形式配置)后,Jenkins Master做两件事,1.选择要运行job的Jenkins Slave机器;2. 在选取的Slave机器上运行job。
本文主要关注第一点,如何准备待运行Job的Jenkins Slave机器。
在k8s出现之前,我们常配置虚拟机来做Jenkins Slave机器。
通常做法是按照Job以及不同的业务组等准备不同环境的多台虚拟机,例如标签python,java,test_team, dev_team等的虚拟机群,跑job时,按需从特定标签的虚拟机群里选一台机器做Slave机器,跑完job后机器回收以备后用。
在k8s出现后,基于k8s动态创建pod来做Jenkins Slave有它的巨大优势,具体相对虚拟机做Slave(静态)这种方式来说,优势如下:
资源利用率方面
虚拟机创建后就一直在那里,不管有没有Job在跑,它就一直在那。所以显然在没Job在运行是,虚拟机所占用的cpu,mem等资源可以说是闲置的。
而在k8s中动态创建Jenkins Slave的方式时,只有要跑Job时,才会创建机器占用资源,Job结束后,机器回收,资源也被回收,达到随用随建的高效资源利用率。
资源分配情况
虚拟机跑Job时,因为不同的Job需要的环境可能不同,常常会出现有些环境的虚拟机很忙,Job需要排队等待运行,资源不足。而另一些环境的虚拟机只被少数几个Job用,资源闲置,这种资源分配不均衡的情况。
而基于k8s动态创建Jenkins Slave时,这种资源分配不均不会存在,整个k8s集群可以看作一个整体的资源池,每次是从资源池里动态申请所需的资源创建机器运行Job,Job运行后资源能被完全回收重新注入资源池。
扩容便利度
随着业务的发展,常常会资源不足,满足不了日益增多的Job需求。此时需要扩容时,如果是新增虚拟机,则不可避免的涉及创建虚拟机,在Jenkins配置这台虚拟机做Slave等操作。
而用k8s集群本身的扩容优势,当资源不足时,动态扩容方便简单,甚至对Jenkins来说不需要任何额外操作。
Jenkins和k8s的集成整体框架如下: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集成的理论,下面我将介绍该如何落地。主要包括如下内容:
实践中涉及的项目代码可参考:jenkins_k8s_template
Jenkins Master上安装Kubernetes-plugin插件,然后配置好k8s集群信息如下:
配置好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主要就是根据上文中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
FROM swc-harbor.nioint.com/sqe/jnlp-slave:latest
LABEL maintainer="[email protected]"
USER root
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 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