写点什么

笨方法使用 Kubernetes 实现持续交付

2017 年 6 月 21 日

本文要点

  • 使用 Kubernetes 实现持续集成,并不存在所谓正确的或者错误的路线。这取决于团队的需求。
  • 简单的架构可能需要一些手工步骤,实现从 Docker Registry 推送(Push)新的 Docker 镜像到 Kubernetes 集群。
  • 越是复杂的微服务应用,越可能需要复杂的架构。
  • 要实现从草图开始重构由多个微服务组成的应用,需要集中式的 Kubernetes 配置。
  • 如果要实现无需重建应用而快速安全的回滚,那么当新的 Docker 镜像被推送到 Registry 时,或是当已请求回滚并且前期可用的 Docker 镜像已被推送到 Kubernetes 时,需要由发布管理组件去更新配置。

本文将探讨如何构建一种用于持续集成的架构,我们采用了由简至繁的方法。在每一次将架构复杂化时,我们会给出原先的简单方法的局限性,并验证添加架构的复杂性和 / 或重构架构是合理的。

本文所给出的终极方法,是 Weaveworks 探索出的最适合自身的方法。

持续交付

持续交付是以频繁且少量的方式而非一次性大批量的发布去生成软件的方法。

为什么持续交付很重要?将版本持续部署到应用会消除“发布日”的思维模式。理论上讲,版本的完成越是频繁,那么版本的风险也就越低。开发人员还可在代码就绪时更改应用(无论是实现新代码,或是回滚到旧版本)。这意味着可以更快地更改业务,进而使企业更具竞争力。

由于微服务间使用 API 互相通信,需要保证版本间在一定程度上的向后兼容性,以免必须在团队间做版本同步。

根据 Conway 定律,软件呈现了其所属企业的结构。因此,微服务和容器不仅体现了技术上的改进,也同等程度上体现了企业的改进。在将一个单体应用分解为微服务时,应使每个微服务可被独立的团队交付。

在本文中,我们将介绍如何使用 Kubernetes 实现持续交付。

Kubernetes 概述

Kubernetes 是一种管理容器化应用的容器编排器。正如我们先前所提及的,并不存在使用 kubernetes 实现持续交付的所谓正确方法。虽然实现持续交付对发布和自动化非常关键,但是 Kubernetes 并未对该问题提供一种解决方案。

(点击放大图像)

Kubernetes 在平台中可创建和管理的最小单元称为 Pod。我们从上面的结构图中可以看到,一个 Pod 中存在着一个 Docker 容器。Docker 容器镜像将应用代码包括在一个隔离的环境中。

Pod 是一系列在同一机器上一并调度的容器,它们共享同一网络命名空间。一个容器可与本机通信,并发现位于同一 Pod 中、绑定于任何端口上的其它容器。

在 Google 的 Tim Hockin 看来,Pod 并非永生的。他所指的是,如果由于底层硬件故障等原因导致云端机器消失,那么 Pod 也会随之而消亡。针对 Pod 也会消亡这一事实,不应将重要服务置于 Pod 中运行,寄希望于机器不会消失。机器随时都可能会消失,尤其是在云环境中。

应采用的替代做法是将 Pod 包裹在部署中,由部署指定 Pod 的数量。例如,可以定义一个部署为具有一个 Pod 的三个实例,并且这些实例应保持运行。如果当前机器宕机了,部署会将这三个 Pod 实例置于新的机器上,在其它地方启动它们,并保持它们的运行。

Kubernetes 集群是应用实际运行之处。

第一版架构

下面介绍第一种部署,也是最简单的一种部署。其中,受版本控制的代码将持续集成系统与 Docker Registry 联系起来,然后通过持续集成系统将最新的镜像手工部署到 Kubernetes 集群中。手工部署的命令为:

复制代码
kubectl apply -f service.yaml

虽然在一开始时完全可以使用手动部署,但是此后的部署更新应实现持续集成系统的自动化。持续集成系统通过镜像标签更新 Kubernetes,并将更新推送到 Kubernetes API。这使得 Kubernetes 从 Docker Registry 上拉取(Pull)标签所指向的 Docker 镜像,并加以部署。

(点击放大图像)

更改的提交

