在本教程中,我们将使用Rancher在Kubernetes上部署和伸缩Jenkins。按照本文的步骤一步步来,你将会使用到我们用来测试实际构建作业的master-agent体系结构,创建出功能齐全的Jenkins。

介 绍

Jenkins是一个开源的持续集成和持续交付工具,它可以用来自动构建、测试和部署软件。在全世界有超过一百万的用户在使用Jenkins,它是目前最流行的自动化服务器。Jenkins的优势包括:

  • 是一个拥有庞大社区支持的开源软件

  • 基于Java的代码库,使其可以移植到所有主要平台

  • 有超过1000个插件的丰富生态系统

Jenkins能够与主流的源代码管理系统(Git、SVN、Mercurial以及CVS)、主流的构建工具(Ant、Maven、Grunt)、shell脚本和Windows批处理命令、测试框架、报表生成器的都良好地协同工作。Jenkins的插件还提供了对Docker和Kubernetes的支持,Docker和Kubernetes能够创建、部署基于云的微服务环境,并且把它们投入到测试和生产部署中。

Jenkins支持master-agent体系结构(许多build agents/构建代理根据master服务器调度来完成任务),使其具有高度的可伸缩性。Master的工作是安排构建作业,将作业分发给代理实际执行,监视这些代理并获得构建的结果。除此之外,master服务器还可以直接执行构建作业。

代理的任务是构建从master服务器发送过来的作业。作业可以配置在指定类型的代理商运行,如果没有特别需求,Jenkins就简单地选择下一个可用代理。

Jenkins的可伸缩性可以带来许多便利:

  • 并行运行多个构建方案

  • 自动地挂载和移除代理,节约开销

  • 分配负载

当然,尽管Jenkins包含了这种开箱即用的可伸缩性特性,配置它的过程却并不是很简单。有许多能够扩展Jenkins的选择,而其中一种强大的选择就是使用Kubernetes。

Kubernetes是什么?

Kubernetes是一个开源的容器编排工具。它主要用来帮助操作人员部署、伸缩、更新和维护服务,以及提供服务发现机制来管理节点集群上的容器化应用程序。你可以查看官方文档,了解更多关于Kubernetes的内容和用途:

https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/

Kubernetes是管理可伸缩的、基于容器的工作负载的最佳工具之一。包括Jenkins在内的大多数应用程序都可以进行容器化,而这也使得Kubernetes成为了非常好的选择。

项目目标

在我们开始之前,先花一点时间描述一下我们将要构建的系统。

我们首先会将Jenkins master实例部署到Kubernetes集群上。我们将使用Jenkins的kubernetes插件。我们将使用Jenkins的kubernetes插件,通过提供动态代理来适配当前的工作负载,在集群上扩展Jenkins。该插件基于具体的Docker镜像启动代理,为每个构建创建一个Kubernetes pod。在构建完成后,Jenkins将删除pod来节省资源。代理则使用JNLP(Java Network Launch Protocol,Java网络启动协议)启动,因此容器能够在启动和运行之后自动连接到Jenkins master。

前期准备和安装

你需要准备这些东西来完成本教程:

Linux机器用于运行Rancher:我们还会使用它构建自定义的Jenkins镜像。可以按照Rancher安装入门指南在主机上安装Docker和Rancher:

https://rancher.com/quick-start/

Docker Hub账户:我们需要一个带有容器镜像仓库的账户,为Jenkins master和代理推送自定义镜像。

GCP账户:我们将在GCP上部署Kubernetes集群。谷歌云平台的free-tier应该能够完成这项工作。您实际使用其他公有云,操作也是一样的。

为Jenkins组件构建自定义的镜像

那么我们先从给Jenkins组件构建自定义镜像开始,将它们推送到Docker Hub。

登录到Linux服务器,在那里你就可以运行Rancher并构建镜像。如果还没有安装Docker和Rancher,请按照Rancher快速入门指南在主机上安装Docker和Rancher。主机准备好后,我们就可以准备dockerfile了。

