有容云:实战总结之 利用Docker、Docker Compose &Rancher构建持续部署

前言:

本文由John Patterson 、 Chris Lunsford写于2016年4月4日,译者有容云张向波,转载请注明出处。(原文链接见文末)

作者John Patterson和Chris Lunsford 运营了一家提供运营和基础架构服务的公司,本文是他们给大家分享的内容:关于如何通过使用Docker、Docker-Compose和Rancher来实现容器部署落地。

我们想跟你一起从头开始体验整个过程,特别是之间遇到的一些痛点和所做的决策。目前,已经有许多的资源和工具可以与Docker一起配合来搭建持续集成和部署工作流程。搭建一个部署工作流程较简单,但是搭建一个部署系统相对比较复杂,因为很多相关的工作流程在已有的环境中已经实现,并且存在很多依赖关系,同时还要让开发和运维部门启用新的工作流程。希望我们在搭建部署系统中的经验能够帮您跳过项目中的那些坑。

在这篇文章中,我们将回顾最初只使用Docker来构建的工作流程。随后的几篇文章中,我们将进一步通过Docker-Compose和Rancher来一起构建工作流程。

以下事件发生在我们长期服务的一家SaaS服务商,接下来我们称这家公司为Acme Business Company或者ABC。这个项目始于ABC着手将大部分Java微服务从自建机房的服务器迁移到AWS的Docker环境中。项目目标主要是降低未来上线周期和拥有更高的应用部署服务可靠性。

实现应用部署的计划如下所示:

整个流程从代码更改、提交、推送到Git仓库开始,这将通知我们的持续集成(CI)系统运行单元测试,单元测试通过的话,编译代码并作为构件保存。如果这步成功通过的话,将触发新任务,通过代码构件来生成Docker镜像并推送到Docker私有镜像仓库。最后,我们将镜像部署到环境中。

必需组件如下:

  • 源代码仓库- ABC将代码保存在私有的GitHub仓库中。
  • 持续集成和部署工具- ABC使用本地安装的Jenkins。
  • 私有镜像仓库-基于S3的Docker镜像仓库为容器提供服务。
  • 运行Docker的主机环境 -ABC 有多个目标环境,且每个目标均包含预发布环境和生产环境。

乍看起来,整个流程还是挺简单的,而实际上并没那么简单。和大多数其他公司一样,ABC以前(现在也是)开发和运维是分开的。当代码准备好部署时,一个包含应用详细信息和目标环境的工单(ticket)将被创建。这个工单将指派给运维部门,并安排在当周的部署维护窗口进行上线。这种情况下,持续部署和交付的方式是不清晰的。

起初,应用部署的工单可能如下:

部署过程:

  • 打开部署窗口,工程师在Jenkins中对相关项目点击“立即构建”,传递分支名字作为参数。输出显示一个被标记tag的Docker镜像被自动推送到镜像仓库。工程师在环境中选择一个当前不在负载均衡设备中激活的Docker主机,登陆并且从镜像仓库拉取新版本镜像。

  • 找到当前运行的容器

  • 停止运行的容器.

配置必须的标识并正确启动新的容器。具体容器配置可以从之前运行的容器,主机shell历史记录,或者从配置文档中获取。

  • 启动服务,通过手工执行测试来确认服务正常。

  • 在生产环境维护窗口,更新负载均衡配置,指向更新的主机。
  • 验证通过后,更新将被应用到环境中需要故障恢复的其他主机上。

这种部署过程并不引人注目,却是持续部署中的第一步,还有很多地方需要改进,先权衡一下收益:

  • 运维工程师可以用相同的步骤来部署所有的应用。Docker run 步骤中参数针对不同的服务或应用需要定制,但步骤始终一致:Docker pull,Docker stop,Docker run。这些流程足够简单,很小概率会遗漏步骤。
  • 最小2台主机组成的环境中,我们进行了可管理的蓝绿部署(灰度发布)。通过负载均衡设备配置在生产窗口进行简单版本切换和回滚。随着部署变得更灵活、支持快速升级、支持快速回滚,后端的服务发现机制也变得更复杂。由于是手动进行,蓝绿部署的成本微乎其微,但带来了直接升级(in-place upgrade)的收益。

