持续集成与持续部署宝典Part 4:建立持续部署流水线

随着Docker项目及其相关生态系统逐渐成熟,容器已经开始被更多企业用在了更大规模的项目中。所以,咱们须要一套连贯的工做流程和流水线来简化大规模项目的部署。mysql

Rancher Labs准备了此持续集成与持续部署系列文章,共两万余字,但愿能供企业参考如何利用诸如Docker和Rancher这类工具来建立属于企业的持续集成和持续部署流水线,并根据本身的实际状况和需求在这CI/CD流水线中也加入自定义的流程。git

本文是此系列文章的最后一篇,咱们将在本文中完成建立持续部署流水线的最后工做。本文内容包括建立持续部署流水线(发布Docker镜像、部署到集成环境、发布和部署一个新的版本)和部署策略(就地更新、蓝绿部署)。sql

建立持续部署流水线docker

咱们已经建立好了测试环境,在前文中咱们也构建好了CI流水线,由它来建立应用、将应用打包进容器、进行集成测试。如今咱们未来到本系列文章的最终章,拓展CI流水线来建立一个持续部署流水线。shell

发布Docker镜像数据库

咱们首先将打包的镜像发布到Docker存储库中。方便起见,咱们使用了一个公共DockerHub仓库,不过,对于实际的开发项目,咱们仍是建议将Docker镜像push到私有库中。下面咱们在Jenkins中建立一个新的Free Style Project任务,点击New Item按钮,把任务命名为push-go-auth-image。完成了这些步骤后,你会进入到Jenkins任务配置页面,在这里你能够定义push你的go-auth镜像到Dockerhub所须要的步骤。安全

由于这是咱们对前一章中构建的流水线的后续,所以该做业会有和go-auth-integration-test做业相似的配置。你须要首先设置的是parameterized build而且添加GO_AUTH_VERSION变量。并发

要push镜像,咱们选择Add build step下拉菜单,而后选择Execute shell选项。在结果文本框中添加下面的命令。在这些命令中,咱们将登录到DockerHub,而且push咱们以前构建好的镜像。这里咱们准备将其push到usman/go-auth仓库中,而你则须要把它推送到本身的DockerHub库中。负载均衡

上一章提到,咱们使用的是git-flow分支模型,其全部的功能分支都合并到“开发”分支中。为了可以不断地将发生的变动部署到集成环境中,咱们须要一个简单的机制来生成基于开发分支的最新镜像。在打包过程当中,咱们使用GO_AUTH_VERSION来标记docker容器(例如,docker build -t usman/go-auth:${GO_AUTH_VERSION} ....)。在默认状况下,这个版本将会成为开发分支,可是本章后面咱们将为咱们的应用程序建立新发布,使用CI/CD流水线来构建、打包、测试,并把它们部署到咱们的集成环境中。要注意的是,在这个方案中,咱们总会覆盖咱们开发分支的镜像(usman/go-auth:develop) ,这限制了咱们引用历史构建以及执行回滚。你能够对流水线作一个简单的更改,把Jenkins构建编号添加到自身的版本名称上,好比usman/go-auth:develop-14。运维

你须要指定你的DockerHub用户名、密码和电子邮件地址。你能够在每次运行时用参数构建的方式指定它们,也可使用Jenkins Mask Passwords Plugin在主要的Jenkins配置中安全地定义它们,并将它们添加到构建中。要确保Build Environment中为你的做业启用了“Mask passwords(而且启用全局密码)”。

如今咱们须要确保这个做业是在集成测试做业以后才触发的。要作到这一点,咱们须要更新集成测试做业,以便使用当前的构建参数触发参数化构建。这意味着在每次成功运行集成测试做业后,咱们会把测试好的镜像push到DockerHub上。

最后,咱们须要在镜像成功push到DockerHub以后触发部署做业。就像咱们为其余做业所作的同样,咱们能够经过添加构建后操做来实现这一点。

部署到集成环境

咱们将使用Rancher Compose CLI来中止运行的环境,从DockerHub获取最新的镜像,并从新启动环境(提醒一下,Updates API还在发展,可能会发生变化。将来几周或者几个月内确定会增长新的功能,所以请随时查看文档是否有更新项)。在咱们建立Jenkins做业来实现持续部署以前,咱们先手动完成这些步骤。

咱们可使用最简单的方法——中止全部服务(auth服务、负载均衡器以及mysql),提取最新的镜像并启动全部服务。然而,对于咱们来讲,咱们只想更新应用程序,而并不想中止长时间运行的环境,这样就不太理想了。要更新咱们的应用程序,咱们首先要中止auth-service。你能够在Rancher Compose使用stop命令完成操做。

这会中止运行goauth服务的全部容器,你能够在Rancher UI中打开堆栈来验证该服务的状态是否设置为Inactive(不活跃)。接下来,咱们要让Rancher拉取咱们想要部署的镜像版本。如今,咱们已经能够动态指定想要运行的版本,而无需每次都要更新模板了。若是你须要屡次push相同的镜像版本,请添加pull开关,确保咱们使用的是镜像版本的最新副本。