编写Jenkins Master Dockerfile

我们先在当前文件夹下创建一个名为Dockerfile-jenkins-master的文件,来定义Jenkins master镜像:

在文件内部,加入下面Dockerfile构建命令。这些命令使用主Jenkins Docker镜像作为基础,配置我们用于部署到Kubernetes集群的插件:

完成后,保存并关闭文件

编写Jenkins代理的Dockerfiles

接下来,我们就可以为Jenkins代理创建Dockerfile文件了。我们将创建两个代理镜像,演示Jenkins如何正确识别为每个作业准备的正确代理。

在当前目录中创建一个空文件。我们将把它复制到镜像中作为正在构建的每个代理的标识符:

现在,为第一个代理镜像创建Dockerfile

该镜像将把空文件复制到一个唯一的名称,标记所使用的代理。

完成之后保存并关闭文件

最后,定义第二个代理。这个和前一个代理相同,不过使用了不同的文件标识符:

保存并关闭文件

现在你的工作目录看起来应该是这样的:

构建镜像并Push到Docker Hub

有了准备好的Dockerfile,我们现在就准备构建和push镜像到Docker Hub啦。

首先构建Jenkins master的镜像:

注意:下面的命令中,将 <dockerhub_user>替换成自己的Docker Hub账户名

[root@rancher-instance jenkins-kubernetes]# docker build -f Dockerfile-jenkins-master -t <dockerhub_user>/jenkins-master .

当命令的结果返回之后,查看新创建的镜像:

使用账户凭证登录到Docker Hub:

[root@rancher-instance jenkins-kubernetes]# docker loginLogin with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: Password: Login Succeeded

现在,将镜像推送到Docker Hub:

注意:下面的命令中,同样注意替换成自己的Docker Hub账户

你可能还需要同样的命令来构建第二个镜像给Jenkins JNLP代理:

注意:下面的命令中,注意将<dockerhub_user>替换成自己的Docker Hub账户名

如果一切顺利,你就能在Docker Hub账户中看到下图这个状态:

使用Rancher部署集群

现在我们的镜像已经发布,就可以使用Rancher来帮助部署GKE集群了。如果您之前安装了Rancher,通过web浏览器访问服务器的ip地址就能登录到实例了。

接下来,创建新的GKE集群。这里为了创建具有访问权限的服务账户,你需要登录到谷歌云账户。使用其他的公有云服务所需的步骤也是相似的,具体可以参考文档学习如何创建服务账号,以及如何与Rancher一起部署集群:

https://rancher.com/docs/rancher/v2.x/en/cluster-provisioning/hosted-kubernetes-clusters/

在集群上部署Jenkins

在集群准备好之后,我们就可以部署Jenkins master和创建一些服务了。如果你对kubectl比较熟悉,你可以直接用命令行来实现;不过通过Rancher的UI,你也能很容易地部署所有需要的组件。

无论你选择何种方式将工作负载添加到集群上,都需要在本地计算机上创建下面的文件来定义需要创建的对象。

首先创建一个文件定义Jenkins部署:

在文件里粘贴下面的内容:

注意:下面的内容中将<dockerhub_user>替换成自己的Docker Hub账户名

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: jenkins spec: replicas: 1 template: metadata: labels: app: jenkins spec: containers: - name: jenkins image: <dockerhub_user>/jenkins-master env: - name: JAVA_OPTS value: -Djenkins.install.runSetupWizard=false ports: - name: http-port containerPort: 8080 - name: jnlp-port containerPort: 50000 volumeMounts: - name: jenkins-home mountPath: /var/jenkins_home volumes: - name: jenkins-home emptyDir: {}

下面,创建一个文件配置我们需要的两个服务。

一个是LoadBalancer服务,它将提供一个公开的IP地址便于我们在Internet上访问Jenkins。另一个是ClusterIP服务,用于在master和代理之间的内部通信,之后会用到该服务:

在文件内,复制下面的YAML结构:

