Kubernetes集群中基于 CRD 实现分批发布

简介: 分批发布是一种通用的发布方式,但是在Kubernetes集群中,要实现分批发布,需要控制各种状态,维护service流量,以及各种label配置,十分麻烦。阿里云容器服务提供一种基于 CRD 的分批发布方式,大大方便发布流程。

分批发布是一种通用的发布方式,但是在Kubernetes集群中,要实现分批发布,需要控制各种状态,维护service流量,以及各种label配置,十分麻烦。阿里云容器服务提供一种基于 CRD 的分批发布方式,大大方便发布流程。

使用kubectl进行分批发布

新集群默认安装了alicloud-application-controller,老集群请先手动安装,安装方式,
kubectl create -f alicloud-application-controller.yml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: alicloud-application-controller
  labels:
    owner: aliyun
    app: alicloud-application-controller
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      owner: aliyun
      app: alicloud-application-controller
  template:
    metadata:
      labels:
        owner: aliyun
        app: alicloud-application-controller
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ''
    spec:
      tolerations:
      - effect: NoSchedule
        operator: Exists
        key: node-role.kubernetes.io/master
      - effect: NoSchedule
        operator: Exists
        key: node.cloudprovider.kubernetes.io/uninitialized
      containers:
        - name: alicloud-application-controller
          image: registry.cn-hangzhou.aliyuncs.com/acs/aliyun-app-lifecycle-manager:0.1-c8d5da8
          imagePullPolicy: IfNotPresent
      serviceAccount: admin

我们这里以下面这个StatefulSet为例子演示分批发布的流程,

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.cn-hangzhou.aliyuncs.com/xianlu/old-nginx
        ports:
        - containerPort: 80
          name: web

这是一个含有三个实例的nginx 实例,为了暴露此容器,我们使用Service来暴露,Service的Yaml如下

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  selector:
    app: nginx
  type: LoadBalancer

这里通过SLB 暴露nginx 服务。
为了保证用户的Yaml安全性,分批发布需要使用Secret来存储最终的yaml,这里需要将yaml执行一下base64操作,再存储。
这个是StatefulSet的Secret Yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysts
type: Opaque
data:
  yaml: YXBpVmVyc2lvbjogYXBwcy92MQpraW5kOiBTdGF0ZWZ1bFNldAptZXRhZGF0YToKICBuYW1lOiB3ZWIKc3BlYzoKICBzZWxlY3RvcjoKICAgIG1hdGNoTGFiZWxzOgogICAgICBhcHA6IG5naW54ICMgaGFzIHRvIG1hdGNoIC5zcGVjLnRlbXBsYXRlLm1ldGFkYXRhLmxhYmVscwogIHNlcnZpY2VOYW1lOiAibmdpbngiCiAgcmVwbGljYXM6IDMgIyBieSBkZWZhdWx0IGlzIDEKICB0ZW1wbGF0ZToKICAgIG1ldGFkYXRhOgogICAgICBsYWJlbHM6CiAgICAgICAgYXBwOiBuZ2lueCAjIGhhcyB0byBtYXRjaCAuc3BlYy5zZWxlY3Rvci5tYXRjaExhYmVscwogICAgc3BlYzoKICAgICAgdGVybWluYXRpb25HcmFjZVBlcmlvZFNlY29uZHM6IDEwCiAgICAgIGNvbnRhaW5lcnM6CiAgICAgIC0gbmFtZTogbmdpbngKICAgICAgICBpbWFnZTogcmVnaXN0cnkuY24taGFuZ3pob3UuYWxpeXVuY3MuY29tL3hpYW5sdS9vbGQtbmdpbngKICAgICAgICBwb3J0czoKICAgICAgICAtIGNvbnRhaW5lclBvcnQ6IDgwCiAgICAgICAgICBuYW1lOiB3ZWI=

