Kubernetes 和 Docker 工作流的 Jenkins 设置

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

介绍

暑假期间,我有机会在 Kubernetes 中与 Jenkins 玩了一会儿。更具体地说,我想看看运行 Docker Workflow 插件的 最佳方式是什么。

因此,我们的想法是让 Pod 运行 Jenkins 并使用它来运行使用 Docker Workflow Plugin 定义的构建。经过大量阅读和更多实验后,我发现有很多方法可以做到这一点,每种方法各有优缺点。

这篇文章介绍了所有可用的选项。进一步来说:

  1. 构建直接在 Master 上运行
  2. 使用 Docker 插件 启动 Slaves
  3. 在 Docker 中 使用 Docker 插件 和 Docker
  4. 使用 Swarm 客户端
  5. Docker 中的 Docker

在我完成所有可能的设置之前,我认为描述所有这些插件可能会有所帮助。

码头插件

一个使用 Docker 来创建和使用从站的 Jenkins 插件。它使用 http 来与 Docker 通信并创建新容器。这些容器只需要准备好 java 并运行 SSHD ,这样主人就可以通过 ssh 进入它们并发挥它的魔力。互联网上有很多关于从属容器的图像,在我重新连接时最受欢迎的是 evarga jenkins slave

该插件可用但感觉有点不稳定,因为它创建了 Docker 容器,但有时无法连接到从站并重试 (通常需要 2 到 3 次尝试) 。尝试过许多不同的从图像和许多具有相似经验的不同身份验证方法 (密码、密钥身份验证等)

一群

有一个插件来创建奴隶是一种方法。另一个是“带上你自己的奴隶”,这几乎就是 swarm 的全部内容。这个想法是 Jenkins master 正在运行 Swarm 插件,用户负责启动 swarm 客户端(它只是一个 java 进程)。


 java -jar /path/to/swarm-client.jar http://jenkins.master:8080


客户端连接到主服务器,让它知道它已启动并正在运行。然后 master 就可以在客户端上开始构建了。

Docker 工作流插件

此插件允许您在工作流脚本中使用 Docker 图像和容器,或者换句话说,在 Docker 容器内执行工作流步骤并从工作流脚本创建 Docker

为什么?

将构建的所有需求封装在一个 Docker 镜像中,而不用担心如何安装和配置它们。

下面是一个示例 Docker Workflow 脚本的样子:


 java -jar /path/to/swarm-client.jar http://jenkins.master:8080


注意 :您不需要使用 Docker 插件 来使用 Docker 工作流插件

另外 Docker 工作流插件 正在使用 Docker 二进制文件。这意味着您需要在任何您打算使用 Docker Workflow 插件的 地方安装 docker 客户端。

差点忘了 :构建的“ 执行者 ”和参与工作流的容器,需要共享项目工作空间。我现在不会详细介绍。请记住,它通常需要访问 docker 主机上的特定路径 (或一些共享文件系统) 。未能满足此要求会导致“难以检测”问题,例如构建永远挂起等。

现在我们准备看看可能的设置是什么。

没有奴隶

这是最简单的方法。它不涉及 Jenkins 从站,构建通过配置固定的执行程序池直接在主站上运行。

由于没有从站,运行 Jenkins 本身的容器需要安装和配置 Docker 二进制文件以指向实际的 Docker 主机。

如何使用 Kubernetes 内部的 docker 主机?

有两种方法:

  1. 使用 Kubernetes API
  2. 通过挂载 /var/run/docker.sock

您可以使用如下所示的简单 shell 脚本执行 (1)。


 java -jar /path/to/swarm-client.jar http://jenkins.master:8080


您可以 (2) 通过在 Jenkins POD 上指定 hostDir 卷挂载。


 java -jar /path/to/swarm-client.jar http://jenkins.master:8080


可以 在此处 找到此类设置的实际示例。

优点


  1. 最简单的方法
  2. 最少的插件数量

缺点

  1. 不缩放
  2. 直接访问 Docker 守护进程
  3. 需要访问主机上的特定路径(请参阅 Docker Workflow Plugin 上的说明)

Docker 插件管理的从站

由于显而易见的原因,先前的方法无法扩展。由于 Docker Kubernetes 已经就位,将它们用作资源池听起来是个好主意。

所以我们可以添加 Docker 插件 并让它为我们要运行的每个构建创建一个从属容器。这意味着我们需要一个 Docker 容器,它可以访问 Docker 二进制文件 (docker 工作流要求) ,并且还将从 master 挂载项目的工作区。

