原文:BUILDING WITH JENKINS INSIDE AN EPHEMERAL DOCKER CONTAINER
作者:Maxfield Stewart 译者:杰微刊兼职翻译刘晓鹏
《容器的深入思考》一文告诉大家如何在容器中构建一个项目。今天,我将向大家展示我的团队当前是如何综合运用Jenkins和Docker来为Riot引擎团队提供服务的。在最近的博文中,我承诺不就将会直接讨论实际的salve构建和Jenkins配置。但是,从某种意义上讲,这是一件主要的事件:如果你没有一台接收salve的Jenkins服务器,最好的办法是回过去看看我以前的博客。
不过,在正确的开始本教程之前,我们先讨论一下方式和方法。通过Docker,有很多种方式来创建 slaves。即使缩小场景,只使用 Jenkins,还是有多种选择。通过研究与发现,我觉得有两种主要的方式你可以采用。从概念上讲,我将这两种模式称之为“Docker execution”和“Docker ephemeral slave”。
这两种方式的本质区别是Jenkins如何与构建的slave进行连接和通信。在执行模式下,Jenkins使用一种传统的流行方式连接:在虚拟机或者物理设备上运行一个客户端,这里指的就是一台运行的Docker主机。在临时模式中,Jenkins直接连接Docker容器,将其视为一个构建的slave。这两者之间的区别很重要,所以我们花一点时间来分解这两种模式。
DOCKER 执行模式
在执行模式下,我们在结构上假定slave是一台Docker主机,但是把它当做一台物理机来处理。当一个Jenkins任务启动时,它直接在slave上同步/创建一个工作目录,并通过“docker run”和“docker exec”命令来转换容器,然后将其挂载到本地的工作空间中。容器是一个虚拟暂存空间,是一个隔离的环境。它可以包含所有的自定义版本的工具和二进制文件(我们需要对装载到容器的源代码进行编译)。
当一个构建任务完成时,所有二进制文件和生成的构建归档文件将会发送到传统Jenkins工作空间中的slave上。然后,Jenkins可以安全的关闭容器,正常的执行后续的清理工作。
该模式的最佳代表是Cloudbees定制构建环境插件(Cloudbees Custom Build Environment Plugin),该插件是一个开源插件,由 Jenkins 源码库的主人维护。
DOCKER 临时 Slave 模式
临时模式的目的在于利用Docker容器的自主性和隔离性来扩展 Jenkins 的构建范围,以满足在Jenkins上的任何需求。相对于传统的预先分配slave数组或现成的虚拟机,这种模式将容器自身看做是一个slave。
当Jenkins的执行器上有一个需求时,我们需要转换容器,自动地配置Jenkins以便将该容器视为一个新的slave来接收,然后执行任务,最后关闭容器,回收slave。当然这种模式比执行模式更复杂。
这种方式有几个相互竞争的插件,这些插件通常都是以如何维护和构建Docker云为中心。迄今为止,这种插件有Kubernetes,Mesos以及“纯”Docker方式。
如何选择模式?
两种模式都能有效的解决问题。在Riot,我们感兴趣的是为特定的目标获取分配盒子和“执行器”的方式,所以临时模型对我们有很强的吸引力。我们喜欢用一个容器来代表整个slave的想法。因此,我们使用Docker Plugin 来完成我们的目标。
随着时间的推移,我们很高兴当初的选择。Docker Plugin的主开发者(KostyaSha)对该插件的维护非常活跃,经常更新,并且有很强大的社区。他负责响应问题,并在GitHub repo 提供了清晰的路线图。没有他的工作,我不可能完成这篇文章中提供的教程,该教程是基于 0.16 版本插件的。
此外请注意,KostyaSha最近将“Docker Plugin”分出来一个新的仓库“Yet Another Docker Plugin”进行继续开发。由于我们现在的生产环境正在使用的插件是“Docker Plugin”,所以在本文中选择该插件进行分析。
在以后,我们可能会改变我们的想法。我们尽量保证灵活性,以便在有更好的解决方案时能够方便的进行转换。我们采取的方式也受到过教训-在本教程最后我会对它们进行描述。
教程
这是我写的最长的教程。所以我决定在这只保存链接以节省空间(将实现与方案进行分离)。如果你已经清楚了之前的文章,该教材只需要花费30-45分钟左右的时间就可完成。你可以从这获取到完整的教程:
Containerized Jenkins Farm教程
另外,如果你想跳过结构部分,尽快开始并运行起来,你可以从这获取到完整的教程,然后按照 README 中的说明进行操作:
https://github.com/maxfields2000/dockerjenkins_tutorial/tree/master/tutorial_07
经验教训
运营这个平台有着诸多其自身独特的挑战。请记住这个简短的列表,希望能帮助你节省时间和精力:
运营一个大规模的 DOCKERHOSTS 并不是一个简单的任务。
磁盘空间是一个大问题。Docker镜像很消耗空间。每个运行的容器也要耗费空间。有时候,容器挂了也还会占用空间。有的团队使用卷来创建slave,这需要耗费更多的空间。
在Docker主机上监控磁盘空间是必不可少的,不要等到磁盘消耗完的时候再去处理,要及时的监控并处理。
清理镜像和容器,就像垃圾回收一样。
每次一个新的镜像推送到Docker主机,都会留下“悬浮”的未使用层,清理这些空间应该是日常的操作,否则磁盘空间就会成为问题。
容器的slave有时无法停止或无法清理,关注“退出”和“死亡”的容器是保证Docker主机清洁必不可少的一部分。
增加新的镜像/SLAVE 到 DOCKERHOSTS 队列是一个很耗时的操作。
最初,要求工程师必须将他们的镜像在 Jenkins 中进行配置。很快我们发现这个过程是一个不必要的障碍。根据我们的经验,在早期的开发中,工程团队平均每周需要对他们的Dockerfile做多次修改。
我们创建一个称之为“Harbormaster”的工具,该工具通过 Groovy 的API,能够自动的验证工程师提供的镜像,并自动的配置 Jenkins。Harbormaster 通过一组核心的标准来测试每个镜像,并验证salve是否正常工作。然后生成一份测试报告并自动配置Jenkins。
关于 Harbormaster 如何工作的讨论可能会导致本文过长。我将在以后的博客对其进行阐述。
风险监控室是必不可少的
关于如何监控 Jenkins 和Docker Swarm,我们也还在不断的成长中。Docker Cloud 的监控艺术是发展过程中的永恒主题,并且当这个云是一个构建场景而不是应用场景时,还会呈现出一种独特的扭曲状态。
正如Harbormaster,在这讨论监控也会使得本文太长。同样,我会在以后的博客中更多的讨论生产环境下的监控问题。
JENKINS的审计可能会咬到你
曾经,由于 Jenkins 的崩溃导致磁盘消耗完的问题,导致我们工作到半夜。结果是因为“创建/销毁”构建的slave时,产生了 100,000 个微小的日志文件。Jenkins保存了所有的创建和销毁slave时的审计文件;一定要注意,否则你会死的很难看。
当然还有更多的经验教训。在以后的博客中我还继续会讨论我们是如何处理某些问题的,所以有问题就赶紧问吧,不要犹豫!
你的生产环境系统和我们的研究结果
随着本教程的结束,你应该已经有了一个完整功能Docker Jenkins 沙盒。在创建过程中你会遇到一些困难,在生产环境中你也需要做几件事情。
1.使用Docker Plugin 配置你生产环境的 Jenkins 主服务器,正如你在上述教程中做的一样(安装插件)。
2.启动一个“生产环境”的Docker主机。这可能有点超出了本教程的范围。我们的流水线团队使用 Centos 虚拟机来运行 VSphere,不过你也可以使用 AWS 的实例或物理机,任何你想要的有效的Docker主机都行。这就是Docker的强大之处。
3.如果在构建环境的Docker主机中,没有使用 TLS 安全机制(在安全环境中并不少见),确保在设置中移除“https”和“Docker cert path”。
4.如果你正在使用 TLS,确保在 Jenkins 中配置生产环境的证书。
5.确保你构建的slave镜像是生产环境下的Dockerhost所能到达的。在 Riot,我们使用一个中央镜像仓库。
很多东西都涉及到安装,所以,请不犹豫,有什么问题就问,并提供必要的点。
对于我们来说,这不是一个“沙盒”或“玩耍”的设置。这个教程中,列出的只是我们在线环境中改变的一个组件。我们生产环境的Dockerhost实际上是一个Docker Swarm 应用,由 10 台Dockerhost机器支撑。下面这些图标展示我们现在(发布本文的时候)是如何设置这些东西的
抽象结构
物理结构
这是来自我们生产系统中的某些统计数据
Jenkins 统计数据:
Jenkins 统计数据细节
平均队列大小:20-30
预备执行器:~650
平均使用的执行器:30-40
构建节点的总数量:~80
每小时的平均任务数:~600
DockerJenkins 统计数据
DockerJenkins 统计数据细节
平均队列大小:3
预备执行器:20(为构建流程控制)
平均使用的执行器:3
任意时间的平均节点数:5
每小时的平均任务数:50
去年初年初,我们将系统部署在Docker很早的版本上(Docker 1.2),Docker Plugin 也是的版本(.8),稳定性是当初关注一个核心问题。不过现在的版本(Docker 1.10 + Docker Plugin 0.16),我非常相信,就我们的需求而言,它是足够稳定的。在这一年中,我们一直在使用它们,我们从少量的构建任务和几个早期的使用团队发展到现在,无论是任务数还是团队数都有了巨大的增加。很明显,一旦我们有机会进行完整的测试,我们就会迁移到新的插件“Yet Another Docker Plugin”上。
事实上,我们的Dockerized Jenkins平台现在构建的任务,大概只占我们整个 Jenkins 平台所支撑的全部任务(超过4000)的25%。网络新构建任务创建在传统Jenkins环境中的几乎为0,大部分新创建的任务都在我们的Docker平台上。原因如下:
1、引擎团队通过自定义Dockerfiles可以完全控制他们的构建环境。
2、通过Docker,可以将他们部署的构建环境复制到本地,这样那些“构建环境”就可以很容易在本地进行测试。
3、团队不在需要“系统管理员”来构建虚拟机或其他环境,这些权限“放手”到了每个人手里。
结论
2015年8月,当我开始这一系列博客的写作之旅时,我们已经有了一个功能性的原型。八个月以后,博客几乎赶上了我们当前的进度,缺乏监控和扩展。
在这个点上,你应该对Docker基础有一个很坚实的入门,并且知道一些关于Docker的扩展和安全问题,这些都通过Jekins的真实应用场景演示过。另一方面,你应该有一个功能性配置文件,用于配置一个完整的Jekins测试环境,并通过它来运行你本地的Docker Toolbox Dockerhost,还包括建立自己的构建slave的能力。这几乎就是“盒子容器中的Jenkins”,在以后的博客中,我将会更深入的挖掘这个生态系统,分析我们创建的工具、API以及监控。
我真心希望你能觉得这些东西是有用的。我们收到的反馈也非常棒,我很喜欢社区的这种热情。如果你能在下面发表评论,我将会非常感激!
所有有效的文件都在我公开的Github上;这里所有的一切仅仅是开源的魔法!在这里,可以毫不犹豫的发起问题,提出需求等。