介绍
在夏天的时候,我有机会在Kubernetes内部与詹金斯 一起玩 。 更具体地说,我想看看让Docker Workflow插件运行的最佳方法是什么。
因此,想法是让Pod运行Jenkins并使用它运行使用Docker Workflow Plugin定义的构建。 经过大量的阅读和更多的实验后,我发现这样做的方法很多,各有千秋,各有千秋。
这篇文章介绍了所有可用选项。 进一步来说:
在进行所有可能的设置之前,我认为描述所有这些插件可能会有所帮助。
一个使用Docker来创建和使用从属的Jenkins插件。 它使用http以便与Docker通信并创建新容器。 这些容器只需要准备好Java并运行SSHD ,以便主服务器可以将它们放入ssh并发挥其魔力。 互联网上有许多用于奴隶容器的图像,在我重新连接时,最受欢迎的是evarga jenkins奴隶 。
该插件是可用的,但由于它创建了Docker容器,因此感觉有点不整洁,但有时无法连接到从属服务器并重试(通常需要2到3次尝试) 。 尝试了许多不同的从属映像以及具有相似体验的许多不同的身份验证方法(密码,密钥身份验证等) 。
有一个插件来创建从属是一种方法。 另一个是“带上自己的奴隶”,这几乎就是一群人的全部。 这个想法是, Jenkins主服务器正在运行Swarm插件,而用户负责启动swarm客户端(它只是一个Java进程)。
java -jar /path/to/swarm-client.jar http://jenkins.master:8080
客户端连接到主服务器,让它知道它已启动并正在运行。 然后,主服务器就可以在客户端上开始构建。
该插件允许您在工作流脚本中使用Docker映像和容器,换句话说,在Docker容器中执行工作流步骤并从工作流脚本创建Docker 。
为什么?
要将构建的所有需求封装在Docker映像中,而不必担心如何安装和配置它们。
以下是示例Docker Workflow脚本的样子:
- node('docker') {
- docker.image('maven').inside {
- git 'https://github.com/fabric8io/example-camel-cdi'
- sh 'mvn clean install'
- }
- }
另外 : Docker Workflow插件正在使用Docker二进制文件。 这意味着您打算在打算使用Docker Workflow Plugin的任何位置安装Docker客户端。
几乎忘记了 :构建的“ 执行者 ”和参与工作流的容器需要共享项目工作区。 我现在不详细介绍。 请记住,它通常需要访问docker主机(或某些缺少共享文件系统)上的特定路径。 未能满足此要求会导致“难以发现”的问题,例如建筑物永久悬挂等。
现在我们准备看一下可能的设置。
没有奴隶
这是最简单的方法。 它不涉及Jenkins从属服务器,而是通过配置固定的执行程序池直接在主服务器上运行。
由于没有从属服务器,因此运行Jenkins本身的容器将需要安装并配置Docker二进制文件以指向实际的Docker主机。
如何在Kubernetes内部使用Docker主机?
有两种方法:
- 使用Kubernetes API
- 通过挂载/var/run/docker.sock
您可以使用以下简单的shell脚本来完成(1)。
- #!/bin/bash
- KUBERNETES=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT
- TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`
- POD=`hostname`
- curl -s -k -H "Authorization: Bearer $TOKEN" $KUBERNETES/api/v1/namespaces/$KUBERNETES_NAMESPACE/pods/$POD | grep -i hostIp | cut -d "\"" -f 4
您可以(2)通过在Jenkins POD上指定hostDir卷安装。
- {
- "volumeMounts": [
- {
- "name": "docker-socket",
- "mountPath": "/var/run/docker.sock",
- "readOnly": false
- }
- ],
-
-
- "volumes": [
- {
- "name": "docker-socket",
- "hostPath": {
- "path": "/var/run/docker.sock"
- }
- }
- ]
- }
这种设置的实际示例可以在这里找到。
优点
- 最简单的方法
- 插件数量最少
缺点
- 不缩放
- 直接访问Docker守护程序
- 需要访问主机上的特定路径(请参阅Docker Workflow Plugin上的注释)
Docker插件管理的从站
由于明显的原因,以前的方法无法扩展。 由于Docker和Kubernetes已经存在,因此将它们用作资源池听起来是个好主意。
因此,我们可以添加Docker Plugin并为我们要运行的每个构建创建一个从属容器。 这意味着我们需要一个Docker容器,该容器可以访问Docker二进制文件(docker工作流要求),并且还需要从主容器安装项目的工作空间。
如上所述,主机将需要通过ssh连接到从机。 为使此操作成功,需要配置凭据或正确的ssh密钥。 在这两种情况下,都需要更新docker插件的xml配置,以引用Jenkins凭据配置的ID (例如,请参阅此config.xml ) 。
那么,这个ID到底是什么?
Jenkins正在使用凭据插件来存储和检索凭据。 每组凭据都有一个唯一的ID,其他插件可以使用此ID来引用一组凭据。 出于安全原因,密码,密码等不以纯文本形式存储,而是使用SHA256加密。 它们用于加密的密钥也被加密,从而使事情更加安全。 您可以在“ Jenkins中的凭据存储 ”这一出色的帖子中找到有关此主题的更多详细信息。
我想让您注意的是,由于凭据存储在Jenkins中的方式,创建主控和从属映像之间无需人工交互就可以互通有无。 可以尝试使用如下脚本:
- #Generate master.key and secret
- MAGIC="::::MAGIC::::"
- mkdir -p /var/jenkins_home/secrets
- openssl rand -hex 128 > /var/jenkins_home/secrets/master.key
- openssl dgst -sha256 -binary /var/jenkins_home/secrets/master.key > /tmp/master.hashed
- HEX_MASTER_KEY=`head -c 16 /tmp/master.hashed | xxd -l 16 -p`
- openssl rand 259 > /tmp/base
- echo $MAGIC >> /tmp/base
- openssl enc -aes-128-ecb -in /tmp/base -K $HEX_MASTER_KEY -out /var/jenkins_home/secrets/hudson.util.Secret
生成密钥和主密钥。 并使用它们来加密密码,您可以使用如下脚本:
- #!/bin/bash
- IN=`echo $1 | base64`
- SUFFIX="::::MAGIC::::"
- MASTER_KEY=`cat /var/jenkins_home/secrets/master.key`
- HASHED_MASTER_KEY=`echo -n $MASTER_KEY | sha256sum | cut -d " " -f 1`
- HASHED_MASTER_KEY_16=${HASHED_MASTER_KEY:0:16}
- openssl enc -d -aes-128-ecb -in /var/jenkins_home/secrets/hudson.util.Secret -K $HASHED_MASTER_KEY -out /tmp/hudson.key
- HUDSON_KEY=`cat /tmp/hudson.key`
- HUDSON_KEY_TRIMMED=${HUDSON_KEY:0:-16}
- HUDSON_KEY_16=${HUDSON_KEY_TRIMMED:0:16}
- echo $HUDSON_KEY_16 > /tmp/hudson16.key
- echo "$IN$SUFFIX" > /tmp/jenkins.password
- openssl enc -aes-128-ecb -in /tmp/hudson16.key -out /tmp/jenkins.password.enc -K $IN
实际加密密码。 我不会向任何人推荐它,我只是显示脚本来强调它的复杂性。 当然,诸如此类的脚本也利用了Credentials插件内部的细节,并且感觉有些怪异。 通过在Jenkins init.groovy.d中抛出以下groovy脚本,我发现了一种稍微更优雅的方法来配置凭据:
- import jenkins.model.*
- import com.cloudbees.plugins.credentials.*
- import com.cloudbees.plugins.credentials.common.*
- import com.cloudbees.plugins.credentials.domains.*
- import com.cloudbees.plugins.credentials.impl.*
- import com.cloudbees.jenkins.plugins.sshcredentials.impl.*
- import hudson.plugins.sshslaves.*;
-
- domain = Domain.global()
- store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
-
- priveteKey = new BasicSSHUserPrivateKey(
- CredentialsScope.GLOBAL,
- "jenkins-slave-key",
- "root",
- new BasicSSHUserPrivateKey.UsersPrivateKeySource(),
- "",
- ""
- )
-
- usernameAndPassword = new UsernamePasswordCredentialsImpl(
- CredentialsScope.GLOBAL,
- "jenkins-slave-password", "Jenkis Slave with Password Configuration",
- "root",
- "jenkins"
- )
-
- store.addCredentials(domain, priveteKey)
- store.addCredentials(domain, usernameAndPassword)
上面的代码段演示了如何使用空密码创建用户名/密码凭证以及SSH私钥。
优点
- 很简单
缺点
- Docker插件目前还没有?
- 直接访问Docker守护程序
- 需要访问主机上的特定路径(请参阅Docker Workflow Plugin上的注释)
即使我们忽略了Docker插件的问题,我仍然希望采用一种不会直接与Kubernetes背后运行的Docker守护进程进行通讯的方法 。
带有DIND的Docker插件管理的从站
在我们的案例中,为了避免落后Kubernetes 。
这里的可能性越来越多。 一个人可以直接在Kubernetes主服务器上使用DIND,也可以将它与Docker插件结合使用,以便每个从服务器运行自己的守护程序并100%隔离。
无论哪种方式,构建过程中发生的一切都与世界其他地方完全隔离。 另一方面,它确实需要使用特权模式。 这可能是一个问题,因为该模式在某些环境中可能不可用(即,上次我在Google Container Engine上不可用)。
注意:通过在从属服务器中托管docker守护程序,使我们摆脱了在外部docker上使用卷安装的要求(请记住,只有执行者和工作流步骤需要共享工作空间)。
优点
- 100%隔离
- 不需要访问外部docker上的特定路径!
缺点
- 复杂
- 需要特权模式
- Docker映像未“缓存”
使用Swarm客户端
DIND是否仍然需要提出一种扩展规模的解决方案,到目前为止, Docker Plugin似乎并不是理想的解决方案。 同样,相当于Kubernetes的Docker插件 ( Kubernetes插件 )似乎确实需要更多注意。 因此,我们只剩下Swarm了 。
使用Swarm似乎很合适,因为我们使用Kubernetes及其启动N个运行Swarm客户端的容器非常简单。 我们可以使用带有适当映像的复制控制器。
优点
- 快速
- 可缩放
- 强大的
缺点
- 从站需要从外部进行管理。
- 需要访问主机上的特定路径(请参阅Docker Workflow Plugin上的注释)
将Swarm客户端与DIND一起使用
在此用例中,DIND的主要问题在于,“ in Docker ”中的映像未缓存。 一个人可以尝试共享Docker Registry,但是我不确定这是否可能。
另一方面,对于大多数其余选项,我们需要使用hostPath挂载,在某些环境中可能无法使用。
解决上述两个问题的解决方案是将Swarm与DIND结合使用
使用Swarm时 ,客户端会停留(而不是在每次构建后被擦除)。 这解决了图像缓存问题。
此外,借助DIND,我们不再需要通过Kubernetes使用hostPath挂载。
所以我们有一个胜利-胜利。
优点
- 快速
- 可缩放
- 强大的
- 100%隔离
- 图像被缓存
缺点
- 从站需要从外部进行管理。
总结思想
在执行poc的过程中,我厌倦了上述所有设置:“ Kubernetes上的Jenkins for Docker Workflow ”,我认为我应该分享。 还有一些我想尝试的事情:
- 使用机密对从站进行身份验证。
- 消除混乱
- 等等
随时在评论中添加经验,建议和更正。
希望你觉得它有用。
翻译自: https://www.javacodegeeks.com/2015/09/jenkins-setups-for-kubernetes-and-docker-workflow.html