下面的为Service的Secret Yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysvc
type: Opaque
data:
  yaml: YXBpVmVyc2lvbjogdjEKa2luZDogU2VydmljZQptZXRhZGF0YToKICBuYW1lOiBuZ2lueAogIGxhYmVsczoKICAgIGFwcDogbmdpbngKc3BlYzoKICBwb3J0czoKICAtIHBvcnQ6IDgwCiAgICBuYW1lOiB3ZWIKICBzZWxlY3RvcjoKICAgIGFwcDogbmdpbngKICB0eXBlOiBMb2FkQmFsYW5jZXI=

分别将上面的两个Secret 创建出来,kubectl create -f xxxxx

1

可以看到两个Secret都已经创建完毕,下面就可以来创建分批发布的 CRD。分批发布的 CRD 格式如下,

apiVersion: alicloud.com/v1beta1
kind: BatchRelease
metadata:
  name: example-batch-release
  annotations:
    aliyun.batchnum: "2"
spec:
  statefulSetSecretName: mysts
  serviceSecretName: mysvc

aliyun.batchnum: 代表分几批发布,目前默认是2批
statefulSetSecretName: 表示存储StatefulSet的Secret 名称
serviceSecretName: 表示存储Service的Secret 名称
使用kubectl create -f xxx 创建此CRD分批发布
2
可以看到,描述资源都已经创建出来了。

