1987WEB视界-分享互联网热门产品和行业

您现在的位置是:首页 > WEB开发 > 正文

WEB开发

Jenkins使用痛点基于k8s编译的job的Workspace访问改造

1987web2023-10-06WEB开发129

来这里找志同道合的小伙伴!

相信接触过 devops、CI/CD 这些概念的同学都听说过Jenkins,在各大中型 IT 和互联网公司中,它几乎一定存在于 devops 工具链的最核心位置。 Jenkins 是目前开源世界中用户量最大、生态最完善、功能最强大的持续集成工具,它搭配完善的插件体系,几乎能完成你能想到的 devops 链上的所有事情。

不过,Jenkins 也有一些让用户觉得很不方便的地方,本文将聚焦解决 Jenkins 使用中的一个痛点。接下来您将花7-10分钟,跟我一起来定位并解决这个问题。

痛点

在谈到待解决的问题之前,我们需要先明确一些情况。

我们都知道,Jenkins 从架构上看基本属于单机软件,它不直接支持横向扩展和数据共享。为了应对越来越多的用户和 job,Jenkins 支持了 master-slave 的执行模式,用户可以在 master 节点上创建和配置任务,不过真正执行任务却是在 slave 节点上,两者通过 jnlp 等网络协议传输数据。这样对用户来说 slave 节点几乎是透明的,对 master 节点来说又能分散运算压力,可谓是两全其美!

其中最受欢迎的 slave,恐怕要数运行在 kubernetes 集群上的动态 slave 节点了(Jenkins 通过 Kubernetes Plugin 实现了在 kubernetes 集群上按需动态起停 pod 来执行 job 任务)。动态 slave 节点的好处是:有任务才创建、运行完就销毁,对资源的利用率简直太理想了!

Jenkins + kubernetes 架构如下图所示:

图片来自网络

那么问题来了!

如果我要执行一个编译打包的 job,在 Jenkins master 节点上创建并配置好了任务,然后任务在 kubernetes 创建的一个 pod 里顺利执行了,然后 pod 告诉 Jenkins master 节点说 job 执行成功了,然后 pod 被销毁了…… 那我编译出来的包呢?也随着 pod 被销毁了......

以前我们为了解决这个问题,一般都需要在 Jenkins file 里面使用相关的工具(如:curl),然后将编译好的包传输到某个第三方服务上。说实话,这样操作太麻烦、不人性化、强依赖、强耦合 …… 差评!

今天我们要解决的就是这个问题!

再次明确一下我们的需求:取回 kubernetes 上运行的 job 的 Workspace,并且能够在 Jenkins 页面上访问和下载文件

想一想怎么做

子曰:写代码之前先想好怎么做,不然写出来也是 bug!

我们先来捋一下思路,既然是编译任务,那肯定会至少包含从代码库拉取源代码和执行编译两个步骤,也就是说源码和编译出来的包肯定是在 slave 节点的某个路径上,而最后我们需要在 Jenkins 的页面上查看到这个路径的内容,并且在 kubernetes 的 pod 被销毁以后还能看到,那自然是:

  1. 需要将这个 job 的 Workspace 拷贝出来放到一个 Jenkins master 服务能访问的路径下;

  2. 考虑到页面响应的时效问题,最理想的是将这个 job 的 Workspace 拷贝到 master 节点上的 Workspace 下。

我能想到的满足以上两点,并且成本最低(不依赖第三方服务)的方法是:用 nfs-util 将 slave 节点的 Workspace 目录挂载到 master 节点上 $JENKINS_HOME 路径下的 Workspace 文件夹上,这样 master 和 slave 节点的 Workspace 就能同步了,这些文件也能被保存下来了。

完美的想法!

挂载NFS服务

在 master 节点上安装 nfs 工具并启动,设置访问权限等。这一步就不细说了,自己上百度去 google 一下,满大街都是,没有难度。

然后在该 Job 的 jenkins file 中加上下面这句:

  1. podTemplate(......

  2. volumes:[

  3. nfsVolume(mountPath:slave节点的workspace,serverAddress:master节点的IP,serverPath:master节点的workspace,readOnly:false)

  4. ]

  5. ......

  6. ){......}