痛点:

  • 重复输入相同的命令。 更准确的说,在bash框口中重复输入。这个解决办法很简单,自动化! 有很多工具来解决Docker容器的启动。对运维工程师来说最简单的方式是将重复的逻辑写成bash脚本,这样就有了单一的入口。如果你是一个DevOps工程师,你也可以通过Ansible、Puppet、Chef或者 SaltStack来实现。写脚本逻辑很容易,但有一些问题亟待解决:部署逻辑脚本存放在哪?多个服务使用不同的参数如何追踪和管理?
  • 降低出错率及日志需求-即使运维工程师拥有超人类的能力避免了打字输入错误,在工作一整天后的午夜还能保持头脑清醒,但他也不会知道某个应用服务的端口需要更改为其他端口。Docker端口参数需要更改,原因在于应用程序的具体工作原理只是开发人员比较清楚,需要将这些信息传递给运维团队。多数情况下,运维脚本逻辑记录在一个单独的资源库,亦或者根本没有记录下来。随着应用的不断变化而时时更新应用部署步骤是比较困难的,所以将部署脚本逻辑用Dockerfile提交到代码仓库是一个不错的选择。即使某些情况下不能这样做,也有其他的解决方式(详见后文)。重点是具体的部署步骤被记录并存储了。代码实现要比一个部署工单能更好的完成上述工作,但至少工单记录下来的部署步骤要比没有任何文字记录或者只放在脑子里要好很多。
  • 可见性低  对容器进行故障排查需要登录主机并执行命令。这意味着需要登录一群主机,并重复输入”docker ps” 和”docker logs -tail=100”。有许多很不错的集中日志处理的解决方案,很值得花时间去搭建一套。这个过程中,我们发现比较困难的是,如何定位某个容器运行在哪台主机上。在灰度发布的场景中,开发比较关心当前环境中各个版本的上线情况和扩展水平。对于运维团队来说找到对应的容器来进行升级和故障排查是比较麻烦的。

鉴于此,我们着手对这个问题进行解决。

第一步,将通用的部署过程写成bash脚本,例如:

这个例子只对最简单的容器生效:用户不需要和容器进行直接交互。我们需要添加特定的应用逻辑来启用主机端口映射(host port mapping)和卷挂载(volume mount)。如下:

这个脚本放在所有的Docker主机上来优化部署,运维工程师登录主机,传递参数给脚本,然后脚本负责剩下的工作。部署时间因此缩短,但还是需要手动编写部署脚本的逻辑。此外,有一个新问题,当对通用脚本进行更新后,如何将更新的脚本应用到所有的Host上。通常来说,利用仓库来进行代码和脚本管理有以下优势:代码审查、测试、变更记录、复用。需要人为干预的越少越好。

理论上,部署应用的脚本可以与应用存储在同一个代码仓库中,但实际中很难,最重要的一点就是开发会反对将运维相关的东西放在他们的Java代码仓库中。特别是一些bash部署脚本也包括Dockerfile本身。

这可以归结为一个不同部门的文化问题,如果可能的话,还是值得去尝试的。虽然也可以把部署代码或脚本单独存放在其他仓库中进行维护,但需要额外搞定应用代码和部署代码的同步问题。我们在此将以后面这种方式作为例子。在ABC,每一个项目会单独创建一个文件夹在独立的代码仓库中来存放Dockerfile,部署脚本放在自己的目录下。

Dockerfiles仓库会迁出一份副本到Jenkins主机的公共目录下(如:”/opt/abc/Dockerfiles”)。在构建Docker镜像之前,Jenkins会检查本地“docker”文件夹下是否存在Dockerfile。如果不存在,Jenkins会搜索Dockerfiles路径,拷贝Dockerfile和脚本,再通过“docker build”构建镜像。由于Dockerfile放在Master分支,有可能Dockerfile在某些情况下会超前(或落后)于应用程序配置,实际生产中,这在大多数情况下,不会造成问题。下面是从Jenkins
构建逻辑摘录来的:

渐渐的,Dockerfile和对应的支持脚本被整合到应用的源代码仓库中。由于Jenkins优先在本地仓库中进行查找,所以在整合过程中不需要进行额外的其他配置更改。在迁移完第一个Java应用后,仓库拓扑如下:

我们在将Dockerfile和脚本存储在独立的仓库时,遇到的一个问题是,当应用源代码或者部署脚本发生变更时,都会触发Jenkins重新构建镜像。由于Dockerfiles仓库包含了多个项目的代码,所以在对某一个Dockerfile进行更新时,不希望触发所有项目重新构建。解决方法:一个比较隐蔽的Jenkins配置项 Git
plugin
 - Included Regions。 当启用这个选项后,只有在仓库中特定的文件夹发生变化时,才会触发镜像构建。这使得我们可以将所有的Dockerfile保存在一个仓库,只有当特定的内容在代码库中更新后触发特定的Docker
镜像构建。(相比之前触发所有的项目重新构建)。

