Kubernetes 设计模式笔记 —— 声明式部署

声明式部署(Declarative Deployment)模式主要体现在 Kubernetes 对其 Deployment 对象的应用上。

升级某个服务意味着,需要平滑地关闭旧版本的 Pod,启动新版本的 Pod,然后等待和确认其部署成功,有时候在部署失败时还需要执行回滚操作。
这些步骤或者需要一定的 downtime,同时不会有多个版本的服务在并行地运行(旧版本完全停止后再启动新版本);或者不允许有 downtime,但在升级过程中,新旧版本的服务同时在线会造成资源消耗的增长(旧版本开始停止的时候就添加新版本的实例)。

手动执行上述操作难免会有错误发生,写脚本来自动化处理又需要付出较大的时间成本。好在 Kubernetes 通过 Deployment 概念自动化了这些升级、回滚流程,可以在 Deployment 中定义替换的策略(如 RollingUpdateRecreate)以及其他升级过程中的细节。

Rolling Deployment

下面是一个采用滚动升级(rolling update)策略的 Deployment 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: apps/v1
kind: Deployment
metadata:
name: random-generator
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: random-generator
template:
metadata:
labels:
app: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
readinessProbe:
exec:
command: [ "stat", "/random-generator-ready"]

其中 replicas: 3 表示副本的总数量是 3,在执行 rolling update 时,声明的副本数量必须大于 1。
maxSurge: 1 表示在升级过程中,允许临时添加的 Pod 的最大数量。滚动升级有一个切换的过程,必然导致某个时间段内新旧版本的应用同时运行,从而实际运行的 Pod 数量大于声明的副本数量。此处的配置最多允许 4 个副本同时运行。
maxUnavailable: 1 表示升级过程中可能无法访问的 Pods 数量。此处的配置有可能导致在升级的某个阶段,只有两个 Pods 可用。
readinessProbe 配置对于执行无 downtime 的滚动升级非常关键,它用来判断某个 Pod 副本是否已经在线

Rolling deployment

RollingUpdate 策略会确保升级过程中没有 downtime。Deployment 负责创建新的 ReplicaSet 并用新的容器替换掉旧容器,用户则可以通过配置 maxSurgemaxUnavailable 字段来控制切换的速率。

Deployment 的优势
  • Deployment 是完全被 Kubernetes 内部管理的资源对象,整个的升级过程由 Server 端执行,无需客户端介入
  • Deployment 的声明式性质,使得用户更加关注期望达到的状态而不是达到该状态需要执行的操作步骤
  • 整个升级过程会以版本的方式进行记录,还提供了 pause、continue 和 rollback 等选项

Fixed Deployment

RollingUpdate 策略在需要确保无 downtime 时非常有用,但该方式也有一些负面影响。比如在升级过程中,会有两个版本的容器同时运行,这有可能导致接收服务的客户端出现一些 issue,尤其当更新引入了没有向后兼容的特性时。
在此类场景下,可以使用 Recreate 策略。
Fixed deployment using a Recreate strategy

Recreate 策略的效果类似于 RollingUpdatemaxUnavailable 的值设置成了副本的数量。这意味着所有当前版本的容器都会先被终止掉,在旧容器被全部清理干净之后才开始同步启动所有的新容器。
结果就是升级过程中会存在一定的 downtime。

Blue-Green Release

Blue-Green deployment 发布策略致力于在生产环境中最小化部署时的 downtime。借助 Kubernetes 对于发布行为的抽象(Deployment),用户可以自行定义和实现将不可变的容器从一个版本转换到另一个版本的具体方式,比如 Blue-Green 部署方式。
如果 Kubernetes 集群中并未安装 Service Mesh 或者 Knative 等扩展组件,Blue-Green deployment 就需要手动实现。
其原理就是创建一个新的 Deployment,包含最新版本的容器(green),但是并不向外提供任何服务。旧的 Pod 副本(blue)依然在运行和处理请求。
一旦用户确认新版本的 Pod 是健康的,可以提供服务,就将入站流量从旧的 Pod 副本切换到新版本的副本。在 Kubernetes 中可以通过修改 Service selector 来完成切换动作。当新版本的容器运行稳定后,旧版本即可被删除。
Blue-Green release

Blue-Green 方案的优势在于,同一时间只会有一个特定版本的应用对外提供服务,不需要接收服务的客户端处理多个并行的服务版本;其劣势则在于需要双倍的资源去运行 blue 和 green 容器。此外,有些时候切换的过程会非常复杂。

Canary Release

Canary release 是一种软部署方式,一开始只会将旧版本实例的一个较小的子集替换为新版本。先只允许一小部分用户能够访问更新后的服务,从而降低新版本向生产环境引入的风险。
当能够确认新版本的服务对一小部分用户没有产生负面影响,再用新版全面替换掉旧版。
Canary release

在 Kubernetes 中,上述部署方式可以通过创建一个包含新版本容器的 ReplicaSet 来实现,只不过副本的数量可以设置得很小,作为 Canary 实例。同时 Service 对象负责将一部分用户的请求转发给 Canary 容器。当我们确信新版本应用可以正常提供服务,则横向扩展新的 ReplicaSet 到期望的副本数量,同时收缩旧 ReplicaSet 的副本数量至 0。

总结

Deployment 很好地向我们展示了,Kubernetes 将复杂的手动升级应用的流程,转化为可以重复执行、支持自动化编排的声明式部署。

上述四种部署方式的总结:Deployment and release strategies

参考资料

Kubernetes Patterns