K8S - 实现statefulset 有状态service的灰度发布

什么是灰度发布 Canary Release

在这里插入图片描述

参考
理解 什么是 滚动更新,蓝绿部署,灰度发布 以及它们的区别




配置partition in updateStrategy/rollingUpdate

这次我为修改了 statefulset 的1个yaml file
statefulsets/stateful-nginx-without-pvc.yaml:

---
apiVersion: v1 # api version
kind: Service # type of this resource e.g. Pod/Deployment ..
metadata:
  name: nginx-stateful-service # name of the service
  labels:
    app: nginx-stateful-service
spec:
  ports: 
  - port: 80 # port of the service, used to access the service
    name: web-port
  clusterIP: None # the service is not exposed outside the cluster
  selector: # label of the Pod that the Service is selecting
    app: nginx-stateful # only service selector could skip the matchLabels:
---


apiVersion: apps/v1
kind: StatefulSet # it's for a stateful application, it's a controller
metadata:
  name: nginx-statefulset # name of the statefulset
  labels:
    app: nginx-stateful
spec: # detail description
  serviceName: "nginx-stateful-service" # name of the service that used to manange the dns,  
                                         # must be the same as the service name defined above
  replicas: 3 # desired replica count
  selector: # label of the Pod that the StatefulSet is managing
    matchLabels:
      app: nginx-stateful
  template: # Pod template
    metadata:
      labels:
        app: nginx-stateful
    spec:
      containers:
      - name: nginx-containe
        image: nginx:1.25.4 # image of the container
        ports: # the ports of the container and they will be exposed
        - containerPort: 80 # the port used by the container service
          name: web-port
  updateStrategy:
    rollingUpdate:
      partition: 2
    type: RollingUpdate

关键是最后1个block

  updateStrategy:
    rollingUpdate:
      partition: 2
    type: RollingUpdate

rollingUpdate 很容易理解, 关键是partition 的值

这个值表示在image 版本更新后, 只会更新 pod-index 中index >= partition 的POD, 其他POD保持先版本, 这就能同时让两个版本存在一段时间, 实现灰度发布




一个例子

首先我们先apply 上面的yaml
[gateman@manjaro-x13 statefulsets]$ kubectl apply -f stateful-nginx-without-pvc.yaml 
service/nginx-stateful-service unchanged
statefulset.apps/nginx-statefulset created
检查pods , 3个pod 起来了分别是0, 1, 2
[gateman@manjaro-x13 statefulsets]$ kubectl get pods -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
nginx-statefulset-0   1/1     Running   0          12m   10.244.2.120   k8s-node0   <none>           <none>
nginx-statefulset-1   1/1     Running   0          12m   10.244.1.59    k8s-node1   <none>           <none>
nginx-statefulset-2   1/1     Running   0          12m   10.244.3.69    k8s-node3   <none>           <none>

为了更好的present, 我们把pods数量scale 到5个
[gateman@manjaro-x13 statefulsets]$ kubectl scale statefulset nginx-statefulset --replicas=5
statefulset.apps/nginx-statefulset scaled
[gateman@manjaro-x13 statefulsets]$ kubectl get pods -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
nginx-statefulset-0   1/1     Running   0          13m   10.244.2.120   k8s-node0   <none>           <none>
nginx-statefulset-1   1/1     Running   0          13m   10.244.1.59    k8s-node1   <none>           <none>
nginx-statefulset-2   1/1     Running   0          13m   10.244.3.69    k8s-node3   <none>           <none>
nginx-statefulset-3   1/1     Running   0          13s   10.244.2.121   k8s-node0   <none>           <none>
nginx-statefulset-4   1/1     Running   0          12s   10.244.3.70    k8s-node3   <none>           <none>

这时5个pod 起来了

查看每个pod的image 版本
[gateman@manjaro-x13 statefulsets]$ kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
nginx-statefulset-0	nginx:1.25.4
nginx-statefulset-1	nginx:1.25.4
nginx-statefulset-2	nginx:1.25.4
nginx-statefulset-3	nginx:1.25.4
nginx-statefulset-4	nginx:1.25.4
这时我们更新image 版本从 1.25.4 更新到1.26.1
[gateman@manjaro-x13 statefulsets]$ kubectl set image statefulset/nginx-statefulset nginx-container=nginx:1.26.1
statefulset.apps/nginx-statefulset image updated
再次检查 每个pod 的image version
nginx-statefulset-0	nginx:1.25.4
nginx-statefulset-1	nginx:1.25.4
nginx-statefulset-2	nginx:1.26.1
nginx-statefulset-3	nginx:1.26.1
nginx-statefulset-4	nginx:1.26.1

可以见到只有pod 2 3 和4 更新了, 0, 1 还是旧版本

下一步, 把新版本应到pod 1 和 pod 0

也很简单, 只需要更改partition 的值就行

---
apiVersion: v1 # api version
kind: Service # type of this resource e.g. Pod/Deployment ..
metadata:
  name: nginx-stateful-service # name of the service
  labels:
    app: nginx-stateful-service
