K8S灰度发布

01 常见的部署方案

  • 滚动更新

    服务不会停止,但是整个pod会有新旧并存的情况。
    
  • 重新创建

    先停止旧的pod,然后再创建新的pod,这个过程服务是会间断的。
    
  • 蓝绿

    **无需停机,风险较小** 
    01-部署v1的应用(一开始的状态) 所有外部请求的流量都打到这个版本上. 
    02-部署版本2的应用 版本2的代码与版本1不同(新功能、Bug修复等). 
    03-将流量从版本1切换到版本2。 
    04-如版本2测试正常,就删除版本1正在使用的资源(例如实例),从此正式用版本2。
    
  • 金丝雀

1.1 滚动更新

maxSurge:指定升级期间存在的总Pod对象数量最多可超出期望值的个数,其值可以是0或正整数,也可以是一个期望值的百分比;例如,如果期望值为3,当前的属性值为1,则表示Pod对象的总数不能超过4个。

maxUnavailable:升级期间正常可用的Pod副本数(包括新旧版本)最多不能低于期望值的个数,其值可以是0或正整数,也可以是期望值的百分比;默认值为1,该值意味着如果期望值是3,则升级期间至少要有两个Pod对象处于正常提供服务的状态。

K8S灰度发布_第1张图片

#rollingupdate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rollingupdate
spec:
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  selector:
    matchLabels:
      app: rollingupdate
  replicas: 4
  template:
    metadata:
      labels:
        app: rollingupdate
    spec:
      containers:
      - name: rollingupdate
        image: registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
        ports:
        - containerPort: 8080  
---
apiVersion: v1
kind: Service
metadata:
  name: rollingupdate
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: rollingupdate
  type: ClusterIP
#执行
kubectl apply -f rollingupdate.yaml 
kubectl get pods 
kubectl get svc 
curl cluster-ip/dockerfile

修改rollingupdate.yaml文件,将镜像修改成v2.0

# 在w1上,不断地访问观察输出 
while sleep 0.2;do curl cluster-ip/dockerfile;echo "";done 
# 在w2上,监控
pod kubectl get pods -w 
# 使得更改生效 
kubectl apply -f rollingupdate.yaml 
kubectl get pods

conclusion :发现新旧pod是会共存的,并且可以访问测试看一下

kubectl get pods -w 
kubectl get svc

可以发现,新老版本的确会共存

1.2 重新创建

recreate.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: recreate
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: recreate
  replicas: 4
  template:
    metadata:
      labels:
        app: recreate
    spec:
      containers:
      - name: recreate
        image: registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
        ports:
        - containerPort: 8080
        livenessProbe:
          tcpSocket:
            port: 8080

修改recreate.yaml文件

kubectl apply -f recreate.yaml 
kubectl get pods

conclusion :发现pod是先停止,然后再创建新的

#停止
NAME READY STATUS RESTARTS AGE 
recreate-655d4868d8-5dqcz 0/1 Terminating 0 2m31s 
recreate-655d4868d8-sb688 0/1 Terminating 0
#创建
NAME READY STATUS RESTARTS AGE 
recreate-6f74f4686d-4xkgl 1/1 Running 0 13s 
recreate-6f74f4686d-blrt7 1/1 Running 0 13s

Have a try

kubectl rollout pause deploy rollingupdate 
kubectl rollout resume deploy rollingupdate 
kubectl rollout undo deploy rollingupdate 
# 回到上一个版本

1.3 蓝绿

bluegreen.yaml

#deploy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue
spec:
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  selector:
    matchLabels:
      app: bluegreen
  replicas: 4
  template:
    metadata:
      labels:
        app: bluegreen
        version: v1.0
    spec:
      containers:
      - name: bluegreen
        image: registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
        ports:
        - containerPort: 8080
        
#执行
kubectl apply -f bluegreen.yaml 
kubectl get pods

bluegreen-service.yaml

#service
apiVersion: v1
kind: Service
metadata:
  name: bluegreen
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: bluegreen
    version: v1.0
  type: ClusterIP


#执行service.yaml
kubectl apply -f bluegreen-service.yaml 
kubectl get svc 
# 在w1上不断访问观察 
while sleep 0.3;do curl cluster-ip/dockerfile;echo "";done