如上所述,master 需要通过 ssh 连接到 slave。为了成功,需要配置凭据或正确的 ssh 密钥。在这两种情况下,docker 插件的 xml 配置都需要更新,以便引用 Jenkins 凭据配置的 id (例如,请参阅此 config.xml

那么这个id到底是什么?

Jenkins 使用 凭证插件 来存储和检索凭证。每组凭据都有一个唯一的 ID,其他插件可以使用此 ID 来引用一组凭据。出于安全原因,密码、口令等不以纯文本形式存储,而是使用 SHA256 加密。他们用于加密的密钥也被加密,这样事情就更安全了。您可以在这篇有关“ Jenkins 中的凭证存储 ”的精彩文章中找到有关该主题的更多详细信息。

我想让您注意的是,由于凭据存储在 Jenkins 中的方式,创建一个无需人工交互即可相互交谈的主映像和从映像并非易事。可以尝试使用如下脚本:


 java -jar /path/to/swarm-client.jar http://jenkins.master:8080


生成秘密和主密钥。要使用它们来加密密码,您可以使用如下脚本:



 java -jar /path/to/swarm-client.jar http://jenkins.master:8080


实际加密密码。我不会向任何人推荐这个,我只是展示脚本来强调这是多么复杂。当然,这样的脚本也使用了 Credentials Plugin 内部的细节,而且感觉有点老套。通过将以下 groovy 脚本放入 Jenkins init.groovy.d 中,我发现了一种稍微更优雅的配置凭据的方法:


 java -jar /path/to/swarm-client.jar http://jenkins.master:8080


上面的代码片段演示了如何使用空密码创建用户名/密码凭证和 SSH 私钥。


优点


  1. 足够简单

缺点

  1. Docker 插件 目前还没有吗?
  2. 直接访问 Docker 守护进程
  3. 需要访问主机上的特定路径(请参阅 Docker Workflow Plugin 上的说明)

即使我们将 Docker 插件 的问题放在一边,我仍然希望采用一种不会直接与运行在 Kubernetes 后面的 Docker 守护进程对话的方法。

使用 DIND 的 Docker 插件管理从站

为什么要在 Docker 中使用 Docker

在我们的例子中,为了避免落后于 Kubernetes

这里的可能性越来越多。可以直接在 Kubernetes master 上使用 DIND,也可以将它与 Docker Plugin 结合使用,这样每个 slave 都运行自己的守护进程并 100% 隔离。

无论哪种方式,构建期间发生的事情都与世界其他地方完全隔离。另一方面,它确实需要使用 特权 模式。这可能是一个问题,因为该模式在某些环境中可能不可用 (即我上次检查时它在 Google Container Engine 上不可用)。

注意:通过在 slave 中托管 docker 守护进程,我们无需在外部 docker 上使用卷挂载(请记住,只有执行程序和工作流步骤需要共享工作空间)。

优点


  1. 100% 隔离
  2. 不需要访问外部 docker 上的特定路径!

缺点

  1. 复杂
  2. 需要特权模式
  3. Docker 图像未“缓存”

使用 Swarm 客户端

DIND 与否,仍然需要提出一种扩展解决方案,而 Docker Plugin 到目前为止似乎并不是一个理想的解决方案。同样, Kubernetes Docker 插件 Kubernetes 插件 )的等效项似乎确实需要更多关注。所以我们只剩下 Swarm 了。

使用 Swarm 似乎很合适,因为我们使用的是 Kubernetes 并且启动 N 个运行 Swarm 客户端的容器非常简单。我们可以使用具有适当图像的复制控制器。

优点


  1. 快速地
  2. 可扩展
  3. 强壮的

缺点

  1. 从站需要在外部进行管理。
  2. 需要访问主机上的特定路径(请参阅 Docker Workflow Plugin 上的说明)

将 Swarm 客户端与 DIND 结合使用

在这个用例中,DIND 的主要问题是“在 Docker 中”中的图像没有被缓存。人们可以尝试共享 Docker Registry ,但我不确定这是否可行。

另一方面,对于大多数剩余选项,我们需要使用 hostPath 挂载,这在某些环境中可能不起作用。

解决上述两个问题的解决方案是将 Swarm 与 DIND 结合起来

使用 Swarm, 客户会留下来 (而不是在每次构建后被清除)。 这解决了图像缓存问题。

此外,使用 DIND,我们不再需要通过 Kubernetes 使用 hostPath 挂载。

所以我们有一个双赢。

优点


  1. 快速地
  2. 可扩展
  3. 强壮的
  4. 100% 隔离
  5. 图像被缓存

缺点

  1. 从站需要在外部进行管理

结束语

作为我正在做的一个 poc 的一部分,我厌倦了上述所有设置:“ Jenkins for Docker Workflow on Kubernetes ”,我认为我应该分享。还有一些我想尝试的事情:

  • 使用 秘密 对奴隶进行身份验证。
  • 消除混乱
  • ETC

欢迎在评论中补充经验、建议、指正。

希望你觉得它有用。