[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get sts
NAME      DESIRED   CURRENT   AGE
web       3         3         6m
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get pods -o=wide
NAME      READY     STATUS    RESTARTS   AGE       IP             NODE
web-0     1/1       Running   0          7m        172.16.2.2     cn-hangzhou.i-bp199b7a244chaux4ozh
web-1     1/1       Running   0          6m        172.16.2.131   cn-hangzhou.i-bp199b7a244chaux4ozi
web-2     1/1       Running   0          6m        172.16.1.136   cn-hangzhou.i-bp199b7a244chaux4ozg
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      172.19.0.1      <none>           443/TCP        4h
nginx        LoadBalancer   172.19.12.163   120.55.148.238   80:32065/TCP   7m
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# curl 120.55.148.238
old

可以看到,nginx 的StatefulSet和对应的Service 都已经创建出来,并且curl 是可以直接访问。

下面我们开始分批发布一个新版本的StatefulSet,这里我们新的StatefulSet Yaml 模板如下

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.cn-hangzhou.aliyuncs.com/xianlu/new-nginx
        ports:
        - containerPort: 80
          name: web

可以看到,新老StatefulSet的区别在于,更换了新版本的镜像。
同样,我们需要创建一个Secret 来存储这个新的StatefulSet

apiVersion: v1
kind: Secret
metadata:
  name: my-new-sts
type: Opaque
data:
  yaml: YXBpVmVyc2lvbjogYXBwcy92MQpraW5kOiBTdGF0ZWZ1bFNldAptZXRhZGF0YToKICBuYW1lOiB3ZWIKc3BlYzoKICBzZWxlY3RvcjoKICAgIG1hdGNoTGFiZWxzOgogICAgICBhcHA6IG5naW54ICMgaGFzIHRvIG1hdGNoIC5zcGVjLnRlbXBsYXRlLm1ldGFkYXRhLmxhYmVscwogIHNlcnZpY2VOYW1lOiAibmdpbngiCiAgcmVwbGljYXM6IDMgIyBieSBkZWZhdWx0IGlzIDEKICB0ZW1wbGF0ZToKICAgIG1ldGFkYXRhOgogICAgICBsYWJlbHM6CiAgICAgICAgYXBwOiBuZ2lueCAjIGhhcyB0byBtYXRjaCAuc3BlYy5zZWxlY3Rvci5tYXRjaExhYmVscwogICAgc3BlYzoKICAgICAgdGVybWluYXRpb25HcmFjZVBlcmlvZFNlY29uZHM6IDEwCiAgICAgIGNvbnRhaW5lcnM6CiAgICAgIC0gbmFtZTogbmdpbngKICAgICAgICBpbWFnZTogcmVnaXN0cnkuY24taGFuZ3pob3UuYWxpeXVuY3MuY29tL3hpYW5sdS9uZXctbmdpbngKICAgICAgICBwb3J0czoKICAgICAgICAtIGNvbnRhaW5lclBvcnQ6IDgwCiAgICAgICAgICBuYW1lOiB3ZWI=

然后我们更新刚才创建的 CRD,将statefulSetSecretName改成新的StatefulSet名称。
修改后的CRD Yaml 如下:

[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get BatchRelease example-batch-release -o=yaml
apiVersion: alicloud.com/v1beta1
kind: BatchRelease
metadata:
  annotations:
    aliyun.batchnum: "2"
  clusterName: ""
  creationTimestamp: 2018-07-31T08:17:17Z
  generation: 1
  name: example-batch-release
  namespace: default
  resourceVersion: "43484"
  selfLink: /apis/alicloud.com/v1beta1/namespaces/default/batchreleases/example-batch-release
  uid: 2386ddfd-949a-11e8-a3c2-00163e086528
spec:
  serviceSecretName: mysvc
  statefulSetSecretName: my-new-sts
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl describe BatchRelease example-batch-release
Name:         example-batch-release
Namespace:    default
Labels:       <none>
Annotations:  aliyun.batchnum=2
API Version:  alicloud.com/v1beta1
Kind:         BatchRelease
Metadata:
  Cluster Name:
  Creation Timestamp:  2018-07-31T08:17:17Z
  Generation:          1
  Resource Version:    43484
  Self Link:           /apis/alicloud.com/v1beta1/namespaces/default/batchreleases/example-batch-release
  UID:                 2386ddfd-949a-11e8-a3c2-00163e086528
Spec:
  Service Secret Name:       mysvc
  Stateful Set Secret Name:  my-new-sts
Status:
  Control:
  Release:
    Batch _ Order:  1
    Progress:       finished
    Status:         WaitingForConfirm
  Resources:
    Service:
      Name:       nginx
      Namespace:  default
      Status:     Updating
    Stateful Set:
      Name:       web
      Namespace:  default
      Status:     Updating
Events:
  Type    Reason             Age   From               Message
  ----    ------             ----  ----               -------
  Normal  CreateSubResource  2m    aliyun-controller  Create StatefulSet resource sucessfully
  Normal  CreateSubResource  2m    aliyun-controller  Create service resource sucessfully
  Normal  Synced             2m    aliyun-controller  Batch CRD synced successfully
  Normal  UpdateResource     1m    aliyun-controller  Begin to update StatefulSet web with partition 2
  Normal  UpdateResource     1m    aliyun-controller  Waiting StatefulSet default:web ready, readyReplicas 2 replicas 3 times 1
  Normal  UpdateResource     1m    aliyun-controller  Waiting StatefulSet default:web ready, readyReplicas 2 replicas 3 times 2
  Normal  UpdateResource     1m    aliyun-controller  Begin to update service with new selector map[app:nginx aliyun.version:2]
  Normal  UpdateResource     1m    aliyun-controller  Update StatefulSet and Service sucessfully, waiting confirm
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get pods -o=wide
NAME      READY     STATUS    RESTARTS   AGE       IP             NODE
web-0     1/1       Running   0          2m        172.16.2.132   cn-hangzhou.i-bp199b7a244chaux4ozi
web-1     1/1       Running   0          2m        172.16.2.3     cn-hangzhou.i-bp199b7a244chaux4ozh
web-2     1/1       Running   0          1m        172.16.1.138   cn-hangzhou.i-bp199b7a244chaux4ozg
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      172.19.0.1     <none>           443/TCP        5h
nginx        LoadBalancer   172.19.2.184   101.37.107.187   80:32173/TCP   2m
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# curl 101.37.107.187
new
[root@iZbp11x2k7by5gfy6pkrl1Z ~]#

我们可以通过event 看到 CRD 的所有事件。同时可以看到,nginx的3个pod,已经有一个 pod发生了改变,变成了最新镜像,同时 curl对应的service,会发现流量已经指向了新的pod。这样用户就可以快速试错了。

下面我们来演示如何快速回滚,如果流量打到新的 pod后发现有问题,需要回滚,那么我们需要编辑CRD,

3

将Status 的action 置为rollback 就可以快速回滚。

[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl edit BatchRelease example-batch-release
batchrelease.alicloud.com "example-batch-release" edited
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get pods -o=wide
NAME      READY     STATUS    RESTARTS   AGE       IP             NODE
web-0     1/1       Running   0          7m        172.16.2.132   cn-hangzhou.i-bp199b7a244chaux4ozi
web-1     1/1       Running   0          7m        172.16.2.3     cn-hangzhou.i-bp199b7a244chaux4ozh
web-2     1/1       Running   0          3s        172.16.1.139   cn-hangzhou.i-bp199b7a244chaux4ozg
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      172.19.0.1     <none>           443/TCP        5h
nginx        LoadBalancer   172.19.2.184   101.37.107.187   80:32173/TCP   7m
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# curl 101.37.107.187
old

可以看到原来web-2所在的pod已经被回滚到了老镜像,现在curl service 也都是老的服务了。

发布第二批

4

发布第二批需要在action 置为continue 就可以

[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get pods -o=wide
NAME      READY     STATUS    RESTARTS   AGE       IP             NODE
web-0     1/1       Running   0          3s        172.16.2.138   cn-hangzhou.i-bp199b7a244chaux4ozi
web-1     1/1       Running   0          13s       172.16.2.12    cn-hangzhou.i-bp199b7a244chaux4ozh
web-2     1/1       Running   0          2m        172.16.1.153   cn-hangzhou.i-bp199b7a244chaux4ozg
[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get BatchRelease example-batch-release -o=yaml
apiVersion: alicloud.com/v1beta1
kind: BatchRelease
metadata:
  annotations:
    aliyun.batchnum: "2"
  clusterName: ""
  creationTimestamp: 2018-07-31T09:44:58Z
  generation: 1
  name: example-batch-release
  namespace: default
  resourceVersion: "58066"
  selfLink: /apis/alicloud.com/v1beta1/namespaces/default/batchreleases/example-batch-release
  uid: 6321dcaf-94a6-11e8-a3c2-00163e086528
spec:
  serviceSecretName: mysvc
  statefulSetSecretName: my-new-sts
status:
  control: {}
  release:
    batch_order: "2"
    progress: finished
    status: WaitingForConfirm
  resources:
    Service:
      name: nginx
      namespace: default
      status: Updating
    StatefulSet:
      name: web
      namespace: default
      status: Updating

可以看到StatefulSet的三个 pod都被更新了。

这个时候就可以确认发布了

6

置为confirm 就确定了这次发布。

[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get BatchRelease example-batch-release -o=yaml
apiVersion: alicloud.com/v1beta1
kind: BatchRelease
metadata:
  annotations:
    aliyun.batchnum: "2"
  clusterName: ""
  creationTimestamp: 2018-07-31T09:44:58Z
  generation: 1
  name: example-batch-release
  namespace: default
  resourceVersion: "58542"
  selfLink: /apis/alicloud.com/v1beta1/namespaces/default/batchreleases/example-batch-release
  uid: 6321dcaf-94a6-11e8-a3c2-00163e086528
spec:
  serviceSecretName: mysvc
  statefulSetSecretName: my-new-sts
status:
  control: {}
  release:
    progress: finished
    status: Success
  resources:
    Service:
      name: nginx
      namespace: default
      status: Success
    StatefulSet:
      name: web
      namespace: default
      status: Success


[root@iZbp11x2k7by5gfy6pkrl1Z ~]# kubectl get secret -l owner=aliyun -n=kube-system
NAME                       TYPE      DATA      AGE
example-batch-release.v1   Opaque    4         18m
example-batch-release.v2   Opaque    4         56s

可以看到,所有的确认版本历史都会被记录到secret里面,方便到时候跨版本回滚。

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
6月前
|
人工智能 算法 调度
阿里云ACK托管集群Pro版共享GPU调度操作指南
本文介绍在阿里云ACK托管集群Pro版中,如何通过共享GPU调度实现显存与算力的精细化分配,涵盖前提条件、使用限制、节点池配置及任务部署全流程,提升GPU资源利用率,适用于AI训练与推理场景。
549 1
|
6月前
|
弹性计算 监控 调度
ACK One 注册集群云端节点池升级:IDC 集群一键接入云端 GPU 算力,接入效率提升 80%
ACK One注册集群节点池实现“一键接入”,免去手动编写脚本与GPU驱动安装,支持自动扩缩容与多场景调度,大幅提升K8s集群管理效率。
365 89
|
11月前
|
资源调度 Kubernetes 调度
从单集群到多集群的快速无损转型:ACK One 多集群应用分发
ACK One 的多集群应用分发,可以最小成本地结合您已有的单集群 CD 系统,无需对原先应用资源 YAML 进行修改,即可快速构建成多集群的 CD 系统,并同时获得强大的多集群资源调度和分发的能力。
716 9
|
11月前
|
资源调度 Kubernetes 调度
从单集群到多集群的快速无损转型:ACK One 多集群应用分发
本文介绍如何利用阿里云的分布式云容器平台ACK One的多集群应用分发功能,结合云效CD能力,快速将单集群CD系统升级为多集群CD系统。通过增加分发策略(PropagationPolicy)和差异化策略(OverridePolicy),并修改单集群kubeconfig为舰队kubeconfig,可实现无损改造。该方案具备多地域多集群智能资源调度、重调度及故障迁移等能力,帮助用户提升业务效率与可靠性。
|
存储 Kubernetes 监控
K8s集群实战:使用kubeadm和kuboard部署Kubernetes集群
总之,使用kubeadm和kuboard部署K8s集群就像回归童年一样,简单又有趣。不要忘记,技术是为人服务的,用K8s集群操控云端资源,我们不过是想在复杂的世界找寻简单。尽管部署过程可能遇到困难,但朝着简化复杂的目标,我们就能找到意义和乐趣。希望你也能利用这些工具,找到你的乐趣,满足你的需求。
1089 33
|
Kubernetes 开发者 Docker
集群部署:使用Rancher部署Kubernetes集群。
以上就是使用 Rancher 部署 Kubernetes 集群的流程。使用 Rancher 和 Kubernetes,开发者可以受益于灵活性和可扩展性,允许他们在多种环境中运行多种应用,同时利用自动化工具使工作负载更加高效。
681 19
|
人工智能 分布式计算 调度
打破资源边界、告别资源浪费:ACK One 多集群Spark和AI作业调度
ACK One多集群Spark作业调度,可以帮助您在不影响集群中正在运行的在线业务的前提下,打破资源边界,根据各集群实际剩余资源来进行调度,最大化您多集群中闲置资源的利用率。
|
Prometheus Kubernetes 监控
OpenAI故障复盘 - 阿里云容器服务与可观测产品如何保障大规模K8s集群稳定性
聚焦近日OpenAI的大规模K8s集群故障,介绍阿里云容器服务与可观测团队在大规模K8s场景下我们的建设与沉淀。以及分享对类似故障问题的应对方案:包括在K8s和Prometheus的高可用架构设计方面、事前事后的稳定性保障体系方面。
|
Prometheus Kubernetes 监控
OpenAI故障复盘丨如何保障大规模K8s集群稳定性
OpenAI故障复盘丨如何保障大规模K8s集群稳定性
505 0
OpenAI故障复盘丨如何保障大规模K8s集群稳定性
|
缓存 容灾 网络协议
ACK One多集群网关:实现高效容灾方案
ACK One多集群网关可以帮助您快速构建同城跨AZ多活容灾系统、混合云同城跨AZ多活容灾系统,以及异地容灾系统。

相关产品

  • 容器服务Kubernetes版
  • 推荐镜像

    更多