在这样的架构中,如果开发人员使用git push 在受版本控制的代码中做了一次更改,持续集成系统将自动完成一次Docker build。持续集成系统会对该Docker 镜像做标签,标签所使用的SHA-1 哈希对应于推送代码的SHA-1 哈希,并赋予了唯一的名字。此后,持续集成系统会将镜像推送到Docker Registry。

Kubectl set image

持续集成系统将运行“kubectl set image”程序提交上述更改。kubectl set image 会获取一个运行中的 API 对象,并告知 Kubernetes 使用特定的新标签更新持续集成系统。例如,用户可使用 kubectl set image 更改某个前端服务的当前镜像。

然后,Kubernetes 会自动拉取回新的 Docker 镜像,并替换当前镜像。此外,用户也可以回滚更新,这是 Kubernetes 内建的一个特性。

实现回滚

只要新的更改被推送到 Master 分支,就会进而被推送到生产环境。

要回滚该更改,需要再做一次代码更改。开发人员需要从 Master 分支恢复最近一次提交。当存在合并(Merge)提交时,事情会略为复杂。在理想情况下,用户需重置回最近一次合并前的版本,然后强制推送新的更改。

在推送回滚后,需重构旧版本。持续集成系统将会运转起来,重构该新镜像,并推送新镜像到 Docker Registry。该新镜像是旧镜像的一个新拷贝。

不足之处

这种架构方法存在一些不足之处。首先,容器的构建和推送可能会很慢。无论容器是否最大程度上使用了磁盘 I/O 和网络代码,构建和推送所用时间主要取决于容器中的内容。这对于做回滚是一个问题,因为最终用户为尽快解决问题,需要回滚快速完成。

其次,这种架构耦合紧密,不允许不同的环境(例如开发、试机和生产)处于不同的版本上。对于大多数用户而言,这无疑是一个问题。

下面,我们将尝试对第一版架构进行改进!

第二版架构

(点击放大图像)

第二版架构是基于第一版的初始架构而构建的,它引入了一个理念,即让版本控制配置独立于其余的应用代码版本库(Repo)。这可使用户将版本控制配置作为整个应用的单一数据源(SSOT,Single Source Of Truth),这表示应用是由所有的微服务组成的。

一种做法是让用户服务和具有这些服务代码的订购服务毗邻于它们的Kubernetes YAML。相对于这种做法,更好的做法是拉取所有这些Kubernetes YAML 到一个称为“配置版本库”的集中代码版本库中。

这一点很重要,因为这使得集群被破坏后,用户可从版本控制重构整个集群。现在,如果有人意外地删除了生产集群,该版本控制配置的版本库是恢复应用所唯一必须的。

第二版架构新引入了这样的配置版本库,因此持续集成系统需要多做一些工作。此外,第二版架构与第一版是相同的。

更改的提交

那么在提交了代码更改后,在架构上发生了什么?

持续集成系统会构建一个新的容器镜像,然后持续集成系统(根据代码版本库的响应执行操作)会将更改推送到Docker Register。持续集成系统克隆(Clone)配置版本库的最近版本,对Kubernetes YAML 应用更改。之后,持续集成系统将更改部署到Kubernetes 集群。最后,Kubernetes 集群将镜像从Docker Registry 拉取下来。

不足之处

正如我们在前面所提及的,现在大量的工作由持续集成所承担。最好是让架构的每一部分只去做好一件事情,而不是让架构中的某一部分承担了大部分的负担。

其次,对代码的推送依然是触发持续集成系统的唯一可能途径。最好是无需推送代码就可实现回滚。在这个实例中直接使用kubectl 做带外(Out of Band)回滚,这意味着开发人员必须手工更新中央配置版本库。这使得该版本库不再是SSOT。

第三版架构

(点击放大图像)

我们已经在第二版架构中实现了如上的复杂性,最好是再进一步添加版本管理器。Weaveworks 团队所使用的版本管理器称为 Weave Flux ,它是一个完全开源的版本管理软件,也是 Weave Cloud 的一个组成部分。虽然还有 Spinnaker 等其它类似的产品,但是相比于 Spinnaker,Weave Flux 在设计上要更为简洁,并且是专门针对容器设计的。