另一个问题是运维工程师必须在部署之前进行应用的镜像构建,这会导致上线周期的延长,特别是在镜像构建中出错,需要开发介入。为了减少这种情况,更好的支持持续部署,我们定义每一个提交的大分支版本都触发镜像构建。这要求每一个镜像拥有唯一的版本标识而不只是依靠应用程序的版本标识字符串。我们最终采用应用版本字符-提交次数-提交SHA值

最终显示的版本字符串如:1.0.1-22-7e56158。

在结束我们这次Dockerfile内容的讨论之前,还有一些关键决策值得我们注意。在大规模使用容器之前,我们基本对此一无所知,这些关键点对容器集群的稳定运行有着重要的作用。

  • 重启策略  – 重启策略允许用户定义容器异常终止后的容器动作。容器重启策略可以实现应用程序的故障恢复,一旦应用依赖的子服务从故障中恢复,应用容器即可恢复正常,这得益于应用容器对依赖容器服务可用性的持续监听。长远看来,用户应该配置合适的规则使异常的容器能够在新的主机上启动,这将会节省一部分工作。目前,ABC默认容器重启策略是“-restart
    always”,故障容器将会不断重启,直到容器恢复正常。一个简单的重启策略将会大大降低计划内(和计划外)主机重启带来的负面影响。
  • 资源配额  – 用户可以通过运行时资源来限制配置容器最大可消耗的内存和CPU。资源配额不能防止主机容器的超额分配,但是可以防止容器内存泄漏和失控容器造成的影响。我们对内存比较敏感的容器分配比较大的内存配额(如,内存=8G)。资源配额虽然可能会造成单个应用的内存溢出、无法响应,但保证了主机和其它容器的正常工作。

容器策略和资源配置的协同配合将会带来更高的容器集群稳定性,同时降低故障影响,缩短故障恢复的时间。实践过程中,有了这种保护机制,以往被用来故障恢复的时间,现在用在和开发团队一起进行故障根本原因排查。

小结

我们最初从源代码库构建包含标识符的容器镜像,接下来通过Docker 命令行工具写成的脚本和参数来部署容器。同时梳理了我们环境中的容器部署代码逻辑,强调了那些对有助于运维部门保持服务稳定运行的一些关键决策。

当前这个阶段,镜像构建和部署之间依然存在欠缺。部署维护工程师需要手动登录到服务器执行部署脚本。我们已经比最初的时候前进了一大步,但还有很多内容可以自动化。当前所有的部署逻辑集中在一个脚本中,当开发人员需要安装调试脚本,理清脚本逻辑变得很复杂。目前我们的脚本中也定义了许多环境参数来引入环境参数,查找某个环境变量对应的服务和添加新的环境变量是相对繁琐并容易混淆。

在 下一篇文章,我们将通过解构通用的封装脚本,对我们是如何解决这些痛处一探究竟,介绍如何使用Docker Compose让部署逻辑更贴合应用。

温馨提示

对Docker容器技术或容器生产实施感兴趣的朋友欢迎加群454565480讨论。我们汇集了Docker容器技术落地实施团队精英及业内技术派高人,在线为您分享Docker技术干货。我们的宗旨是为了大家拥有更专业的平台交流Docker实战技术,我们将定期邀请嘉宾做各类话题分享及回顾,共同实践研究Docker容器生态圈。

时间: 2024-08-07 08:40:12

有容云:实战总结之 利用Docker、Docker Compose &Rancher构建持续部署的相关文章

有容云:梁胜-如何让Docker容器在企业中投产(下)

编者注: 本文是对上海容器大会有容云专场梁胜博士直播视频的文字回播,力求高度还原当天演讲内容未加个人观点,如在细节部分略有出入欢迎留言指正.(文章较长,分为上.下两个部分) 前情提要: 在上篇中梁博士讲了容器技术短时间内爆发的根本原因,容器在企业中投产的必要性.必然性以及容器投产四种场景中的前两种:新一代的私有云.混合云环境:企业应用商店和一键部署:本篇将介绍最后两种场景:多环境.多资源池的DevOps流水线,构建轻量级PaaS服务,以及微服务.容器云等方面的内容,阅读前文清点击:梁胜 | 如何

有容云老司机带路, 使用Docker实现丝般顺滑的持续集成

持续集成作为最先进的项目实践之一,近年来逐渐受到国内软件公司的重视:但对于许多朋友来说,可能从来都没有听说过持续集成这个词,抑或只是了解一个概念但并没有实践过. 什么是持续集成?它对软件开发有哪些好处呢? 持续集成的概念 持续集成,Continuous integration ,简称CI. 随着软件开发复杂度的不断提高,团队开发成员间如何更好地协同工作以确保软件开发的质量已经慢慢成为开发过程中不可回避的问题.尤其是近些年来,敏捷(Agile) 在软件工程领域越来越红火,如何能在不断变化的需求中快