完事! 大功告成,验证一下!

访问 pipeline job 的 Workspace

访问 pipeline 类 job 的 Workspace,需要进入到 job 的某一次 build 页面(如上图中1处所示),然后点击左侧菜单的 Pipeline Steps(上图中2处所示)。

继续点击右边的 Allocate node: Start(如上图中3处所示),即可看到 Workspace 的入口:

点击进入:

什么情况?怎么出错了?

分析一下出错的原因

细看一下出错的 Stack trace:

哦,报了一个文件找不到的错误。登录到 Jenkins master 节点的后台去看一下,确认该 job 的 Workspace 及其内容已经全部同步到 master 上了!那应该是程序里面读取这个目录的参数有问题吧?

看到报错的源文件是org.jenkinsci.plugins.workflow.support.actions.WorkspaceActionImpl.java,这是一个插件的源码,通过 Github 上查询得知,属于 workflow-support 插件,那没办法了,只能把插件的源码下载下来看一下了!

看源码

根据上面的提示查看源码,发现报错的地方如下图所示:

所在文件:

org.jenkinsci.plugins.workflow.support.actions.WorkspaceActionImpl.java

看这个意思是 getworkspace() 这个方法返回 null 值了。再跟进 getworkspace() 方法去看看(by the way,这个方法是在 workflow-api 插件的源码中实现的,再下载 workflow-api 插件的源码):

所在文件:

org.jenkinsci.plugins.workflow.actions.WorkspaceAction.java

getworkspace() 中主要是 getNode() 和 getPath() 两个方法,但是这两方法在 workflow-api 插件中定义为抽象方法,再跟一下代码,发现这两个方法的实现还是在 workflow-support 插件中实现的:

所在文件:

org.jenkinsci.plugins.workflow.support.actions.WorkspaceActionImpl.java

OK!这下明白了!

原来在页面上访问 job 的 Workspace 时,是根据这个 job 所在的 node 加上 node 上的 path 来定位的。前面我们虽然将 slave 的 Workspace 挂载到 master 的 Workspace 下,但是程序访问的时候还是去 slave 节点上找,可此时 slave 节点已经被 kubernetes 销毁了,所以程序报错说找不到了!

改代码

子曰:如果没有其他的需求,我们就一切从简,实现这个访问 Workspace 的功能就行。

既然我们已经通过 nfs 把 job 的 Workspace 同步到 master 节点的 Workspace 下了,那我们强行让 node 和 path 返回 master 节点的 node 和 path 即可。

这里如果你再跟一下代码的话,会发现此时你不知道 master 节点的 node 应该返回什么。没办法,继续跟代码吧,这是一个痛苦的过程,最终,我们在 Jenkins-core 源码中发现,master 节点的 node (节点名)为""(空字符串对象,不是null)。

最终,我们通过一些条件判断之后,将 getNode() 和 getPath() 两个方法改一下即可:

所在文件:

org.jenkinsci.plugins.workflow.support.actions.WorkspaceActionImpl.java

尾声

至此,我们就完成了基于 kubernetes 编译的 job 的 Workspace 访问的改造。再次从页面上访问一下 Workspace:

全部内容可见也可下载了,完美!

------------------END------------------

下面的内容同样精彩

点击图片即可阅读

京东技术

---关注技术的公众号

长按识别二维码关注

我们都知道持续集成和持续交付是 DevOps 的组成部分,因为它们用于集成方法的多个阶段。市面上的CI/CD工具有很多,但是你知道Jenkins这个基于Java的开源CI/CD工具是最受欢迎的吗?用于测试自动化的 Jenkins 是开发人员的热门选择,因为它能够轻松地与各种测试工具集成。它一直是 DevOps 专业人士和初学者的首选。

Jenkins初学者教程:包含示例和最佳实践的综合指南

关注留言点赞,带你了解最流行的软件开发知识与最新科技行业趋势。