修改bluegreen.yaml

#修改三处
01-deployment-name:blue ---> green 
02-image:v1.0---> v2.0 
03-version:v1.0 ---> v2.0

#重新执行
kubectl apply -f bluegreen.yaml 
kubectl get pods 
# 同时观察刚才访问的地址有没有变化 可以发现,两个版本就共存了,并且之前访问的地址没有变化

修改bluegreen-service.yaml

# 也就是把流量切到2.0的版本中 
selector: 
	app: bluegreen 
	version: v2.0

#修改完执行
kubectl apply -f bluegreen-service.yaml 
kubectl get svc 
# 同时观察刚才访问的地址有没有变化 发现流量已经完全切到了v2.0的版本上

好事之者:istio、spinnaker

1.4 金丝雀

selector: 
	app: bluegreen 
	version: v2.0 
# 把version删除掉,只是根据bluegreen进行选择

kubectl apply -f bluegreen-service.yaml 
# 同时观察刚才访问的地址有没有变化,istio中就更方便咯 
此时新旧版本能够同时被访问到,AB测试,新功能部署少一些的实例

02灰色发布实现方式

2.1、ambassador

基于ambassador实现K8S灰度发布

2.2、ingress-nginx

推荐:K8S基于ingress-nginx实现灰度发布

Ingress-Nginx 是一个K8S ingress工具,支持配置 Ingress Annotations 来实现不同场景下的灰度发布和测试。 Nginx Annotations 支持以下 4 种 Canary 规则:

  • nginx.ingress.kubernetes.io/canary-by-header:基于 Request Header 的流量切分,适用于灰度发布以及 A/B 测试。当 Request Header 设置为 always时,请求将会被一直发送到 Canary 版本;当 Request Header 设置为 never时,请求不会被发送到 Canary 入口;对于任何其他 Header 值,将忽略 Header,并通过优先级将请求与其他金丝雀规则进行优先级的比较。
  • nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务。当 Request Header 设置为此值时,它将被路由到 Canary 入口。该规则允许用户自定义 Request Header 的值,必须与上一个 annotation (即:canary-by-header)一起使用。
  • nginx.ingress.kubernetes.io/canary-weight:基于服务权重的流量切分,适用于蓝绿部署,权重范围 0 - 100 按百分比将请求路由到 Canary Ingress 中指定的服务。权重为 0 意味着该金丝雀规则不会向 Canary 入口的服务发送任何请求。权重为 100 意味着所有请求都将被发送到 Canary 入口。
  • nginx.ingress.kubernetes.io/canary-by-cookie:基于 Cookie 的流量切分,适用于灰度发布与 A/B 测试。用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务的cookie。当 cookie 值设置为 always时,它将被路由到 Canary 入口;当 cookie 值设置为 never时,请求不会被发送到 Canary 入口;对于任何其他值,将忽略 cookie 并将请求与其他金丝雀规则进行优先级的比较。

注意:金丝雀规则按优先顺序进行如下排序:

canary-by-header - > canary-by-cookie - > canary-weight

我们可以把以上的四个 annotation 规则可以总体划分为以下两类:

  • 基于权重的 Canary 规则

K8S灰度发布_第2张图片

  • 基于用户请求的 Canary 规则
    K8S灰度发布_第3张图片

正常服务的:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: springboot-rest-demo
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: springboot-rest.jadepeng.com
    http:
      paths:
      - backend:
          serviceName: springboot-rest-demo
          servicePort: 80

canary 的:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: springboot-rest-demo-gray
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "canary"
	nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
  rules:
  - host: springboot-rest.jadepeng.com
    http:
      paths:
      - backend:
          serviceName: springboot-rest-demo-gray
          servicePort: 80

使用Nginx实现灰度发布

nginx+lua+redis 灰度发布实现方案)

2.3、gateway+nacos

Nacos+gateway实现灰度发布

SpringCloudGateway实现灰度发布,结合nacos支持不同服务配置不同灰度版本及灰度权重(概率)

2.4、istio

k8s+istio:流量控制之灰度发布

2.5、spinnaker

k8s容器灰度发布实践(基于spinnaker)【附源码】

你可能感兴趣的:(#,K8S,云原生,docker,kubernetes,运维)