apiVersion: v1 kind: Service metadata: name: jenkins spec: type: LoadBalancer ports: - port: 80 targetPort: 8080 selector: app: jenkins apiVersion: v1 kind: Service metadata: name: jenkins-jnlp spec: type: ClusterIP ports: - port: 50000 targetPort: 50000 selector: app: jenkins

在Rancher上,点击自己管理的集群(例子中名为jenkins)。在左上角的菜单中,选择Default项目,然后选择Workloads选项卡。

现在,点击Import YAML。在接下来的页面中,点击右上角的Read from a file按钮。选择在本地创建的deployment.yml文件并点击Import。

Rancher将在集群上面部署一个基于你Jenkins master镜像的pod

接下来,我们需要在Jenkins master上配置访问UI的方式。

在Load Balanced选项卡中,按照先前导入文件一样的操作。单击Import YAML按钮,接着点Read from a file按钮。然后从自己的电脑中选择service.yml文件,点击Import按钮。

Rancher会开始创建你的服务。部署负载均衡会花费一些时间。

在service状态成为Active后,你可以点击在负载均衡器行后侧的三个垂直点,选择View/Edit YAML来找到它的公共IP地址。在这里,向下滚动界面找到在status->loadBalancer->ingress->ip下的IP地址。

这样我们就可以通过该IP地址在web浏览器中访问Jenkins UI了。

配置动态的构建代理

有了Jenkins master启动运行后,我们可以进一步配置动态构建代理,以在必要的时候可以自动启动Pods。

禁用默认Master构建代理

Jenkins UI中左侧的Build Executor Status下,默认配置了两个Executor,等待执行构建作业,它们是由Jenkins master提供的。

主实例应该只负责调度构建作业、将作业分发给代理以供执行、监视代理并获取构建结果。因为我们不希望主实例执行构建,因此要禁用这些。

点击Manage Nodes之后的Manage Jenkins。

单击与master行上的齿轮图标。

接下来的页面中,把# of executors设置成0,点击Save。

这两个空闲的executors将从UI左侧的Build Executor Status中删除。

收集配置信息

为了在Kubernetes集群上自动部署构建代理,我们需要一些信息来配置Jenkins。我们需要三条来自GCP账户的信息以及一条来自ClusterIP服务中的信息。

在你的GCP账户中,选择Kubernetes Engine,接着是Clusters,然后点击集群的名称。在Detail列中,复制端点IP供之后使用。这是我们需要让Jenkins连接到集群的URL:

下一步,点击端点右侧的Show credentials。复制Username和Password。

现在,切换到Rancher UI。在左上角菜单中,选择Jenkins集群上的Default项目。在上方的导航窗口中选择Workloads选项卡,然后单击页面上的Service Discovery选项卡:

点击jenkins-jnlp行上垂直的三个点,然后单击View/Edit YAML。复制spec > clusterIP以及spec > ports > port中的值备用。

配置Jenkins Kubernetes插件

返回主Jenkins仪表盘,点击Manage Jenkins,然后选择Manage Plugins:

点击Installed选项卡并查看Kubernetes插件是否安装:

现在我们来配置插件。前往Manage Jenkins并选择Configure System:

滑到页面底部的Cloud部分。点击Add a new cloud,选择Kubernetes。

在下面的表单中,Kubernetes URL字段上输入https://,然后输入从GCP账户复制的集群端点IP地址。

在Credentials下,点击Add按钮,选择Jenkins。在出现的表单上,输入从GCP账户复制的用户名和密码,单击底部的Add按钮。

返回到Kubernetes表单,从Credentials下拉菜单中选择刚才添加的凭据并单击Test Connection按钮。如果配置正确,则会显示“Connection test successful”。

现在,向下滚动到页面底部的Images部分,单击Add Pod Template按钮,然后选择Kubernetes Pod Template。 使用唯一值填写“Name”和“Labels”字段,以标识您的第一个代理。 我们将使用标签指定应该使用哪个代理镜像来运行每个构建。

