介绍
暑假期间,我有机会在 Kubernetes 中与 Jenkins 玩了一会儿。更具体地说,我想看看运行 Docker Workflow 插件的 最佳方式是什么。
因此,我们的想法是让 Pod 运行 Jenkins 并使用它来运行使用 Docker Workflow Plugin 定义的构建。经过大量阅读和更多实验后,我发现有很多方法可以做到这一点,每种方法各有优缺点。
这篇文章介绍了所有可用的选项。进一步来说:
- 构建直接在 Master 上运行
- 使用 Docker 插件 启动 Slaves
- 在 Docker 中 使用 Docker 插件 和 Docker
- 使用 Swarm 客户端
- 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 主机?
有两种方法:
- 使用 Kubernetes API
- 通过挂载 /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
可以 在此处 找到此类设置的实际示例。
优点
- 最简单的方法
- 最少的插件数量
缺点
- 不缩放
- 直接访问 Docker 守护进程
- 需要访问主机上的特定路径(请参阅 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 私钥。
优点
- 足够简单
缺点
- Docker 插件 目前还没有吗?
- 直接访问 Docker 守护进程
- 需要访问主机上的特定路径(请参阅 Docker Workflow Plugin 上的说明)
即使我们将 Docker 插件 的问题放在一边,我仍然希望采用一种不会直接与运行在 Kubernetes 后面的 Docker 守护进程对话的方法。
使用 DIND 的 Docker 插件管理从站
在我们的例子中,为了避免落后于 Kubernetes 。
这里的可能性越来越多。可以直接在 Kubernetes master 上使用 DIND,也可以将它与 Docker Plugin 结合使用,这样每个 slave 都运行自己的守护进程并 100% 隔离。
无论哪种方式,构建期间发生的事情都与世界其他地方完全隔离。另一方面,它确实需要使用 特权 模式。这可能是一个问题,因为该模式在某些环境中可能不可用 (即我上次检查时它在 Google Container Engine 上不可用)。
注意:通过在 slave 中托管 docker 守护进程,我们无需在外部 docker 上使用卷挂载(请记住,只有执行程序和工作流步骤需要共享工作空间)。
优点
- 100% 隔离
- 不需要访问外部 docker 上的特定路径!
缺点
- 复杂
- 需要特权模式
- Docker 图像未“缓存”
使用 Swarm 客户端
DIND 与否,仍然需要提出一种扩展解决方案,而 Docker Plugin 到目前为止似乎并不是一个理想的解决方案。同样, Kubernetes 的 Docker 插件 ( Kubernetes 插件 )的等效项似乎确实需要更多关注。所以我们只剩下 Swarm 了。
使用 Swarm 似乎很合适,因为我们使用的是 Kubernetes 并且启动 N 个运行 Swarm 客户端的容器非常简单。我们可以使用具有适当图像的复制控制器。
优点
- 快速地
- 可扩展
- 强壮的
缺点
- 从站需要在外部进行管理。
- 需要访问主机上的特定路径(请参阅 Docker Workflow Plugin 上的说明)
将 Swarm 客户端与 DIND 结合使用
在这个用例中,DIND 的主要问题是“在 Docker 中”中的图像没有被缓存。人们可以尝试共享 Docker Registry ,但我不确定这是否可行。
另一方面,对于大多数剩余选项,我们需要使用 hostPath 挂载,这在某些环境中可能不起作用。
解决上述两个问题的解决方案是将 Swarm 与 DIND 结合起来
使用 Swarm, 客户会留下来 (而不是在每次构建后被清除)。 这解决了图像缓存问题。
此外,使用 DIND,我们不再需要通过 Kubernetes 使用 hostPath 挂载。
所以我们有一个双赢。
优点
- 快速地
- 可扩展
- 强壮的
- 100% 隔离
- 图像被缓存
缺点
- 从站需要在外部进行管理
结束语
作为我正在做的一个 poc 的一部分,我厌倦了上述所有设置:“ Jenkins for Docker Workflow on Kubernetes ”,我认为我应该分享。还有一些我想尝试的事情:
- 使用 秘密 对奴隶进行身份验证。
- 消除混乱
- ETC
欢迎在评论中补充经验、建议、指正。
希望你觉得它有用。