有容云:梁胜-如何让Docker容器在企业中投产(上)

编者注: 本文是对上海容器大会有容云专场梁胜博士演讲视频的文字回播,力求高度还原当天演讲内容未加个人观点,如在细节部分略有出入欢迎留言指正.(文章较长,分为上.下两个部分) 在美国的Dockercon大会中,大会主题是怎么样让Docker容器在企业中投产.大家一直在讲这个关于投产的话题,但其实这里面有一个很关键的问题,Docker是一项不错的技术,但是要变成生产力,仅仅是一些研发人员或者是互联网公司能把容器用好还远远不够.怎样让广大企业能够把容器用起来,能够进一步加快自己内部软件开发及部署的速度

有容云——窥探Docker中的Volume Plugin内幕

编者注: 本文根据有容云技术实施团队原创分享内容整理.对Docker技术感兴趣.或对本文中细节需继续探讨的朋友,欢迎加入我们参与讨论! 特别鸣谢中生代技术群分享支持. 注:本期分享由张朝潞原创,有容云整理发布,转载请注明出处 作者介绍: 张朝潞,有容云(Yourun Cloud)平台存储架构师.曾工作于UIT,华三,腾讯,专注分布式存储的研究和开发,对云计算存储解决方案方面有很深的技术造诣和行业理解. 本次交流将与大家分享Docker Volume plugin相关的内容.今日主题是窥探Dock

有容云:容器驱动的PaaS平台实现方案(下)

编者注: 本文基于上海容器大会现场演讲内容,立足于实战跟大家分享了新一代PaaS平台构建中遇到的问题.当下主流PaaS平台解析.企业交付经验及心得体会等.文章较长,分为上.下两个部分,本文为下篇. 前文阅读请点击:容器驱动的PaaS平台实现方案(上) 下面我花一点时间跟大家分享下比较干货的东西.比如说容器的网络,之前我们也听了一些专家谈到Flannel,Calico 等等,但是我不知道大家有没有注意到,国内外在谈容器网络的时候更多的时候会再谈Overlay网的构建,比如IPSec.VXLAN等等

有容云:微服务容器化的挑战和解决之道

注: 本文根据6月是18日七牛云微服务课堂-微服务容器化的挑战和解决之道演讲内容整理而成,演讲者:有容云联合创始人兼首席架构师马洪喜,与大家一起探讨了如何通过容器技术将微服务和 DevOps 落地. 嘉宾介绍: 马洪喜,此前担任 Rancher Labs 中国区技术负责人.Citrix 公司资深架构师.Oracle 公司虚拟化产品开发经理等职务,在容器云.IaaS 云.桌面云建设方面拥有丰富的经验. 单体架构 VS 微服务架构 传统单体架构存在各种各样的问题,如加载编译耗时长.代码管理复杂.横向

有容云:容器驱动的PaaS平台实现方案(上)

编者注: 本文基于上海容器大会现场演讲内容,立足于实战跟大家分享了新一代PaaS平台构建中遇到的问题.当下主流PaaS平台解析.企业交付经验及心得体会等.文章较长,分为上.下两个部分,本文为上篇. 嘉宾介绍: 马洪喜,有容云联合创始人兼首席架构师.此前担任Rancher Labs中国区技术负责人.Citrix公司资深架构师.Oracle公司虚拟化产品开发经理等职务,在容器云.IaaS云.桌面云建设方面拥有较为丰富的经验. 本次大会的大部分朋友都是以用户身份分享了自己家的故事和经验,我作为厂商代表

有容云AppSoar的安装实操

1)  什么是有容云AppSoar? 有容云AppSoar是基于Docker的一种容器管理平台,使Docker应用平台化.图形化界面,使用起来更加快捷.方便.简单. 2)  安装环境: 虚拟机a:192.168.5.38 作为服务器(2 cpu  1core  4G mem,) 虚拟机b:192.168.5.34 作为主机   (2cpu 1core 4G mem ) 查看方法: cat   /proc/cpuinfo (查询cpu信息) cat   /proc/meminfo |grep Me

有容云-PPT | 当微服务遇见容器

编者注: 本文为10月29日有容云高级技术顾问龙淼在Docker Live时代线下系列-广州站中演讲的PPT,本次线下沙龙为有容云倾力打造Docker Live时代系列主题线下沙龙,每月一期畅聊容器技术生态,北京,深圳,广州,上海--有容云跨城带你起航!文中跟大家讨论了以Docker为代表.日益崛起的容器技术,与微服务又将擦出怎样的火花呢?尝鲜难免需要代价,我们将面临哪些挑战,如何迎接挑战,具体详情见以下PPT分享内容.