如何实现容器化应用程序的持续交付效果?

以Docker为代表的应用程序容器方案将恒定镜像等最佳实践变为现实,同时允许DevOps与平台技术团队各自关注不同的工作重点,而这无疑将DevOps生产效率提升到了新的高度。在今天的文章中,我们将探讨容器技术如何简化全面自动化的持续交付流程,其全面涵盖从代码提交到生产环境下代码运行的一切实际场景。我们还将了解跨越持续集成/持续交付流程中的容器定义与管理最佳实践,并审视各类新型应用特性的部署、测试与发布。

如何实现容器化应用程序的持续交付效果?

容器镜像与标签

应用程序容器的生命周期跨越整个开发与运营流程,而容器镜像本身相当于开发与运营之间的协议。在典型周期当中,开发阶段我们需要进行代码更新、单元测试以及容器镜像构建等一系列任务。该容器镜像随后能够被推送至中央库当中。接下来,在执行测试或者部署应用程序的同时,容器镜像可被随时从中央库中提取出来。

因此该镜像通过进行多次更新,并根据版本迭代做出变更,从而实现高效管理。举例来说,Docker镜像会利用层与写入内容复制机制以保证镜像每次更新时只变动其中发生变更的部分。

在Docker概念当中,容器镜像被保存在一套镜像注册表当中,或者简称为注册表(同样的机制亦被称为Docker Hub、谷歌容器注册表、Quay等等)。在一套注册表中,每套应用程序容器都拥有自己的镜像库,且其中包含多个标签。

Docker允许管理员为单一容器镜像设定多个标签。大家可以将这些标签视为一个命名指针,其指向单一镜像ID。标签的作用是提供基元以管理整个交付流程中的各容器镜像。

截止目前,Docker标签具备可变属性。这意味着一个标签可随时间推移指向其它不同镜像。举例来说,“latest”标签通常被用于指代最新可用镜像。尽管我们能够很方便地变更标签所指向的具体镜像,但这同时也带来了新的问题,即单一标签往往无法保证始终指向同一镜像。

社区方面已经就此提出要求,主张在Docker当中提供恒定标签功能,或者允许使用者利用恒定的镜像ID进行镜像提取。在这些问题得到解决之前,目前的最佳实践就是以自动化方式进行标签管理,同时建立一套严格的命名机制从而将可变标签从恒定标签中剥离出来。

构建恒定容器镜像

在使用应用程序容器时,开发人员通常会编写代码并在自己的笔记本设备上以本地方式运行单元测试。此外,开发人员还可以构建容器镜像,但这些镜像可能尚未做好供其他团队成员使用的准备,因此其并不会被真正推送到镜像注册表当中。

目前的最佳实践在于利用自动化步骤对应用程序进行容器化,并将其作为代码库中的组成部分。对于Docker而言,这些步骤会在Dockerfile当中进行定义,而Dockerfile则可同代码一同进行检查。当变更提交完成后,以Jenkins或者Bamboo为代表的构建编排工具能够构建并标记容器镜像,而后将镜像推送至一套共享式镜像注册表当中。

通过这种方式,每套build能够为我们的应用程序组件创建一个恒定镜像,而此镜像能够囊括一切在任意能够托管容器的系统之上运行该组件的必要元素。该镜像不应要求任何其它配置管理或者安装步骤。尽管从表面上看,为每一套build创建一套恒定镜像似乎有点浪费资源,但像Docker这样的容器引擎能够优化镜像管理,并利用按写入复制等技术保证不同build之间只有变更内容得到更新。

尽管应用程序组件并不需要每次部署都进行重新配置,但也许部分配置数据在组件运行中有其必要作用。这种配置信息最好进行外部化,同时注入到运行时当中以支撑该容器。容器部署与运行工具应当允许这些配置信息作为环境变量进行注入,同时以动态方式注入配置信息以保障不同服务之间的运行依赖关系。举例来说,在Nirmata中创建环境时,我们可以利用将环境变量添加至一到两项服务当中。

容器感知部署流程

部署流程由多个步骤构成,这些步骤负责分别实现执行、构建、测试以及将代码发布至生产环境。这些步骤亦可根据阶段进行组织,而各阶段则可实现全面自动化或者要求特定人工步骤介入。

一旦大家已经开始使用应用程序容器,那么整个部署流程就需要识别容器镜像与标签。最重要的了解容器镜像目前正处于部署流程中的哪个阶段。大家可以通过以下方式实现这项目标:

1. 在流程当中定义阶段与环境类型。

2. 为恒定镜像标签设定一套命名规则,其将应用至由该构建工具生成的每套镜像当中。该标签应当始终保持不变:

例如 {YYYYMMDD}_{build number}

3. 为将被环境所接受的镜像标签设定命名规则:

例如 {environment name}_latest

4. 为将在部署流程当中被环境继承至下一阶段的镜像标签定义命名规则。

例如 {next environment name}_latest

