K8s 应用发布方案 - 金丝雀

K8s 应用发布方案

项目背景

假设目标场景为需要发布名称为 DataAPI 的应用,此应用在 k8s 集群上共有 5 个 Pod,均为无状态的应用,分布在 2 个节点上。假设目前生产使用版本为 v1,待发布版本为 v2。

准备镜像

已推送镜像 ali-hb-test.huifutest.com/app/dataapi-canary 的 v1, v2 版本到指定测试镜像仓库。

基于 Deployment 创建 Pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dataapi-canary-deploy
  namespace: default
spec:
  replicas: 5
  selector:
    matchLabels:
      app: dataapi
      release: canary
  template:
    metadata:
      labels:
        app: dataapi
        release: canary
    spec:
      containers:
      - name: dataapi-canary
        image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v1
        ports:
        - name: http
          containerPort: 80
k apply -f dataapi-canary.yaml
k get pods
NAME                                      READY   STATUS    RESTARTS   AGE
dataapi-canary-deploy-566b698f7f-csm8l    1/1     Running   0          58s
dataapi-canary-deploy-566b698f7f-kcfbf    1/1     Running   0          48s
dataapi-canary-deploy-566b698f7f-mkvv5    1/1     Running   0          50s
dataapi-canary-deploy-566b698f7f-qrbsf    1/1     Running   0          1m
dataapi-canary-deploy-566b698f7f-x8dgh    1/1     Running   0          57s
dataapi-deployment-7f9bf79875-cftpx       1/1     Running   0          5d
hmas-server-deployment-74bffc5f8c-q9dcm   1/1     Running   0          8d
mind3-base-658944fcff-d544g               1/1     Running   14         4d
vango-deployment-56484d676d-xrr9p         1/1     Running   0          4d

创建 Service

apiVersion: v1
kind: Service
metadata:
  name: dataapi-canary-service
  namespace: default
spec:
  selector:
    app: dataapi
    release: canary
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30800
k apply -f dataapi-canary-service.yaml
 k get svc
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                          AGE
dataapi-canary-service   NodePort    172.16.1.57     <none>        80:30800/TCP                     2m

访问测试

curl http://192.168.25.38:30800
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

可以看到访问返回的内容为 V1

while true ;do sleep 2; curl http://192.168.25.38:30800/hostname.html; done;

每隔两秒请求一次接口,可以看到 svc 是带有负载均衡效果的,平均分配到不同的 pod 上

金丝雀发布

核心思想

为什么叫金丝雀发布(Canary)?以前,旷工开矿,在下矿洞前需要检查下方是否有毒气,矿工们先会放一只金丝雀进去探是否有有毒气体,看金丝雀能否活下来。
金丝雀发布平是一种平滑过渡的一种发布方式 。产品上线,一方面要保证质量,另一方面保证刚上线的系统没有问题,这时候就需要设计一套灰度发布系统,让一部分用户继续使用产品A,另一部用户使用产品B,一旦出现问题可以很快的控制影响,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户流量都迁移到B上。

基于 replicas 实现

新建一个 deploy 配置文件,命名为 dataapi-canary-replicas.yaml。内容主要修改镜像版本为 v2,修改 replicas 为1,修改 deploy 名称为 dataapi-canary-deploy-v2,且 Pod 新增一个标签 version: v2.0 。详细信息如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dataapi-canary-deploy-v2
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dataapi
      release: canary
  template:
    metadata:
      labels:
        app: dataapi
        release: canary
        version: v2.0
    spec:
      containers:
      - name: dataapi-canary
        image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v2
        ports:
        - name: http
          containerPort: 80

新建 Pod 之后会看见一个新创建的 Pod

新建出来的 Pod 因为 包含标签 app: dataapi,release: canary 所以也能被 Service 标签选择器选中,并且我们设置数量为1(相当于放出一只金丝雀),我们进行访问测试,可以看到能访问到 v2 的接口。这里我们还能动态的设置新建的 deploy 的 replicas 数量,来实现测试不同的访问流量占比。

在真正的生产环境中我们现在就应该观察新发布的 v2 版本接口是否正常,如果正常那我们可以将 replicas 数量设置为之前 DataAPI 期待的 5个,并将之前的 deploy 删除,以此来实现平滑的过度。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dataapi-canary-deploy-v2
  namespace: default
