基于K8s和docker的Jenkins 可伸缩持续集成系统
概述
本文档主要介绍Jenkins的可伸缩部署方式,一种是基于Docker(或者docker-swarm 集群)的部署方式,另外一种是基于kubernetes的部署方式。
由于基于kubernetes也是基于docker的,都需要用到docker进行通信和中转,因此使用同一的slave镜像将大大节省平台开发与维护成本,因此需要引入jenkins的另一个大插件pipeline。Pipeline也是jenkins 2.0以后的主要方向和升级。
Jenkins系统基于docker的应用
jenkins介绍及传统部署遇到的问题
Jenkins 是开源的一套持续集成框架,可以进行大规模的编译、测试和发布的工作,给软件开发团队带来极大的便利性。
Jenkins 的持续集成环境可以是集群化的,主要的运行模式为master-slave模式。
Jenkins 的master为Jenkins系统的控制节点,slave节点负责具体的项目编译测试等工作。
由于大公司里面需要进行编译的工程或者对象非常庞大,因此需要大量的物理节点作为slave,而且这些环节相对固定,可能很难适应其他项目的编译测试,一旦salve节点遭到破坏,需要人为的进行修复甚至重建,非常麻烦。Docker 来解决问题
Docker的问世,为我们提供了解决方案,使用docker作为jenkins slave节点可以解决slave节点遭到破坏后遇到的问题, 而且大量的工程不是每时每刻同时运行的因此可以在需要时吧docker拉起来进行编译测试,这样就节约了大量的物理节点, 解决了上述问题。
然而使用docker 同样需要集群,因此要用到集群管理工具, swarm 或者kubernetes。Swarm 一般用在小集群上,而且swarm和docker本身的借口完全一致, 因此这里就简单介绍单点docker节点作为slave。 Kubernetes作为大的docker 集群管理工具,当jenkins的工程数量非常大的时候可以用kubernetes, kubernetes的运维相对比docker 和swarm的门槛要高一点。
Jenkins master也可以使用docker来运行或者使用kubernetes来提供高可用的jenkins master。本文不对jenkins master的安装和docker运行做过多的说明。
kubernetes 管理Jenkins slave
Kubernetes 主要是用来进行docker 调度运行的,同样因为这一点通过kubernetes插件的配置,不需要管slave节点是否在线,因为kubernetes帮你负责创建和连接。这样就可以做到没有任务的时候没有任务slave节点在线,做到完全的按需启动slave和调度slave。
使用kubernetes 部署管理的jenkins slave如下:
Jenkins master 的部署
简单说明 jenkins master的安装与运行
1) 物理机上的安装
以centos为例:
yuminstall –y java java-devel
由于centos自己的yum源并没有包含jenkins因此需要添加jenkins对应的源
wget -O /etc/yum.repos.d/jenkins.repohttp://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
rpm–import http://pkg.jenkins-ci.org/redhat-stable/jenkins-ci.org.key
yum install –y Jenkins
修改jenkins 的配置文件 /etc/sysconfig/jenkins
systemctl enable jenkins.service
systemctl start jenkins.service
2) 使用docker来运行
自己制作镜像或者网上下载jenkins_master的镜像。(我这里是下载的镜像)
dockerrun –idt –v /home/jenkins:/home/jenkins -v /home/data:/var/jenkins_home -p8080:8080 -p 50000:50000 jenkins-master
这样既可。
https://hub.docker.com/_/jenkins/ 可以下载到jenkins master镜像
Jenkinsmaster配置和插件安装
jenkins 系统初始化
这里以jenkins master运行在docker 中为例
1) 这里每次全新的jenkins初始化的时候都会有一个任意的密码,路径在/var/jenkins_home/secrets/initialAdminPassword,按 照提示解锁jenkins:
2) 解锁后,系统会根据网络情况提示安装一些插件:
3) 安装过程如下:
安装完成后设置系统管理员账户和密码。
然后登陆即可使用。
Jenkins Docker 插件安装与kubernetes 插件安装
1) 插件更新中心配置:
登陆jenkins–>系统管理–>插件管理–>高级
首先配置涉及站点,默认的是 官方的:http://updates.jenkins-ci.org/update-center.json
也可以配置日本的或者俄罗斯的 http://mirror.esuni.jp/jenkins/updates/update-center.json
http://mirror.yandex.ru/mirrors/jenkins/updates/update-center.json
配置完以后必须点右下角的立即获取
也可以在可选插件哪个页面的下面点击获取。
2) 安装需要的插件:
在可选插件页面勾选需要安装的插件,点击直接安装即可。
例如选择smartjenkins插件:
我们这里需要找的是kubernetes的插件和docker的插件进行安装,如果安装过程中有些插件安装失败,则手动下载插 件然后再高级里面选择上传插件进行安装:
直到安装完成所有需要的插件。
注:pipeline的插件在一开始初始化的时候安装完成了。
使用docker运行jenkins slave并连接到master
Jenkins master 连接slave 有两种模式,一直是master主动发起连接,主要通过ssh 来进行连接,另外一种是slave 主动连接master,使用的jnlp协议。
我们使用docker来运行jenkins slave 都可以,但是要做到没有任务在编译测试的时候没有slave在线则只能通过 jnlp来进行连接而去必须使用kubernetes来调度。
我们这里讨论的是使用单独的或者几个slave长期在线,进行项目的编译测试,都是由master发起连接的。
https://hub.docker.com/u/jenkinsci/ slave镜像下载地址上
docker 运行jenkins slave (ssh 模式)
这种模式docker 运行一个slave 容器跟普通物理机使用完全一致,这里不做说明。
同样可以再在同一个slave节点(docker 容器)上绑定很多个工程或者任务。
docker 运行jenkins slave (jnlp 模式)
Jnlp 模式的则相对应用的比较少,jnlp 是由jenkins slave节点(物理节点,虚机或者容器均可)发起连接的, 他 会根据配置的jenkins master的url , Jenkins连接的token和jenkins slave name( lable)来进行进行连接。
举个例子:
登录jenkins–>系统管理–>节点管理–>新建节点
那么slave 进行运行连接的时候4个参数是:
1. –url
3. 54cf091374806d8db7b9cd3977e23d080c955fa6fa33dd6c33dd594aa7b79350
4. jnlp_test
command as : Jenkins-slave –url http://172.25.8.10:8090 54cf091374806d8db7b9cd3977e23d080c955fa6fa33dd6c33dd594aa7b79350 jnlp_test
之后的编译跟ssh 模式一模一样
如何做到方便高效已经保持少量的slave在线
上面介绍的这两种方式都是使用一个slave进行任务的编译测试,跟传统的部署方式对比仅仅只是增加了编译环境的数 量,但是每个编译环境跟物理机基本一致。
而且由于docker 环境需要进行调试和连接master,也比较麻烦,作为代码开发者一般只管理工程代码怎样编译,可能 根本不懂jenkins,怎么办?
大量的jenkins-slave(dokcer)在线jenkinsmaster的管理效率低下,而且可能由于slave(docker)在线,某些任务的编 译资源被挤占,编译效率下降,怎么办?
这些问题的解决办法是使用docker in docker 来处理。
每个物理节点上长时间的只有一个jenkins-slave(进程或者docker容器都行,最好是容器—无状态,可重新来,降低运 维成本),所有的任务绑定到这几个slave上,每个任务的编译过程是启动自己的容器——下载代码——编译——测试等。
把编译过程写成脚本:
docker pull
docker run
docker exec *** git clone
docker exec build
***
那么什么是docker in docker
使用docker in docker 来进行CI
Dockerin docker 就是在docker中运行docker, 单实质上是将host的docker.sock 挂载到容器中,然后再容器中创建的容器,其实是运行在host机器上呢。
使用docker in docker 来进行CI
Docker in docker其实就是让一个物理机上只有一个jenkins slave在运行,这个jenkinsslave 仅仅只负责任务转发,相当于是一个标准接口, 这样开发人员只需要知道自己的软件需要什么样的docker环境进行编译,而不用关注这个docker 容器怎样跟jenkins master连接。
这时候 Jenkins slave的运行如下:
docker run -it -u root -v /var/run/docker.sock:/var/run/docker.sock my_jnlp_test:0.1 -url http://172.25.8.10:9080 54cf091374806d8db7b9cd3977e23d080c955fa6fa33dd6c33dd594aa7b79350 jnlp_test
同样带来一些问题,例如 docker 脚本的编写,docker状况的监控,编译构建结果的查看与测试等等。
Docker 插件和pipeline 插件帮你搞定这些。
pipeline 来解决docker in docker带来的问题
Pipeline是jenkins 2.0 的主要升级。其主要是用来定义工作流的,这里结合docker来更好管理docker in docker 的编译。
同样对于多个依赖关系的任务进行更好的CI 管理,同时其stage view 更直观的反应CI运行的状况。
Pipeline工程的创建和配置:
Jenkins–>新建–>需要选择pipeline
项目配置中仅仅需要配置pipeline部分
写一段pipeline script 就可以进行构建了
node(‘jnlp_test1’){
stage “Container Prep”
docker.image(‘my_docker:0.1’).inside{
stage ‘Checkout’
git url:’http://101.71.10.3:15480/chenmiao/dhcAPI.git’
stage ‘Build’
sh “mvn clean package”
}
}Node 用来制定在哪一个slave节点上进行构建
Stage 用来给任务分段
这些具体的得看自己学习啦,我这里也是简单的一个例子。
编译的效果如下:
比较清晰的显示出每一个阶段用了多长时间,哪个阶段失败了。
这个到目前为止解决了基于固定的物理服务器,尽可能少的在线编译问题,但不能解决占用冲突—即可能1000个任务中只有20个在线,但这20个在线的任务是同一个物理服务器上的,结果是编译依旧非常低效。kubernetes进行按需创建slave
kubernetes 的引入是为了高效平衡的对docker进行调度,可以有效解决上述的问题。
Jenkins环境上kubernetes的配置:
登录Jenkins–>系统管理–>系统设置:
搜索“云” –>增加一个云–>kubernetes
然后配置kubernetes:
这里必配项有:Name、Kubernetes URL、kubernetesNamespace、 Jenkins URL 以及 Kubernetes Pod Template(大项,这一项最少需要一个,否则不能使用kubernetes)
再来配置jenkins-slave 对应的docker的信息,由于kubernetes是报docker封装成Pod来管理,即配置kubernetes Pod Template:
这里需要名却的是第一处的Name 就是子啊项目配置时的slave节点,label 是kubernetes进行管理用的。其余的配置项为slave容器需要的配置。
Jenkins ci工程的配置
Pipeline Test1 for example:
这里只需要指定node为kubernetes Pod配置的哪个名字即可。
自由风格的工程配置一样:
这样既可以在对应的docker 里面进行项目CI。
在没有任务运行的时候,系统上是没有slave的:
Kubernetes get pod的结果也一样没有jnlp-slave的Pod
root@debian:/home/Daniel/jnlp_slave# kubectl -s 172.25.5.150:8080 get pod –all-namespaces -o wide NAMESPACE NAME READY STATUS RESTARTS AGE NODE default kube-apiserver-172.25.5.150 1/1 Running 3 14d 172.25.5.150 default kube-controller-manager-172.25.5.150 1/1 Running 0 14d 172.25.5.150 default kube-scheduler-172.25.5.150 1/1 Running 0 14d 172.25.5.150 kube-system kube-ui-v1-1dn43 1/1 Running 0 10d 172.25.5.155 |
运行任务时:
Kubernetes got pod 中有jnlp-slave 的pod
root@debian:/home/Daniel/jnlp_slave# kubectl -s 172.25.5.150:8080 get pod –all-namespaces -o wide NAMESPACE NAME READY STATUS RESTARTS AGE NODE default kube-apiserver-172.25.5.150 1/1 Running 3 14d 172.25.5.150 default kube-controller-manager-172.25.5.150 1/1 Running 0 14d 172.25.5.150 default kube-scheduler-172.25.5.150 1/1 Running 0 14d 172.25.5.150 jenkins jnlp-slave-4eeed2fbc128e 0/1 Running 0 3s 172.25.5.155 kube-system kube-ui-v1-1dn43 1/1 Running 0 10d 172.25.5.155 |
问题记录
1. 我们使用的kubernetes版本不支持Pod name 和lable中使用下划线,因此前期Pod一直创建不成功。
2. Kubernetes Pod template 中Container的配置项 Commandto run slave agent 以及Arguments topass to the command配置一直有错误:Command 最好使用全路径, Arguments 最好用括号
3. Jenkins master 和jenkins slave 运行的时候需要挂载卷,这些卷如果是host上的目录需要将其的所有者改为jenkins 里面运行的用户,而且容器里面的卷也需要修改其所有者。
chown Jenkins:Jenkins/home/Jenkins 为例
4. Jenkins maste 和jenkins slav镜像需要进行定制,网上下载的镜像仅保证最简单的连接。
</article>
<div class="article-bar-bottom">
<div class="tags-box artic-tag-box">
<span class="label">文章标签:</span>
<a class="tag-link" href="http://so.csdn.net/so/search/s.do?q=持续集成系统&t=blog" target="_blank">持续集成系统 </a><a class="tag-link" href="http://so.csdn.net/so/search/s.do?q=集群&t=blog" target="_blank">集群 </a>
</div>
<div class="tags-box">
<span class="label">个人分类:</span>
<a class="tag-link" href="https://blog.csdn.net/daniel_greenspan/article/category/6540627" target="_blank">Jenkins </a><a class="tag-link" href="https://blog.csdn.net/daniel_greenspan/article/category/6540628" target="_blank">kubernetes </a>
</div>
</div>
<!-- !empty($pre_next_article[0]) -->
</div>