spec:
  ports: 
  - port: 80 # port of the service, used to access the service
    name: web-port
  clusterIP: None # the service is not exposed outside the cluster
  selector: # label of the Pod that the Service is selecting
    app: nginx-stateful # only service selector could skip the matchLabels:
---


apiVersion: apps/v1
kind: StatefulSet # it's for a stateful application, it's a controller
metadata:
  name: nginx-statefulset # name of the statefulset
  labels:
    app: nginx-stateful
spec: # detail description
  serviceName: "nginx-stateful-service" # name of the service that used to manange the dns,  
                                         # must be the same as the service name defined above
  replicas: 5 # desired replica count
  selector: # label of the Pod that the StatefulSet is managing
    matchLabels:
      app: nginx-stateful
  template: # Pod template
    metadata:
      labels:
        app: nginx-stateful
    spec:
      containers:
      - name: nginx-container
        image: nginx:1.26.1 # image of the container
        ports: # the ports of the container and they will be exposed
        - containerPort: 80 # the port used by the container service
          name: web-port
  updateStrategy:
    rollingUpdate:
      partition: 1
    type: RollingUpdate

记得修改3个地方, 1是
replicas: 5 改成当前的数量
image: nginx:1.26.1 要改成新的版本
partition: 1 改成1 就是意思把pod 1 也部署新版本

[gateman@manjaro-x13 statefulsets]$ kubectl replace -f stateful-nginx-without-pvc.yaml 
service/nginx-stateful-service replaced
statefulset.apps/nginx-statefulset replaced
[gateman@manjaro-x13 statefulsets]$ kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
nginx-statefulset-0	nginx:1.25.4
nginx-statefulset-1	nginx:1.26.1
nginx-statefulset-2	nginx:1.26.1
nginx-statefulset-3	nginx:1.26.1
nginx-statefulset-4	nginx:1.26.1

这时只有pod0 还是旧版本

如何 把pod0 也同步?
方法1是用上面的方法重新更新partition 的值为0

方法2使用 kubectl patch 修改
kubectl patch statefulset nginx-statefulset --type=‘json’ -p=‘[{“op”: “replace”, “path”: “/spec/updateStrategy/rollingUpdate/partition”, “value”: 0}]’

[gateman@manjaro-x13 statefulsets]$ kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
nginx-statefulset-0	nginx:1.26.1
nginx-statefulset-1	nginx:1.26.1
nginx-statefulset-2	nginx:1.26.1
nginx-statefulset-3	nginx:1.26.1
nginx-statefulset-4	nginx:1.26.1




Deployment 的灰度发布

如果是无状态service 的deployment , 可以用这种方法灰度发布吗?
不行
因为 deployment 的pods 的后续不是1个index 数字, 无序的, 所以无法去比较 pod 的index 和 partition的值

强行写上yaml 就会有如下错误:

[gateman@manjaro-x13 bq-api-service]$ kubectl apply -f bq-api-service-test.yaml 
error: error validating "bq-api-service-test.yaml": error validating data: ValidationError(Deployment.spec.strategy.rollingUpdate): unknown field "partition" in io.k8s.api.apps.v1.RollingUpdateDeployment; if you choose to ignore these errors, turn validation off with --validate=false

但是灰度发布只是1个思想, 实现的方法有很多种
deployment的灰度发布在k8s 是可行的, 例如简单粗暴地用多个deployment 去cover 不同的instance. 具体方法不在此讨论

Kubernetes Ingress-Nginx是一个用于管理Kubernetes集群中的Ingress资源的工具。它支持使用Ingress Annotations来实现不同场景下的灰度发布和测试。其中,Nginx Annotations支持基于Cookie的切分流量来实现灰度发布。具体实现方式是通过判断用户请求中的Cookie是否存在灰度标识Cookie来确定是否为灰度用户,从而决定是否返回灰度版本的服务。 在配置中,可以使用以下Annotations来实现灰度发布: - `nginx.ingress.kubernetes.io/canary`:可选值为true/false,表示是否开启灰度功能。 - `nginx.ingress.kubernetes.io/canary-by-cookie`:灰度发布Cookie的键。当键的值等于"always"时,灰度触发生效;其他值则不会走灰度环境。 例如,如果请求的Cookie中包含名为"vip_user"的键,并且值为"always",则会生效灰度配置,访问灰度版本的服务。 要实际执行灰度发布配置,可以使用以下命令: ``` kubectl apply -f ingress-gray.yaml ``` 如果想查看服务并获取Ingress的外部端口,可以使用以下命令: ``` kubectl -n ingress-nginx get service ``` 这将显示Ingress-Nginx控制器的服务信息,包括集群IP、外部IP和端口等。 #### 引用[.reference_title] - *1* [【云原生 | Kubernetes 实战】20、K8s Ingress 实现业务灰度发布](https://blog.csdn.net/weixin_46560589/article/details/128505651)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【Kubernetes】第十篇 - 灰度发布的介绍与实现](https://blog.csdn.net/ABAP_Brave/article/details/129220116)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值