接下来,在Jenkins tunnel字段中,输入你在Rancher UI中从jenkins-jnlp服务检索到的IP地址和端口,用冒号分隔:

现在,在Container字段中,单击Add Container按钮并选择Container Template,在弹出的内容中填写以下字段:

  • Name: jnlp(这是Jenkins代理需要的)

  • Docker image:<dockerhub_user>/Jenkins-slave-jnlp1(确保更改Docker Hub用户名)

  • Command to run:删除这里的值

  • Arguments to pass to the command:删除这里的值

其余字段保持原样。

接下来,单击Add Pod Template按钮,再次选择Kubernetes Pod Template。对创建的第二个代理镜像重复刚才的过程,需要注意的是,在需要的时候要修改那些对应于第二个镜像的值:

单击Save按钮保存修改并继续。

测试动态构建作业

现在我们已经完成了配置工作,我们可以创建一些构建作业,保证Jenkins能够在Kubernetes之上进行伸缩。这里我们将为每个Jenkins代理创建5个构建作业。

在Jenkins主页面,单击左侧的New Item,为第一个代理的第一个构建输入名称,选择Freestyle project并单击OK按钮。

在下一页的Label Expression字段中,输入你为第一个Jenkins代理镜像设置的标签,如果单击字段之外,会出现一条消息,提示标签由云提供服务。

向下滚动到Build Environment部分,检查Color ANSI Console Output。

在Build部分,单击Add build step并选择Execute shell。把下面的脚本粘贴进去。

完成之后单击Save。

给第一个代理创建另外四个工作则是单击New Item,填写新名称并使用Copy from字段来从第一个构建中复制。你可以在无需对第一个构建作更改的情况下保存每个构建。

接下来,为第二个Jenkins代理配置第一个作业。单击New Item,给第二个代理的第一个作业选个名字,再一次从第一个代理中复制作业。这一次我们将在保存之前修改配置页面上的字段。

首先,修改Label Expression字段匹配第二个代理的标签。

接着,用下面的脚本替换掉Build部分文本框中的脚本:

完成后单击Save。

同样按照刚刚我们的流程,为第二个代理创建另外四个构建。

现在,转回到主页面,单击每行最右边的图标,启动全部刚刚创建的10个作业。在启动之后,它们会按照Build Queue部分的指示排队等待执行:

大约几秒钟之后,会开始创建Pods来执行构建(你可以在Rancher的Workload选项卡中检验这一点)。Jenkins会为每个作业创建一个pod。在每个代理启动时,它连接到master并从队列中接收要执行的作业。

代理完成了自己的工作后,它就会自动从集群中删除:

要检查作业的状态,可以单击每个代理中的一项作业。从Build History中单击构建,然后点击Console Output。由第一个代理执行的作业应该指定使用了jenkins-slave1 Docker镜像,而由第二个代理执行的构建应该指定使用了jenkins-slave2镜像:

如果你得到了上面的输出,那么Jenkins的配置就是正确的,而且是按照预期的方式在运行的。现在你就可以开始定制自己的Kubernetes的构建系统,帮助自己的团队测试和发布软件啦。

结 论

在本文中,我们配置了Jenkins来按需自动部署构建代理,将其连接到了Rancher管理的Kubernetes集群。为此,我们完成了下面的步骤:

  • 使用Rancher创建了一个集群

  • 为Jenkins master和代理创建了自定义Docker镜像

  • 将Jenkins master和L4 LoadBalancer服务部署在Kubernetes集群上

  • 在集群上配置了Jenkins kubernetes插件,自动生成动态代理

  • 使用带有专用代理镜像的多个构建作业测试场景

本文着重展现了设置Jenkins master和代理体系结构的基本的必要配置。我们了解了Jenkins如何使用JNLP启动代理,以及容器如何自动连接到Jenkins master来接受指令。为了实现这一点,我们使用Rancher创建集群、部署工作负载并监控产生的Pods。在这之后,我们又依靠Jenkins Kubernetes插件将所有不同的组件连接在了一起。