
Jenkins 基于 Kubernetes 的动态和静态节点
提到基于 Kubernetes 的 CI/CD,可以使用的工具有很多,比如 Jenkins、Gitlab CI、Drone 之类的,我们这里会使用大家最为熟悉的 Jenkins 来做 CI/CD 的工具。
安装
既然要基于 Kubernetes 来做 CI/CD,我们这里最好还是将 Jenkins 安装到 Kubernetes 集群当中,安装的方式也很多,我们这里仍然还是使用手动的方式,这样可以了解更多细节,对应的资源清单文件如下所示:
我们这里使用 jenkins/jenkins:lts-jdk11
镜像,这是 jenkins 官方的 Docker 镜像,然后也有一些环境变量,当然我们也可以根据自己的需求来定制一个镜像,比如我们可以将一些插件打包在自定义的镜像当中,可以参考文档:https://github.com/jenkinsci/docker,我们这里使用默认的官方镜像就行,另外一个还需要注意的数据的持久化,将容器的 /var/jenkins_home
目录持久化即可,我们这里使用的是 Local PV 的方式。
由于我们这里使用的镜像内部运行的用户 uid=1000
,所以我们这里挂载出来后会出现权限问题,为解决这个问题,我们同样还是用一个简单的 initContainer
来修改下我们挂载的数据目录。
另外由于 jenkens 会对 update-center.json
做签名校验安全检查,这里我们需要先提前关闭,否则下面更改插件源可能会失败,通过配置环境变量 JAVA_OPTS=-Dhudson.model.DownloadService.noSignatureCheck=true
即可。
另外我们这里还需要使用到一个拥有相关权限的 serviceAccount:jenkins
,我们这里只是给 jenkins 赋予了一些必要的权限,当然如果你对 serviceAccount 的权限不是很熟悉的话,我们给这个 sa 绑定一个 cluster-admin
的集群角色权限也是可以的,当然这样具有一定的安全风险。最后就是通过 Ingress 来暴露我们的服务,这个比较简单。
我们直接来创建 jenkins 的资源清单即可:
看到上面的 run: Jenkins is fully up and running
信息就证明我们的 Jenkins 应用以前启动起来了。
然后我们可以通过 Ingress 中定义的域名 jenkins.k8s.local
(需要做 DNS 解析或者在本地 /etc/hosts
中添加映射)来访问 jenkins 服务:
然后可以执行下面的命令获取解锁的管理员密码:
然后跳过插件安装,选择默认安装插件过程会非常慢(也可以选择安装推荐的插件),点击右上角关闭选择插件。
跳过后会直接进入 Jenkins 就绪页面,直接点击开始使用即可:
然后就可以进入 Jenkins 主页了。
首先安装中文插件(如果想要中文界面的话),搜索 Localization: Chinese
:
安装重启完成后,会自动跳转到登录页面:
这里还是使用 admin 和前面的初始密码进行登录。然后可以进入用户管理页面 http://jenkins.k8s.local/user/admin/configure 修改用户密码:
然后就可以使用新的密码登录了。
接下来我们可以安装其他需要的插件,比如 Pipeline
插件。Pipeline
是 Jenkins 的一个核心插件,它定义了一套 DSL 语言,可以用来编写 Pipeline 脚本,这个脚本可以实现从代码构建到部署的整个流程。在使用 Pipeline 类型的项目时,需要提前安装 Jenkins 的 Pipeline 插件。
安装好插件后新建一个 Pipeline 类型的作业:
自由风格项目和 Pipeline 类型的项目区别是,构建部分的操作都是在页面上面完成的。Pipeline 的构建任务描述都是通过代码的方式。
保存后我们可以点击立即构建执行这个任务,也可以查看这个任务的执行结果输出:
架构
Jenkins 安装完成了,接下来我们不用急着就去使用,我们要了解下在 Kubernetes 环境下面使用 Jenkins 有什么好处。
我们知道持续构建与发布是我们日常工作中必不可少的一个步骤,目前大多公司都采用 Jenkins 集群来搭建符合需求的 CI/CD 流程,然而传统的 Jenkins Slave 一主多从方式会存在一些痛点,比如:
- 主 Master 发生单点故障时,整个流程都不可用了
- 每个 Slave 的配置环境不一样,来完成不同语言的编译打包等操作,但是这些差异化的配置导致管理起来非常不方便,维护起来也是比较费劲
- 资源分配不均衡,有的 Slave 要运行的 job 出现排队等待,而有的 Slave 处于空闲状态
- 资源有浪费,每台 Slave 可能是物理机或者虚拟机,当 Slave 处于空闲状态时,也不会完全释放掉资源。
正因为上面的这些种种痛点,我们渴望一种更高效更可靠的方式来完成这个 CI/CD 流程,而 Docker 虚拟化容器技术能很好的解决这个痛点,又特别是在 Kubernetes 集群环境下面能够更好来解决上面的问题,下图是基于 Kubernetes 搭建 Jenkins 集群的简单示意图:
从图上可以看到 Jenkins Master
和 Jenkins Slave
以 Pod 形式运行在 Kubernetes 集群的 Node 上,Master 运行在其中一个节点,并且将其配置数据存储到一个 Volume 上去,Slave 运行在各个节点上,并且它不是一直处于运行状态,它会按照需求动态的创建并自动删除。
这种方式的工作流程大致为:当 Jenkins Master 接受到 Build 请求时,会根据配置的 Label 动态创建一个运行在 Pod 中的 Jenkins Slave 并注册到 Master 上,当运行完 Job 后,这个 Slave 会被注销并且这个 Pod 也会自动删除,恢复到最初状态。
那么我们使用这种方式带来了哪些好处呢?
- 服务高可用,当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master 容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用。
- 动态伸缩,合理使用资源,每次运行 Job 时,会自动创建一个 Jenkins Slave,Job 完成后,Slave 自动注销并删除容器,资源自动释放,而且 Kubernetes 会根据每个资源的使用情况,动态分配 Slave 到空闲的节点上创建,降低出现因某节点资源利用率高,还排队等待在该节点的情况。
- 扩展性好,当 Kubernetes 集群的资源严重不足而导致 Job 排队等待时,可以很容易的添加一个 Kubernetes Node 到集群中,从而实现扩展。 是不是以前我们面临的种种问题在 Kubernetes 集群环境下面是不是都没有了啊?看上去非常完美。
文章转载自公众号:k8s技术圈