利用这些规则,每套容器镜像都能够拥有至少2个标签,这些标签将被用于定义并追踪对应容器镜像在整个部署流程当中的开发进度:

  1. 当该镜像构建完成且永不变更时,为其分配一个独特的恒定标签。
  2. 设定可变标签以标记镜像在部署流程当中所处的具体阶段。

应用程序容器交付与生命周期管理工具,现在已经能够利用这些信息以治理并管理自动化部署流程。举例来说,在Nirmata当中大家可以定义环境类型以表明部署流程中的各个阶段,而标签命名规则则用于标记哪些标签可被纳入各个环境类型以及如何利用命名标签实现源自环境类型的镜像继承。

更新应用程序容器

截至目前,我们已经讨论了如何构建容器镜像并在部署流程当中管理容器镜像。下一步要做的就是在单一或者多套环境当中实现应用程序更新。在这一章节当中,我们将探讨容器机制怎样通过最佳实践实现应用程序的跨环境更新。

微服务

微服务是一种架构类型,其中一款应用程序会被拆分成多项独立服务,而每项服务在设计上具备弹性、灵活性、可组合能力、最小化以及完整性。微服务能够随企业与软件代码库的发展实现规模化环境下的敏捷需求,同时也开始逐步成为越来越多企业应用程序的首选架构解决方案。

容器在部署与运行速度方面拥有突出优势。由于其软件包与系统拥有轻量化特性,因此容器就成了微服务的理想交付载体——只要该服务目前能够运行在其容器环境中,那么每项独立服务都拥有自己的容器镜像与实例。

微服务类应用程序的一大优势在于其拥有细颗度版本控制与发布管理能力,因此每项服务都能够独立实现版本控制与更新。在微服务方案的帮助下,相较于以往对包含大量变更内容的整体系统进行测试与重新部署,如今我们可以更加安全地为生产系统实现增量式变更。另外在合适工具的辅助下,我们也能够同时运行同一服务的多个版本,并根据不同服务版本的实际表现管理客户请求。

蓝-绿部署

所谓蓝-绿部署(有时候也被称为红-黑部署)是一类发布管理最佳实践,其允许我们根据潜在问题进行快速恢复。当执行蓝-绿更新时,新版本(也就是‘绿’)会在发布的同时继续保持现有版本(也就是‘蓝’)的正常运行,此外通过对上游负载均衡或者DNS服务的更新将流量转发至“绿”版本当中。这种部署方式的优势在于,一旦发生问题,大家可以轻松将流量重新引导至仍处于正常运行状态的“蓝”版本处。

容器技术的出现使得蓝-绿部署机制速度更快且更易于执行。由于容器能够提供恒定镜像,因此其始终能够保护回滚至前一镜像版本的能力。另外,由于镜像管理功能经过优化,我们能够在数秒之内完成整个回滚流程。

不过,容器机制的真正价值在于大家可以将蓝-绿部署方案同微服务类应用程序加以结合。如今已经有多种独立服务能够利用这项最佳实践,而其也将在未来帮助更多管理员降低变更影响范畴并控制潜在错误。

金丝雀启动

金丝雀启动机制在创新方面要比蓝-绿部署更进一步,其能够为生产系统提供更为安全的变更部署效果。在使用蓝-绿部署方案时,用户通常需要从应用程序组件的蓝或者绿版本中做出选择,而金丝雀启动则能够同时运行新版本与旧版本,且只有指定用户能够接触到其中的新版本。这就使得我们可以及时纠正新版本中存在的问题,并在确保一切正常之后才将其发送给更多用户。

举例来说,我们可以将某项服务升级至新版本(例如6.1版本),但只允许内部或者测试用户对该服务进行调用。如果该项服务的新版本拥有稳定的运行表现,那么大家能够将一小部分生产流量引导至该版本当中。随着时间推移,这一比例或者生产性流量总量逐步提升,而旧版本则慢慢被淘汰出局。

虽然容器本身并不是实现及管理金丝雀启动机制的必要前提,但其确实能够帮助我们实现更新策略的标准化与自动化。举例来说,Nirmata允许用户选定一套立足于不同环境基础的服务更新处理方案。用户也可以轻松选择如何通知并手动触发更新回滚,选择添加新版本并确保其与现有版本协同运作,或者选择通过滚动更新替代现有版本。

环境现在将以一次性方式存在

云计算令软件定义基础设施快速兴趣,并允许我们将服务器转化为一次性资源实体。容器则将这种趋势推进至新的高度。容器拥有卓越的部署与启动速度,而且在正确编排与自动化工具的辅助下,大家现在可以将整套环境视为按需与一次性功能实体。

虽然生产环境还将在相当长的历史时期当中持续存在,但新型方案确实能够在开发与测试环境下发挥重要优势,且通过一键式操作实现重新创建。现在,部署流程可以与自动化测试机制相对接,包括其中的环境启动、测试运行以及环境测试成功判断等等。

总结陈词

容器已经快速兴起并成为DevOps与持续交付工作中的一项基础性工具。伴随着微服务类架构,容器技术能够甚至足以帮助我们在整套交付流程中利用最佳实践管理应用程序组件——从代码提交至生产运行皆涵盖于其中。

相关推荐