加入版本管理器会进一步地简化架构,它使得每个架构元素只具有单一的职责。软件管理器的作用是观察新容器何时出现在 Registry 中,进而克隆被版本控制的配置,修改该配置,并将配置推送回版本库以记录下所产生的版本。同时,它还会推送新配置到 Kubernetes 集群。

更改的提交

现在,持续集成系统已经可以将被版本控制的代码自动构建到容器镜像中,并推送容器镜像到 Docker Registry。

版本控制器从配置版本库中拉取 Kubernetes YAML 并修改它们,并将修改后的版本推送到集群中。之后,Kubernetes 拉取回 Docker Registry 的最近版本。

在上图中,在版本管理器上有一个“纸卷形”的图标,表示了用于不同环境的各种策略。其中,用于试机的策略,可在任何时候发布;用于生产的策略,可使用版本管理器 GUI 上的按钮手工提交版本。这样,单个微服务版本库和所要发布的策略间不再是紧耦合的。

回滚

在第三版架构中实现回滚非常简单。用户只需告知版本管理器要回滚到最近的版本,其中不需要持续集成系统的任何参与。现在由版本管理器实现对配置的更改。

总结

使用 Kubernetes 实现持续交付可以很简单,也可以很复杂。微服务应用越是复杂,就越可能需要复杂的架构。虽然实现持续集成并不存在所谓的错误路线,但重要的是实现自动化,建立 SSOT,并且有效地实现无需推送新代码更改的回滚。

要了解上述三版架构的更多信息,大家可以看一下我对此主题所做的一个完整的演示

作者简介

Luke Marsden是 Weaveworks 客户体验部门负责人。他参与了一些开源项目和软件开发,致力于内容和用户体验,并喜好在聚会和会议上报告。他曾是 ClusterHQ 的联合创始人。

查看英文原文: Continuous Delivery with Kubernetes the Hard Way

2017 年 6 月 21 日 05:204208
用户头像

发布了 226 篇内容, 共 59.5 次阅读, 收获喜欢 14 次。

关注

评论

发布
暂无评论
发现更多内容

Week 2 作业 02

Croesus

架构师训练营第二周笔记-带你认识框架设计原则和设计模式

郎哲158

学习 极客大学架构师训练营 框架设计

第二周作业

极客大学架构师训练营

medo 支付系统架构设计

陈皮

罗辑思维(得到APP)要上市了,你不知道的27件事

赵新龙

罗辑思维 IPO

架构师训练营 -week02- 作业

大刘

极客大学架构师训练营

第二周作业 (作业一)

Geek_83908e

极客大学架构师训练营

架构师训练营第 1 期 -Week2 - 课后练习

鲁小鲁

极客大学架构师训练营 依赖倒置原则 接口隔离原则 框架设计 软件设计原则

第二周作业1

sean

架构一期二班-吴水金-第二课作业

吴水金

架构师训练营第一期 - 第二周课后作业

卖猪肉的大叔

第二周作业 (作业二)

Geek_83908e

极客大学架构师训练营

架构师训练营第一期第2周作业及总结

木头发芽

第二周作业2

sean

Architecture Phase1 Week2:Framework Design

phylony-lu

极客大学架构师训练营

【架构师训练营第 1 期 02 周】 学习总结

Bear在挨踢

极客大学架构师训练营

架构师训练营作业:第二周

m

甲方日常 23

句子

生活 随笔杂谈 减肥

Architecture Phase1 Week2:HomeWork

phylony-lu

极客大学架构师训练营

架构师训练营第二周作业

郎哲158

极客大学架构师训练营

作业一:

静海

架构训练营第二周练习

灰羽零

架构师训练营 - 学习笔记 - 第二周

徐时良

第二周 框架设计 学习笔记

应鹏

学习 极客大学架构师训练营

架构师训练营第 1 期 - 第2周 - 学习总结

wgl

架构师训练营第 2 周课后练习

叶纪想

极客大学架构师训练营

week2

Geek_deb968

用十六年时间,造一座声音“博物馆”:OPPO的影音进击之路

脑极体

第二周 框架设计 作业一

应鹏

极客大学架构师训练营

VS Code 搭建 C++ 开发环境(Mac 环境)

hungxy

c++ vscode

第二周-学习总结

Yangjing

极客大学架构师训练营

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

笨方法使用Kubernetes实现持续交付-InfoQ