如何jenkins 实现持续部署署的Web服务

3被浏览1043分享邀请回答0添加评论分享收藏感谢收起0添加评论分享收藏感谢收起写回答Docker持续部署图文详解
发表于 08:54|
作者萧田国、张春源
摘要:关于Docker的文章铺天盖地,但精品文章往往翻译居多。都说Docker天生适合持续集成/持续部署,但同样,可落地、实际可操作性的文章也很罕见。
JAVA项目如何通过Docker实现持续部署(只需简单四步),即: 开发同学通过git push上传代码,经Git和Jenkins配合,自动完成程序部署、发布,全程无需运维人员参与。
这是一种真正的容器级的实现,这个带来的好处,不仅仅是效率的提升,更是一种变革:&*&开发人员第一次真正为自己的代码负责——终于可以跳过运维和测试部门,自主维护运行环境(首先是测试/开发环境)。&本文是cSphere Docker实战视频第二讲的文字版,本文联合作者@张春源同学(任职希云cSphere)即为视频主讲人,关于更多系列视频,详见。福利:点击文末的“实战视频”即可手机欣赏本文对应的实战视频哦。
难者不会,会者不难。通过简单的4个配置,即可优雅地实现持续部署。本文依惯例放上目录, 1. 持续部署的技术思路 2. 效果展示 3. 配置Git和Jenkins联动
4. 配置Jenkins自动更新代码 5. 效果图文详解 6. FAQ
好吧,我们正式开始。
1. 持续部署的技术思路
在本例中,假设我们JAVA项目的名称为hello。简要的技术思路如下。
本案例中假设代码托管在上,Jenkins和Docker Registry(类似于yum源)各运行在一个Docker容器中。JAVA项目自己也单独运行在一个叫hello的容器中。 本文采取的持续部署方案,是从私有的Docker Reistry拉取代码。有些变通的方案,把代码放在宿主机上,让容器通过卷组映射来读取。这种方法不建议的原因是,将代码拆分出容器,这违背了Docker的集装箱原则:这也导致装卸复杂度增加。从货运工人角度考虑,整体才是最经济的。这样,也才能实现真正意义的容器级迁移。 或者说,容器时代,抛弃过去文件分发的思想,才是正途。本文最后的问答环节对此有更多阐述。 容器即进程。我们采用上述方案做Docker持续部署的原因和意义,也在于此。容器的生命周期,应该远远短于虚拟机,容器出现问题,应该是立即杀掉,而不是试图恢复。
2. 效果展示
本文最后实现的效果,究竟有多惊艳呢?且看如下的演示。
2.1 程序代码更新前的效果
我们以时间戳来简洁、显式的表述程序更新情况。
2.2 提交程序代码更新本例中,我们把首页的时间戳从,修改为(见如下)。2.3 上传新代码到Git顺序执行如下操作,输入正确的git账号密码。然后呢? 然后什么都不用做了。端杯茶(如果不喜欢咖啡的话),静静地等待自动部署的发生, 旁观一系列被自动触发的过程,机器人似的运转起来(请容稍候再加以描述)。为什么需要3~5分钟?只是因为本案例中的JAVA项目,需要从国外download Maven程序包,以供Jenkins调用和编译JAVA。正式应用环境中,可以把Maven源放在国内或机房。如果仅仅需要对PHP项目做持续部署,那就更快捷了。2.4 查看代码更新后的效果在静静地等待几分钟后,新的代码确实已经自动部署完毕。那么,这一切怎么实现的呢?很复杂么?不然。只要按照如下几步,便可快速实现哦。3. 配置Git和Jenkins联动这个过程也是难者不会,会者不难。主要分为如下三步。3.1 Jenkins配置Git源Jenkins中新建项目java-app,并配置从Git拉取程序代码。具体如下:3.2 Jenkins配置远程构建Jenkins中配置token,以供git远程调用时使用。3.3 Git开启钩子怎么让Git在接收到用户更新的代码后,把消息和任务传递给Jenkins呢?这借助于Git的hook功能,配置起来也非常简单,如下。4. 配置Jenkins自动更新代码Jekins在接收到Git传递过来的消息后,再触发一个远程构建(到目标服务器),按照预定义的任务列表,执行一系列的工作,重建容器等。详见如下:我们把其中最关键的Shell脚本内容摘抄出来。
5. 效果图文详解
在2.3这个章节中,我们当时的操作如下,这个目的是向Git提交更新代码。
当时并没有细说后续发生的事情,既然上面已经说清楚了原理,那我们就可以接下来说说实际发生的事情啦。5.1 上传代码到Git这里貌似整个过程已经完成并顺利退出。其实,后台的工作才刚刚开始哦。这时会触发Git服务器向相应的Jenkins服务器发出一个操作请求,此工作太过迅速,也没啥好说的,我们接下来看Jenkins都干啥子了。5.2 Jenkins进行的精彩互动1)Jenkins会自动"冒出来"一个构建任务。2)我们点进来,看看具体操作日志。是的,正在接受来自Git的任务。
3)下载Maven相关的软件包(就是这个过程慢)。
4)下载完成后,就开始利用maven BUILD 新的hello项目包。
5)然后重建Maven容器,构建新的Image并Push到Docker私有库中。
6)最后,重新把Docker容器拉起来。这样,又新生了。呵呵
问题1:采用这么相对复杂的办法(而不是把更新代码放在宿主机然后卷组映射),是因为项目基于JAVA么;是否PHP项目就可以采用更新代码放在宿主机然后卷组映射这种方式?
回答1:将代码拆分出容器,违背了集装箱原则。导致装卸复杂度增加。从货运工人角度考虑,整体才是最经济的。一切版本化。抛弃过去的文件分发。这是正途。至于文件大小,大的war包也就50M或100M,在现有网络下不成问题,性能问题最好优化。另外建议关注docker
2 docker,p2p传输。
问题2:如果整体代码超过500m或者1g以上,整体集装箱是否就不太好了?如果容器与代码分离,镜像就100m左右(2层,base+服务),然后代码的话,是放到共享存储里,每个代码有更新,比如svn的代码,可以直接在共享存储里进行svn update就可以控制版本&
回答2:如果你的代码500M,那只能说明业务开发该打板子了。
问题3:如果测试环境使用您提供的完整集装箱服务还行,但在生产环境,集群里运行docker做应用,如果每个容器都是有完整的代码,是否有点臃肿,不如每个集群节点里就运行基础服务镜像,通过卷组功能绑定共享存储里的代码,加上Crontab、Python和Shell脚本,这样每次代码更新就1次就行了。
回答3:环境一致性,在过去从来没有解决好。10年前我们做PaaS时,和这个做法类似。不是说不好,时代变了,用脚本东拼西凑,终究难有好的系统。不能只考虑现在的方便,容器技术和vm如果类比,我觉得会让自己下决定时很纠结。
补充3:脚本一般是典型的运维工程师思维,quick & dirty。一般很难做成一个产品或者系统。整体考虑和扩展性考虑都比较少。现在做docker的难点在于到底怎么看待它。到底是拿它做调度的基本单位,还是部署的基本单位考虑清楚,再聊方案。
备注:上述问题的回答,主要由王利俊@cSphere和陈尔冬@华为完成。作者简介:萧田国,男,硕士毕业于北京科技大学,触控科技运维负责人。拥有十多年运维及团队管理经验。先后就职于联想集团(Oracle数据库主管)、搜狐畅游(数据库主管)、智明星通及世纪互联等。从1999年开始,折腾各种数据库如Oracle/MySQL/MS SQL Server/NoSQL等,兼任数据库培训讲师若干年。张春源,目前任职希云cSphere,希云cSphere国际领先的docker管理平台。国内最早期的Docker实践者,在生产环境拥有一年多的Docker容器管理经历。深刻理解Docker对于开发、测试以及运维的价值。擅长利用Docker构建整个DevOps自动化平台。热爱专研Dockerfile这门艺术,并对CoreOS有深入研究。(责编/魏伟)
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章Quora 是如何做持续部署的?工程师如是说 - 文章 - 伯乐在线
& Quora 是如何做持续部署的?工程师如是说
【伯乐在线导读】:Quora 是国外知名的问答网站,曾经在 12 小时内发布了 46 次新版本。不过这对于 Quora 工程师来说,只是普通的一天。他们执行非常快的持续部署周期,代码变动提交后就直接推送到线上。 他们是如何做到的呢?请看 Quora 工程师 Martin Michelsen 的文章。
在 2013 年 4 月 25 日中午 12 点到晚上 11 点 59 分之间,Quora 站点发布了 46 次新版本。这对于我们来说只是普通的一天。我们执行非常快的持续部署周期,代码变动提交后就直接推送到线上。这使得我们可以在各个层面上实现平行化开发。我们希望推送系统足够快,让开发者尽快看到他们对生产环境的改动(目前生产环境修订版上线平均要 6、7 分钟),同时也要注意可靠性和灵活性,让我们可以迅速响应问题。
对开发者而言,只需要一个简单的命令把代码推送到到生产环境:git push
这背后发生的事情要复杂很多。每当一个开发者把提交推送到我们的主 git 仓库,一个 post-receive 钩子会将最新的修订版加入到发版申请列表,并记录到 MySQL 数据库。(post-receive 钩子也会把提交加到 ,我们用它做代码评审。更多关于我们代码评审的相关信息参阅这个回答 )一个内部监控网站展示每个等待发布的修订版的状态。
一个后端服务监控发版申请列表,每当提交新的修订版,服务收集此版本代码库中所有单元测试的名字。我们有上百个测试模块和上千个独立的测试,服务会将测试分配到一些 worker 机器中并行处理。当 worker 运行完测试,它们将结果返回给测试服务,服务在发版申请的列表中标记修订版的综合结果(成功或失败,以及多少个测试失败了和失败的详情)。
同时,另一个服务监控发版申请列表,等待打包新修订版。每当提交新的修订版,它将所有需要运行在我们服务器上的代码进行归档,并打包上传到 Amazon S3。
当修订版打包好后,一个集成测试服务将修订版推送到一台单独的机器(并不是生产环境),用新的包开启 web 服务,并向服务发送请求。只有每个请求返回 200 状态码,集成测试才算通过,如果任何请求返回 4xx 或 5xx 错误码,测试失败。
最后,第四个监控发版申请列表的服务由其他三个服务调用,当修订版的测试和打包没有问题,服务向 S3 上传一个包含版本号的小型元数据文件,来标记修订版的部署(发布)。Web 服务器和其他使用相同代码的机器会周期性检查元数据文件中的版本号,如果有变化,它们会立刻从 S3 上下载最新的包。下载并解压包大概需要一分钟,然后运行新的代码只需要几秒。每台需要代码的机器会独立完成上述操作。我们将这个系统命名为 ,因为在所有需要包的机器上进行部署过程很像虫族(zerg)的 rush 战术。
下图描述了后端架构:
这套系统弹性很大,很少出现失败,但正如其他复杂的系统一样,也会出现失败情况。要么测试 worker 宕机,要么测试服务失败,要么打包程序出现问题。通过这种架构,内部的失败并不会引起一致性问题(比如把未通过单元测试的代码推送到生产环境),并且大多数时候只需要重启失败的机器或服务便可以让其正常工作。
对于大多数修订版,git push 到发布大约间隔 6 分钟,这取决于其中执行时间最长的任务。目前,单元测试是时间最长的任务;打包需要 2-3 分钟,集成测试需要 3 分钟多一点。之后 10 分钟(发布之后),机器下载运行新代码,同时后面的修订版开始测试和打包。(我们不会同一时间更新所有机器,这会导致每次我们发布时,Quora 会有几分钟处于不可用状态!)选择 10 分钟的间隔是为了可靠性 —— 如果我们需要响应突发事件,可以立刻覆盖部署代码。
我认为 6 分钟的测试 + 10 分钟的部署还不够好。我们可以改进测试系统,使其并行测试来提高效率。另外,我们去除掉其他服务中无用的东西,这让我们可以将部署时间由 10 分钟缩短为 5 分钟。
系统的设计主要基于其他公司部署项目时遇到的问题。我们在公司早期就决定采用持续部署方案。在公司规模、代码库、基础架构很小时便于使用这种方案,但我们仍努力多年来维护这一流程,因为持续部署在整个开发流程和开发文化中举足轻重:
持续部署让我们尽可能迅速地将产品的变更展现在用户面前,包括从 bug 的修复到主要特性等一系列东西。
持续部署让我们尽可能迅速隔离并解决出现的问题。当出现 bug,你倾向于在单个提交中 debug,还是从包含一百个提交的整体发版中 debug?
持续部署让我们在改进网站时不需要投入过多精力。我们直到经历了这些之后才意识到这点 —— 持续部署让我们在几分钟之内完成发现问题、快速修复、推送代码并部署到生产环境。如果这些动作时间过长,开发者可能会想“我难道要花一个小时来坐下跟踪代码的推送吗?”。更糟糕的是,如果隔天部署,开发者会想“我难道要明天再审查一遍然后测试代码吗”
持续部署减少了跟踪不同发布状态的多个版本这一工作上的投入。代码是在生产环境还是在发版列表的未推送状态,都一目了然。
持续部署让我们有测试的习惯。毫无疑问,测试非常重要。伴随着变更需要立刻上线的压力,我们没有之后再写测试的余地。我们总是先写好测试。
持续部署很有趣!写代码很有趣,我们的部署过程也应该同样有趣。
通过减少每次版本上线需要的时间,并加强测试,我们每天可以上线更多的修订版,并有效减小变更伴随的阻碍。这也是 Quora 这类快速起步的公司需要的东西。
打赏支持我翻译更多好文章,谢谢!
打赏支持我翻译更多好文章,谢谢!
任选一种支付方式
关于作者:
可能感兴趣的话题
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线登录以解锁更多InfoQ新功能
获取更新并接收通知
给您喜爱的内容点赞
关注您喜爱的编辑与同行
966,690 十月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
通过容器进行持续部署
通过容器进行持续部署
Viktor Farcic
0&他的粉丝
0&他的粉丝
日. 估计阅读时间:
:Facebook、Snapchat、Tumblr等背后的核心技术
亲爱的读者:我们最近添加了一些个人消息定制功能,您只需选择感兴趣的技术主题,即可获取重要资讯的。
相关厂商内容
相关赞助商
相信读者中有很大一部分已经试用过Docker了,即使只是运行由上下载的预构建镜像。或许你的团队已经通过各种实验,认识到Docker为构建微服务所带来的益处,以及这项技术为开发、测试、集成以及最终上线所带来的优势。
不过,在将容器部署至在线环境之前,你必须创建一个完善的构建管道。
将容器技术集成至持续交付管道绝不是一件简单的任务。尽管Docker为我们带来了种种益处,但随之而来的则是在技术与流程方面的各种挑战。本文将为读者列举实现一个全自动化持续部署管道,使其能够构建微服务并部署至Docker容器所需的步骤。
持续部署管道
持续部署管道是在每次代码提交时会执行的一系列步骤。管道的目的是执行一系列任务,将一个经过完整测试的功能性服务或应用部署至生产环境。唯一一个手工操作就是向代码仓库执行一次签入操作,之后的所有步骤都是自动完成的。这种流程可(在一定程度上)消除人为错误的因素,从而增加可靠性。并且可让机器完成他们最擅长的工作(运行重复性的过程,而不是创新性思考),从而增加系统吞吐量。之所以每次提交都需要通过这个管道,原因就在于&持续&这个词。如果你选择延迟这一过程的执行,例如在某个sprint结束前再运行,那么整个测试与部署过程都不再是持续的了。
如果你选择延迟测试与生产环境的部署,那么你同样也延误了发现系统潜在问题的时机,导致的结果是修复这些问题需要投入更多的精力。如果在问题发生一个月后再去尝试修复,比起在问题发生一周内进行修复的成本就要高得多。与之类似,如果在代码提交的几分钟内立即发出bug的通知,那么定位该bug所需的时间就是微不足道的了。不过,持续部署的意义不仅在于节省维护与bug修复的投入,它还能够让你更快地将新特性发布至生产环境中。特性的开发与最终为用户使用之间的时间越短,你就能够越快地从中受益。
我们先不必列出管道中应当包含的全部构建步骤,而是先从一个最小的子集开始,探讨一种可能的方案。这个最小子集能够让你对服务进行测试、构建以及部署。这些任务都是必不可少的。缺少了测试,我们就无法保证该服务能够正常运行。缺少了构建,就没有什么东西可部署。而缺少了部署,用户就无法从新的发布中受益。
传统的软件测试方式是对源代码进行单元测试,这种方式虽然能够带来较高的代码覆盖率,但不见得一定能够保证特性按照预期的方式工作,也无法保证单独的代码单元(方法、函数、类等等)的行为符合设计。为了对特性进行验证,你需要进行功能性测试,这种方式偏向于墨盒测试,与代码没有直接的关联。功能性测试的一个问题在于系统的依赖。Java应用可能需要一个特定的JDK,而Web应用可能需要在大量的浏览器上进行测试。很有可能需要在不同的系统条件组合中对相同的测试集进行重复的测试。
一个令人遗憾的事实是,许多组织的测试并不充分,这无法确保一次新的发布能够在没有人工干预的情况下部署至生产环境中。即使这些测试本身是可靠的,但往往没有将这些测试在所有可能在生产环境中出现的相同条件下运行。出现这一问题的原因与我们对基础设施的管理方式有关。以人工方式对基础设施进行设置的代价是非常高的。为了配置用户可能会使用的所有浏览器,你需要设置多少台服务器?10台还是100台?如果某个项目的运行时依赖与其他项目不同,你又该怎样处理?
大多数企业都需要用到多种不同的环境。比方说某个环境需要运行Ubuntu而另一个需要运行Red Hat,或者是某个环境需要JDK8而另一个环境需要JDK7。这是一种非常费时费力的途径,尤其当这些环境作为静态环境(与之相对的是通过云计算托管的&创建与销毁&途径)时更为明显。即使你为了满足各种组合而设置了足够的服务器,你仍然会遇到速度与灵活性的问题。举例来说,如果某个团队决定开发一个新服务,或是使用不同的技术对某个现有的服务进行重构,从请求搭建新环境直至该环境具备完整的可操作性为止也会浪费大量时间。在这段过程中,持续部署过程将陷入停顿。如果你在这种环境中添加微服务,则浪费的时间将产生指数级的增长。在过去,开发者通常只需关注有限的几个应用程序,而如今则需要关注几十个、几百个、乃至上千个服务。毕竟,微服务的益处包括为某个用例选择最佳技术的灵活性,以及高速的发布。你不希望等到整个系统开发完成,而是希望完成某个属于单一微服务的功能后立即进行发布。这样的瓶颈只要存在一个,就可能会大大地降低整体速度。而在许多情况下,基础设施就是瓶颈所在。
你可以通过使用Docker容器轻松地处理各种测试问题。对服务或应用进行测试所需的各种元素需要、也应当能够设置在某个容器中。请参考一下这个文件,这是一个用于测试微服务的容器,它在后端使用开发,前端使用了,而数据库则采用了MongoDB。它所测试的是一个具备完全自治性的服务切面,与系统中的其他服务相互分离。我并不打算深入讨论Dockerfile定义的细节,只是简单列举其中所包含的内容。该定义包含Git、NodeJS、Gulp以及用于前端的Bower、Scala、SBT以及用于后端的MongoDB。某些测试需要用到Chrome和Firefox。此外还包括了该服务的源代码与所有依赖。我并不是说你的服务也应当选择相同的技术栈,而是想指出,在许多情况下,测试需要用到大量的运行时与系统依赖。
如果你需要搭建一台这样的服务器,就意味着大量的等待时间,直到所有元素都设置完成。而当其他服务也提出了类似的请求之后,你就很可能会遇到各种冲突与问题,毕竟服务器本身就不是为了托管无数存在潜在冲突的依赖而存在的。你也可以选择为测试某个服务创建VM,但这意味着对资源的极大浪费与缓慢的初始化过程。通过使用Docker容器,这一工作就不再属于基础设施团队,而转交开发者负责。开发者们会在测试过程中选择应用所需的组件,在Dockerfile中进行定义,通过团队所用的持续部署工具构建并运行容器,让这一容器执行所需的各种测试。当代码通过全部测试之后,你就可以迈入下一阶段,对服务本身进行构建。测试所用的容器应当在Docker注册表(可选择私有或公有)中进行注册,以便之后重用。除了我们已经提到的各种益处之外,在测试执行结束之后,你就可以销毁该容器,使host服务器回到原来的状态。如此一来,你就可以使用同一台服务器(或服务集群)对你所开发的全部服务进行测试了。
下图中的流程已经开始显得有些复杂了。
当你执行完所有测试后,就可以开始创建容器,并最终将其部署至生产环境中了。由于你很可能会将其部署至一个与你构建所用不同的服务器中,因此你同样应当将其注册在Docker注册表中。
当你完成测试并构建好新的发布后,就可以准备将其部署至生产服务器中了。你所要做的就是获取对应的镜像并运行容器。
当容器已上传至注册表之后,你就可以在每次签入之后部署你的微服务,并以前所未有的速度将新的特性交付给用户。业务负责人会非常高兴并对你进行奖励,而你也会感觉到你的工作是伟大而有意义的。
但目前所定义的流程还远远谈不上一个完整的持续部署管道。它还遗漏了许多步骤、需要考虑的内容以及必需的路径。让我们依次找出这些问题并逐个解决。
通过蓝-绿流程实现安全的部署
整个管道中最危险的步骤可能就是部署了。如果我们获取了某个新的发布并开始运行,Docker Compose就会以新的发布取代旧的发布。也就是说,在过程中会出现一定程度的停机时间。Docker需要停止旧的发布并启动新的发布,同时你的服务也需要进行初始化。虽然这一过程可能只需几分钟、几秒钟甚至是几微秒,但还是造成了停机时间。如果你实施了微服务与持续部署实践,那么发布的次数会比之前更频繁。最终,你可能会在一天之内进行多次部署。无论你决定采用怎样的发布频率,对用户的干扰都是你应当避免的。
应对这一问题的解决方案是蓝-绿部署。如果你初次接触这一主题,欢迎阅读我的文章&&。简单地说,这个过程将部署一个新发布,使其与旧发布并行运行。可将某个版本称为&蓝&,另一个版本称为&绿&。由于两者是并行运行的,因此不会产生停机时间(至少不会由于部署流程引起停机时间)。并行运行两个版本的方式为我们带来了一些新的可能性,但同时也造成了一些新的挑战。
在实践蓝-绿部署时要考虑的第一件事就是如何将用户的请求从旧的发布重定向至新的发布。在此之前的部署方式中,你只是简单地将旧的发布替换为新的发布,因此他们将在相同的服务器与端口上运行。而蓝-绿部署将并行运行两个版本,每个版本将使用自己的端口。有可能你已经使用了某些代理服务(、等等),那么你可能会面对一个新的挑战,即这些代理不能是静态的了。在每次新发布中,代理的配置需要进行持续变更。如果你在集群中进行部署,那么该过程将变得更为复杂。不仅端口需要变更,IP地址也需要变更。为了有效地使用集群,你需要将服务部署至在当时最适合的服务器上。决定最适合服务器的条件包括可用的内存、磁盘和CPU的类型等等。通过这种方式,你就能够以最佳的方式分布服务,并极大地优化可用资源的利用率。而这又造成了新的问题,最紧迫的问题是如何找到你所部署的服务的IP地址与端口号。对这个问题的答案是使用服务发现。
服务发现包括三个部分。你首先需要通过一个服务注册表以保存服务的信息。其次,你需要某个进程对新的服务进行注册,并撤消已中止的服务。最后,你需要通过某种方式获取服务的信息。举例来说,当你部署一个新的发布时,注册进程需要在服务注册表中保存IP地址与端口信息。随后,代理可发现这些信息,并通过信息对本身进行重新配置。常见的服务注册表包括、和。你可以使用用于注册和撤消服务以及,并用实现服务发现与模板创建。如果读者希望了解有关服务发现和相关工具的更多知识,欢迎阅读我的&&一文。
现在,你已经找到了一种保存及获取服务信息的机制,可利用该机制对代理进行重新配置,(目前)唯一一个还未解答的问题就是要部署哪个版本(颜色)。当你进行手工部署时,你自然知道之前部署的是哪个颜色。如果你之前部署了绿色,那么现在当然要部署蓝色。如果一切都是自动化执行的,你就需要将这一信息保存起来,让部署流程能够访问它。由于你在流程中已经建立了服务发现功能,你就可以将部署颜色与服务IP地址和端口信息一同保存起来,以便在必要时获取该信息。
在完成了以上工作后,管道将变为下图中所显示的状态。由于步骤的数量提高了,因此我将这些步骤划分为预部署、部署以及部署后三个组。
运行预集成以及集成后测试
你或许已经注意到,部署管道中的第一个步骤是运行测试。虽然测试的运行至关重要,并且为你提供了代码(很可能)能够按预期运行的信心,但它无法验证要部署至生产环境中的服务是否真的能够按预期运行。许多环节都有可能产生错误,可能是没有正确地安装数据库、或是防火墙阻碍了对服务的访问。服务在生产环境上无法正常工作的原因是多种多样的。即使代码按预期工作,也不代表你已验证了部署的服务已得到正确的配置。即便你搭建了一个预发布服务器以部署你的服务,并且进行了又一轮测试,也无法使你完全确信在生产环境中总是能够得到相同的结果。为了区分不同类型的测试,我将其称为&预部署&测试。我有意避免使用更准确的名称,因为你在早期阶段所运行的测试类型对于每个项目来说都是不同的。他们有可能表示单元测试、功能测试或是其他类型的测试。无论是哪种类型的测试,他们的共同点在于,你会在构建与部署服务之前运行这些测试。
蓝-绿流程为你展现了一种新的机会。由于旧发布与新发布是并行运行的,你就可以对新发布进行测试,随后再对代理进行重新配置,以指向新的发布。通过这种方式,你就可以放心地将新发布部署至生产环境并进行测试,而代理仍会将你的用户重定向至旧的发布。我倾向于将这一阶段的测试称为&预集成&测试。这个名字或许不是最好的,因为许多开发者更熟悉它的另一个名字&集成测试&。但在这个特殊的场景中,它意味着你在将新发布与代理服务集成之前(在代理进行重新配置之前)所需运行的测试。这些测试可以让你忽略预发布环境(这种环境与生产环境永远做不到完全一致),使用对代理重新配置之后用户将使用的完全相同配置对新发布进行测试。当然,&完全&这个词并不太准确,区别在于你会在不使用代理的情况下对服务进行测试,而用户将无法访问这些服务。与预部署测试一样,预集成测试的结果将指示你是继续走完工作流,还是中止这一流程。
最后,当我们重新配置代理之后,还需要再进行一轮测试。这一轮测试称为&集成后&测试,这一过程应当能够快速完成,因为唯一需要验证的就是代理是否确实正确地配置了。通常来说,只需对80(HTTP)与443(HTTPS)端口进行几次请求作为测试就足够了。
在你实施了Docker之后,就应当以容器方式运行所有这些测试,与我建议你进行预部署测试的方式相同,也能够带来相同的益处。并且在很多情况下,同样的测试容器可用于所有的测试类型。我倾向于通过一个环境变量表示所运行的测试的类型。
回滚与清理
在我们回顾这套测试步骤的成败之前,让我们首先定义生产环境的理想状态。我们的逻辑很简单,如果整个流程有任何一部分出错,整个环境就应当保持与该流程尚未初始化之前相同的状态。我们要实现的并不复杂,只是为发生的问题触发某种形式的通知,并且在团队中建立一种文化:修复破坏流程的问题是第一优先任务。问题在于,回滚并不像听上去那么简单。幸运的是,Docker容器使这一操作比使用其他任何途径都要简单,因为它对环境本身会产生的副作用非常小。
根据预部署测试的结果决定下一步非常简单,因为此时你还没有进行任何实际的部署,因此可随意决定继续流程还是中止流程。但另一方面,在你获得预集成测试的结果前所执行的步骤会使生产环境处于一个非理想状态。你已经部署了新的发布(蓝或绿),如果该发布有错误,你必须撤消这一发布。在撤消发布之后,你还需要删除这些发布所生成的任何服务数据。由于代理仍然指向旧发布,因此用户实际上仍然在使用旧发布的特性,而不会注意到你在尝试部署新的特性。而最后的测试过程(即集成后测试)会带来一些额外的困难,因为代理已经重新定向至新的发布,你需要将其恢复成原先的设置。而部署颜色(版本)的注册也同样需要成原先的设置。
虽然我之前仅谈到了由测试所引起的故障,但并不意味着流程中的其他步骤不会失败。这些步骤同样会出错,应当使用类似的逻辑以解决这些问题。无论是哪个步骤失败了,系统环境都需要恢复成之前的状态。
即使整个过程如计划般一样顺利执行,也仍然有一些清理工作需要处理。你需要停止旧的发布,并删除其注册信息。
目前为止,我还没有提到数据库,而数据库往往会给回滚阶段造成最大的挑战。这一主题已经超出了本文的范围,所以我只打算描述一下我认为最主要的规则:始终确保新发布中产生的模式变更是向后兼容的,并通过大量的测试来确认这一点。你必须在预部署测试阶段运行这些测试。经常有人向我抱怨,保证向后兼容性是不可行的。在某些场景中,这种说法没错。但在多数情况下,这种观点总是来自于瀑布开发过程,团队每个月、甚至每年才会发布一次产品。而如果团队能够保持管道周期的简短,并且在每次签入时都能够执行(假设我们每天至少部署一次),那么影响到数据库的变更通常来说是比较小的,在这种情况下可以比较简单地实现向后兼容性。
决定每个步骤的执行环境
决定每个步骤的执行环境是至关重要的。按照一般的规则来说,尽量不要在生产服务器中执行。这表示除了部署相关的任务都应当在一个专属于持续部署的独立的集群中执行。在下图中,我将这些任务标记为黄色,并将需要在生产环境中执行的任务标记为蓝色。请注意,即使是蓝色的任务也不应当直接在生产环境中执行,而是通过工具的API执行。举例来说,如果你使用Docker Swarm进行容器的部署,那么无需直接访问主节点所在的服务,而是创建DOCKER_HOST变量,将最终的目标地址通知本地Docker客户端。
完成整个持续部署流
现在我们已经能够可靠地将每次签入部署至生产环境中了,但我们的工作只完成了一半。另一半工作是对部署进行监控,并根据实时数据与历史数据进行相应的操作。由于我们的最终目标是将代码签入后的一切操作实现自动化,因此人为的交互将会降至最低。创建一个具备自恢复能力的系统是一个很大的挑战,它需要你进行持续地调整。你不仅希望系统能够从故障中恢复(响应式恢复),同时也希望能够第一时间防止这些故障出现的可能(预防性恢复)。
如果某个服务进程出于某种原因中止了运行,系统应当再次将其初始化。如果产生故障的原因是某个节点变得不可靠,那么初始化过程应当在另一个(健康的)服务器中运行。响应式恢复的要点在于通过工具进行数据收集、持续地监控服务、并在发生故障时采取行动。预防性恢复则要复杂许多,它需要将历史数据记录在数据库中,对各种模式进行评估,以预测未来是否会发生某些异常情况。预防性恢复可能会发现访问量处于不断上升的情况,需要在几个小时之内对系统进行扩展。也可能是每个周一早上是访问量的峰值,系统在这段时间需要扩展,随后在访问量恢复正常之后收缩成原来的规模。如果你有兴趣这方面的更多细节,欢迎阅读我的文章&&与&&。
在持续部署流程中使用的工具取决于个人的偏好,以及项目的特点。因此,我不打算提出一个明确的提议,而是分享一下我个人的偏好。
对于任何基于微服务的架构来说,Docker是一个很明显的选择。我甚至可以说,如果没有容器技术(Docker或其他类型的工具)的出现,那么微服务所造成的问题将超过解决方案。你可以在&&这篇文章中找到更多的信息。在代理方面,NGINX与HAProxy的表现都很出色,虽然他们各自有所缺陷,但总的来说不失为一个好的选择。
如果你的集群具有一定规模,则必须使用一个编排工具。我倾向于选择,与其他工具相比,它提供了更大的自由度。但从另一方面来说,它为分布式所提供的工具较少。你需要自行打造所需的工具(可以说,这就是自由的代价)。Kubernetes相对来说更为成熟,所提供的功能也更多。Mesos在最初设计时并非打算用于Docker,但目前已经开始提供了对Docker的支持。如果你希望了解更详细的对比信息,欢迎阅读我的文章&&。
最后,我偏爱的CI/CD服务器是。请记住,实现本文中所描述的流程是非常艰难的,而将一些无固定风格的作业连接在一起也会造成高昂的维护成本。因此,我偏爱的方式是使用及插件。如果希望了解Jenkins Pipeline的更多信息,欢迎阅读我的文章&&及&&。
The DevOps 2.0 Toolkit
如果本文有幸得到你的喜爱,那么你或许同样会对我的这本书籍感兴趣。本书对包括微服务、容器以及持续部署在内的内容进行了更为深入的探讨。
本书的主旨是表现如何使用不同的技术帮助我们以更好、更高效的方式设计软件,将微服务以不可变容器的方式打包,在通过配置管理工具自动设置的服务器上进行持续地测试与部署。目标是在零停机时间的基础上实现快速、可靠、持续的部署,并具备回滚能力。此外还包括扩展至任意数量的服务器上、对能够从硬件与软件故障中恢复的自恢复系统的设计、以及集群的集中式日志记录与监控。
换句话说,本书描述了在微服务开发与部署生命周期中对某些最新、以及最佳实践和工具的应用。涵盖的内容包括Docker、Kubernetes、Ansible、Ubuntu、Docker Swarmt和Docker Compose、Consul、etcd、Registrator、confd及Jenkins等等。我在书中依次讲解了大量的实践以及更多的工具
读者可在或Amazon上(包括与全球的其他网站)订购本书。
Viktor Farcic在担任高级顾问。他曾使用各种语言进行编码工作,从Pascal开始(是的,他年纪不轻了),包括Basic(当时还没有Visual前缀)、ASP(当时还没有.NET后缀)、C、C++、Perl、Python、ASP.NET、Visual Basic、C#、JavaScript等等。不过,他从来没有Fortran的编码经验。他目前最喜爱的技术是Scala与JavaScript,虽然在办公室使用最多的还是Java。他对于、(CI/CD)以及(TDD)充满了热情。
Docker在2013年三月实现了开源发布,它的出现让软件开发行业对于现代化应用的打包以及部署方式发生了巨大的变化。紧随着Docker的发布,各种具有竞争性、致敬性以及支持性的容器技术纷纷涌现,为这一领域带来了极大的关注度,同时也引起了人们的反思。这一系列文章将解答读者的各种困惑,对如何在企业中实际使用容器进行分析。
这一系列文章首先将对容器背后的核心技术进行观察,了解开发者目前如何使用容器,随后将分析在企业中部署容器的核心挑战,例如如何将容器技术与持续集成和持续交付管道进行集成,并对监控方式进行改进,以支持不断变化的负载,以及使用短期容器的潜在需求。本系列文章的总结部分将对容器技术的未来进行分析,并探讨无核化技术(unikernels)目前在处于技术前沿的组织中所扮演的角色。
本文是本系列文章&&中的其中一篇。你可以通过RSS该系列文章,以获取更新的通知。
查看英文原文:
Author Contacted
语言 & 开发
96 他的粉丝
65 他的粉丝
0 他的粉丝
65 他的粉丝
58 他的粉丝
1 他的粉丝
22 他的粉丝
0 他的粉丝
12 他的粉丝
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
订阅InfoQ每周精要,加入拥有25万多名资深开发者的庞大技术社区。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。

我要回帖

更多关于 docker 持续集成部署 的文章

 

随机推荐