spec:
  replicas: 5
  selector:
    matchLabels:
      app: dataapi
      release: canary
  template:
    metadata:
      labels:
        app: dataapi
        release: canary
        version: v2
    spec:
      containers:
      - name: dataapi-canary
        image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v2
        ports:
        - name: http
          containerPort: 80

删除之前的 deploy

进行访问测试 就可以发现全部访问結果都为 v2 了,以此来实现平滑过渡,达到金丝雀发布的目的。

基于 strategy 实现

【注意】测试 rollout pause 之前,已将 Pod 镜像回滚至 v1 状态。
在 deployment 控制器中 spec 下有一个 strategy 字段能让我们灵活的配置 Pod 更新策略,查看描述信息如下:

type 为部署类型。可以是 “重新创建” 或 “滚动更新”。默认为滚动更新。当 type 为 “RollingUpdate” 时,我们可以配置 RollingUpdate 字段。RollingUpdate 字段详细信息如下:

其中 maxSurge 代表更新过程中新建 Pod 最大数量或者比例, maxUnavailable 为更新过程中删除 Pod 的数量或者比例。我们可以动态的调节这两个参数来实现 “金丝雀发布” 或者 “蓝绿部署”。
举例:目前 DataAPI Pod 部署数量为 5,假如我们设置 maxSurge 为 1,maxUnavailable 为 0,即表示在更新过程中只能最大新增一个 Pod,而能删减的 Pod 数量为 0,这时 DataAPI 存活的 Pod 数量为 6 个。由于我们设置的 replicas 为 5,也就是说我们期待的理想状态 Pod 数量是为 5个,但是现在为 6 个,肯定不符合需求!所以 deploy 控制器就会删除一个原来的 Pod。那有什么方法是在不影响以前的 Pod 上新增这一个 “金丝雀” 呢?这时我们就可以使用 pause 了。
​ pause 的作用是将发布进行暂停,此时将不受控制器控制。描述信息如下:

基于以上核心思想,我们就可以发布 v2 版本的 DataAPI 程序了。并且通过配置 strategy 信息和 pause 实现金丝雀发布,deploy 配置文件(这里主要新增 strategy 字段信息)如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dataapi-canary-deploy
  namespace: default
spec:
  replicas: 5
  selector:
    matchLabels:
      app: dataapi
      release: canary
  template:
    metadata:
      labels:
        app: dataapi
        release: canary
    spec:
      containers:
      - name: dataapi-canary
        image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v1
        ports:
        - name: http
          containerPort: 80
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

执行 apply 更新 strategy信息:

 k apply -f dataapi-canary.yaml

查看 deploy 详细信息

 k describe deploy dataapi-canary-deploy

修改 deploy 文件,将 DataAPI 发布镜像版本改为 v2。并更新 Pod,让更新暂停

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dataapi-canary-deploy
  namespace: default
spec:
  replicas: 5
  selector:
    matchLabels:
      app: dataapi
      release: canary
  template:
    metadata:
      labels:
        app: dataapi
        release: canary
    spec:
      containers:
      - name: dataapi-canary
        image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v2
        ports:
        - name: http
          containerPort: 80
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
 kubectl apply -f dataapi-canary.yaml && kubectl rollout pause deploy  dataapi-canary-deploy

查看 Pod 可以看到新建了一个 Pod(相当于放出的金丝雀)

我们进行访问测试

while true ; do curl http://192.168.25.38:30800; done;

可以看到访问的测试中,已经有了 v2 版本的请求响应。这时在真正的生产发布中我们就可以对 v2 版本的接口进行测试了,如果没有问题就可以继续发布下去了。将其余 v1 版本的接口完全替换为 v2 版本的接口。

kubectl rollout resume deploy dataapi-canary-deploy

再次进行测试,就会发现服务已经更新为了 v2 版本。也就完成了一个完整的金丝雀发布。

总结

第一种方式较为简单,第二种方式比较难懂且较为复杂。合理的利用标签选择器和 strategy 还能实现蓝绿部署,A/B 测试等策略。


 上一篇
我真的追星吗? 我真的追星吗?
前几天和家里一个表妹聊天,我提到我要去《中国好声音》看二哥,她说我算是她认识的男生中唯一一个追星的!之后我就有一直问自己,我这算是追星吗?在下结论之前,先搜索二哥在我生活中留下的记忆吧。 云相册里面最早一张是 2017 年 12 月照片,这
2019-06-28
下一篇 
元类 元类
元类注册子类: import json registry = {} def register_class(target_class): registry[target_class.__name__] = target_clas
2019-06-28
  目录