咱们还能够经过下面的命令使用升级功能,零停机地实现环境的滚动更新。下一节中咱们将进一步讨论滚动更新。在升级完成后,你可使--rollbach命令或--confirm-upgrade来确认更改或者回滚到预览状态。

如今咱们已经知道该如何运行咱们的更新,咱们在流水线中建立一个Jenkins做业来执行此操做。和以前同样,建立一个新的freestyle项目,命名为deploy-integration。与其余的做业同样,它也是一个参数化构建,用GO_AUTH_VERSION做为字符串参数。接下来,咱们要从上游的build-go-auth做业中复制工件。

最后,咱们须要向Execute Sheell构建步骤中添加Rancher Compose up命令,这是咱们在以前指定好的。须要注意,你还须要提早在Jenkins上设置Rancher CLI,让它能够用于你在系统路径上的构建。执行shell步骤的内容和下面的代码片断类似。若是你有多个Rancher Compose节点,负载均衡器容器可能会在不一样的主机上启动,你的Route 53记录集合就可能须要更新。

有了咱们两个新的Jenkins做业,咱们从上一章就开始构建的流水线如今看起来就像下图所示。每次对咱们示例应用程序的check-in都会被编译,确保其没有出现语法错误而且可以经过自动化测试。而后,将这些变动打包,经过集成测试,最后再部署到手动测试中。下面的五个步骤为构建流水线提供了一个良好的基线模板,而且有助于将代码从开发阶段转移到测试和部署阶段上。拥有一个连续的部署流水线确保了代码不只能够进过自动化系统的测试,并且还能快速提供给测试人员使用。除此以外它还可以做为生产部署自动化的模型,测试操做工具和代码,持续部署应用程序。

发布和部署一个新的版本

在咱们将代码部署到持续的可测试环境中后,咱们就会让QA团队测试对这些变动进行一段时间的测试。在他们肯定代码已经就绪后,咱们能够建立一个发布,随后将它部署到生产环境中。用git-flow发布的方式相似于特征分支(咱们在前一章讨论过的工做方式),咱们使用gitflow release start [Release Name]命令(以下所示)进行发布。这将建立一个新的名称来发布分支。在这个分支中,咱们将执行一些内部的操做,好比增长版本号,作最后的修改。

完成这些后,咱们运行releasefinish命令将发布分支合并到主分支中。这样,主分支总能反映出最新发布的代码。另外,每一个发布都会加上标签,对每一个发布的内容都可以有历史记录。若是咱们不须要再进行其余的更改,咱们就能够肯定最终的发布了。

最后一步就是把发布push到远端仓库中

git push origin master git push --tags //pushes the v1 tag to remote repository

若是你使用的是Github来托管git库,如今应该会发现有一个新的版本了。咱们还能够将与发布名称相匹配的版本镜像push到DockerHub,这也是一个不错的选择。咱们先运行第一项做业来触发咱们的CD流水线。可能你还记得,咱们为CI流水线设置了GitParameter插件,以便可以从git中获取与过滤器相匹配的全部标记。不过,这是对于默认的开发分支而言,当咱们手动触发流水线时,咱们能够从git标签中进行选择。例如,在下面咱们为应用程序提供了两个版本。咱们选择其中一个,启动集成和部署流水线。

而后,通过如下步骤,咱们的应用程序1.1版本将会被部署到长时间运行的集成环境中,只须要点击几下就能实现。

  1. 从git中获取所选的发布

  2. 构建应用程序,运行单元测试

  3. 建立一个带有标签v1.1的新镜像(好比usman/go-auth:v1.1)

  4. 运行集成测试

  5. Push镜像(usman/go-auth:v1.1)到DockerHub

  6. 将该版本部署到咱们的集成环境

部署策略

管理长时间运行的环境时会遇到不少挑战,其中之一就是尽量在发布期间的停机时间要降至最短,最好为零。为了让这个过程可预测而且安全,须要作至关多的工做。自动化和质量保证确实能够大大提升发布的可预测性和安全性。不过即便是这样,失败也会发生,并且对任何优秀的运维团队来讲,他们的目标都是在最小化影响的同时快速恢复。在本节中,咱们将介绍一些部署长时间运行环境的策略以及它们的优缺点。

就地更新

第一个策略称为就地更新(In-placeupdates),顾名思义,它的思想就是复用应用程序环境,而且就地更新应用程序。这有时也称做是滚动部署。咱们将使用咱们目前讨论的示例应用程序(go-auth)。此外,咱们假定你有用Rancher运行的服务。若是要就地更新,你可使用下面的升级命令:

在用户看不到的地方,Rancher agent会在每一个运行auth服务容器的主机上获取新的镜像(--pull会从新下载,尽管镜像已经存在)。以后代理会中止旧的容器,批量启动新的容器。你可使用--batch-size标志来控制批处理的大小。此外,你还能够指定批更新之间的暂停时间间隔(--interval),使用足够大的时间间隔来验证新容器的行为是否按照预期运行,而且整体而言,服务是健康的。在默认状况下,旧的容器终止后,新的容器会在它们的位置上启动。或者你能够在rancher-compose.yml中设置start_first标志,告诉Rancher在启动新容器以前先中止旧容器。

若是对当前的更新不满意想要回滚,可使用回滚标志来完成回滚。或者你想要继续进行更新,只需告诉rancher指定confirm-update标志完成更新便可。你也能够在原始的up命令中指定confirm-update标志一步完成这些操做。你还能够在RancherUI执行更新,从服务菜单(下图所示)中选择“upgrade”。

就地更新很是简单,不须要额外的资源来管理多个堆栈。然而,这种生产方式是存在缺点的。首先,对回滚更新进行细粒度控制大多很困难,就是说在故障发生的状况下它们每每是难以估计的。例如,处理部分故障和滚动更新会变得很是混乱。你须要知道在哪些节点上部署了更改,哪些没能部署,还有哪些仍在运行以前的版本。其次,你还须要保证全部的更新不只是向后兼容,还能向前兼容,由于旧版本和新版本都是须要在相同的环境中同时运行的。最后,根据使用的状况,就地更新可能不实用。好比,若是老的客户端须要继续使用旧环境,而新的客户端须要向前滚。在这种状况下,使用咱们今天要列出的方法分离客户端会更加容易。

蓝绿部署

就地更新的一个问题是缺乏可预测性。为了克服这一问题,另外一个部署策略是针对应用程序使用两个并行堆栈:一个处于活跃状态,另外一个处于待机状态。要运行新版本,部署应用程序的最新版本到待机堆栈。当验证到新版本须要工做,将会从活动堆栈切换流量到备用堆栈上。这时,先前活跃的堆栈称为备用堆栈,反之亦然。该策略容许验证已经部署的代码、快速回滚(切换备用和从新激活),并还能够在须要时扩展两个堆栈的并发操做。这种策略一般被称为蓝绿部署。用咱们的示例应用程序完成这样的部署,能够简单地在Rancher中建立两个堆栈:go-auth-blue和go-auth-green。此外,咱们假设数据库不是这些堆栈的一部分,而是独立管理的。每一个堆栈都会运行goauth和auth-lb服务。若是假设go-auth-green堆栈式活跃的,要执行更新,咱们要作的就是将最新版本部署到蓝色堆栈中,执行验证并将流量切换到它这。

流量切换

有两个方法可用于执行流量切换,更改DNS记录来指向新堆栈,或者使用代理或负载均衡器,将流量路由到活动堆栈。下面咱们会详细介绍这两个方法。

记录更新

一个简单的方法是更新DNS记录指向活动堆栈。这种方法的一个优势是,咱们可使用加权DNS记录将流量慢慢转换到新版本中。这也是执行canary releases的简单方法,对安全地在实时环境中进行更新或者作A/B测试很是有用。例如,咱们能够将实验性的功能更部署到本身的功能堆栈(或活动堆栈),而后更新DNS,仅将一小部分流量转发到新版本。若是新更新出现问题,咱们能够逆转DNS记录回滚回来。此外,他比将全部流量从一个堆栈切换到另外一个堆栈要安全得多,由于这样会覆盖掉新的堆栈。虽然简单,若是你但愿全部流量能一次切换到新版本,DNS记录更新就把u 事最简洁的方法。根据DNS客户端不一样,这些更改可能须要很长时间才能传播,从而致使和旧版本之间的大量通讯,而不是直接了断切换。

使用反向代理

使用代理或负载均衡器,只须要将其更新成指向新堆栈就能够一次切换整个流量。这种方法在各类场景下都很是有用,例如非向后兼容的更新。要使用Rancher完成这一操做,咱们首先要建立一个仅包含负载均衡器的堆栈。

接着,咱们为负载均衡器指定一个端口,配置SSL并从下拉菜单中选择活动堆栈的负载均衡器做为target service来完成建立。本质上来讲,咱们将负载放到了负载均衡器上,它会在以后将流量路由到实际的服务节点。借助外部负载均衡器,你不须要更新每一个版本的DNS记录。相反,你能够简单地更新外部负载均衡器指向已更新的堆栈。

总 结

在本章中,咱们介绍了如何建立一个持续部署流水线,能够将咱们的示例应用程序放在集成环境中。咱们还研究了如何集成DNS和HTTPs支持来建立一个用户可以进行集成的更加安全可用的环境。在后续的工做中,咱们着眼于运行中的生产环境。部署到生产环境会带来一些列的挑战,咱们但愿部署是知足负载,而且有不多停机时间的(理想下为零)。此外,生产环境也面临着挑战,由于它们必须能向外扩展以知足负载,同时还要减小控制成本。最后,为了提供自动故障转移以及高可用性,咱们对DNS管理进行了更全面地研究。咱们还将研究生产中Docker环境的操做管理以及不一样类型的工做负载,好比state-full链接服务。

结 论

这一系列文章介绍了使用容器实现完整的CI/CD流水线的几种方法。咱们尝试涵盖常见的使用案例,提供详细的示例,而且分享了咱们在Web服务公司工做多年的DevOps中学到的一些最佳实践。将来咱们还会继续将内容进一步深化,发布一份子妹篇,深刻介绍如何在生产中使用容器运行服务,敬请保持关注!

相关文章
相关标签/搜索