十一、Kubernetes 进阶之部署方案篇

1、常用部署方案

1.1 滚动更新

滚动更新是一种自动化程度较高的发布方式,用户体验比较平滑,是目前成熟型技术组织所采用的主流发布方式。

优势在于服务不会停止,但是pod会有新旧版本并存的情况。

  • 准备YAML文件

    • maxSurge 参数详解
      • 该值可以是绝对数(例如,5)或所需 Pods 的百分比(例如,10%)。如果 MaxUnavailable 0,则值不能为 0。默认值为 25%。
      • 定义除了 replicas 数量之外,在一次滚动更新过程中,Deployment还可以创建多少Pod
      • 若设置为30%,则是确保更新期间任何时间运行的 Pods 总数最多为所需 Pods 总数的130%。
    • maxUnavailable 参数详解
      • 定义在一次滚动更新过程中,Deployment最多可以删除多少Pod。如果maxSurge 为 0,则该值不能为 0。默认值为 25%。
      • 若设置为30%,确保可用的 Pods 总数在更新期间,任何时候都至少有 70% 所需的 Pods。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: rollingupdate
    spec:
      strategy:                   # 策略
        rollingUpdate:            
          maxSurge: 1         # 滚动升级时会先启动1个pod
          maxUnavailable: 2       # 滚动升级时允许的最多不可用的 pod 个数
        type: RollingUpdate       # 滚动更新升级方式
      selector:
        matchLabels:
          app: rollingupdate
      replicas: 4
      template:
        metadata:
          labels:
            app: rollingupdate
        spec:
          containers:
          - name: rollingupdate
            image: registry.cn-hangzhou.aliyuncs.com/zhao_yang/springboot-demo-k8s:v1.0   # 先使用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
    
  • 创建资源

    [root@master-kubeadm-k8s project_deploy]# kubectl apply -f rollingupdate.yaml
    deployment.apps/rollingupdate created
    service/rollingupdate created
    
  • 查看资源

    [root@master-kubeadm-k8s project_deploy]# kubectl get pods
    NAME                             READY   STATUS      RESTARTS   AGE
    rollingupdate-67cd875cd6-fdxj2   1/1     Running     0          13s
    rollingupdate-67cd875cd6-r8z7l   1/1     Running     0          13s
    rollingupdate-67cd875cd6-vwq6b   1/1     Running     0          13s
    rollingupdate-67cd875cd6-zdfvr   1/1     Running     0          13s
    
    [root@master-kubeadm-k8s project_deploy]# kubectl get svc
    NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    rollingupdate   ClusterIP   10.102.255.72          80/TCP    61s
    
  • 测试版本

    [root@master-kubeadm-k8s project_deploy]# curl 10.102.255.72/k8s
    hello K8S
    
  • 升级镜像

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: rollingupdate
    spec:
      strategy:
        rollingUpdate:            
          maxSurge: 1
          maxUnavailable: 2
        type: RollingUpdate
      selector:
        matchLabels:
          app: rollingupdate
      replicas: 4
      template:
        metadata:
          labels:
            app: rollingupdate
        spec:
          containers:
          - name: rollingupdate
            image: registry.cn-hangzhou.aliyuncs.com/zhao_yang/springboot-demo-k8s:v2.0   # 使用v2.0版本
            ports:
            - containerPort: 8080  
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: rollingupdate
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: rollingupdate
      type: ClusterIP
    
  • 滚动更新

    [root@master-kubeadm-k8s project_deploy]# kubectl apply -f rollingupdate.yaml
    deployment.apps/rollingupdate configured
    service/rollingupdate unchanged
    
  • 观察Pod创建过程

    image.png
  • 再次测试

    # 现在访问的就是新版本的了
    [root@master-kubeadm-k8s project_deploy]# curl 10.102.255.72/k8s
    hello K8S v2.0
    

1.2 重新创建

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

  • 准备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/zhao_yang/springboot-demo-k8s:v1.0
            ports:
            - containerPort: 8080
            livenessProbe:
              tcpSocket:
                port: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: recreate
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: recreate
      type: ClusterIP
    
    • 创建资源

      [root@master-kubeadm-k8s project_deploy]# kubectl apply -f recreate.yaml
      deployment.apps/recreate created
      service/recreate created
      
    • 查看资源

      [root@master-kubeadm-k8s project_deploy]# kubectl get pods
      NAME                        READY   STATUS    RESTARTS   AGE
      recreate-7b7dbf54cb-6zn2s   1/1     Running   2          118s
      recreate-7b7dbf54cb-86n84   1/1     Running   2          118s
      recreate-7b7dbf54cb-d4sw4   1/1     Running   1          118s
      recreate-7b7dbf54cb-t684d   1/1     Running   1          118s
      
      [root@master-kubeadm-k8s project_deploy]# kubectl get svc
      NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
      recreate     ClusterIP   10.107.31.94           80/TCP    2m2s
      
    • 测试版本

      [root@master-kubeadm-k8s project_deploy]# curl 10.107.31.94/k8s
      hello K8S
      
    • 升级镜像

      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/zhao_yang/springboot-demo-k8s:v2.0     # 升级2.0版本
              ports:
              - containerPort: 8080
              livenessProbe:
                tcpSocket:
                  port: 8080
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: recreate
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 8080
        selector:
          app: recreate
        type: ClusterIP
      
    • 重新创建

      [root@master-kubeadm-k8s project_deploy]# kubectl apply -f recreate.yaml
      deployment.apps/recreate configured
      service/recreate unchanged
      
    • 观察Pod创建过程

      image.png
  • 再次测试

    # 升级成功
    [root@master-kubeadm-k8s project_deploy]# curl 10.107.31.94/k8s
    hello K8S v2.0
    

1.3 蓝绿部署

V1 版本称为蓝组,V2 版本称为绿组,发布时会一次性将流量从蓝组直接切换到绿组。

蓝绿部署其实就是创建2组Pod同时运行,通过切换Service绑定的标签进行版本切换。无需停机,风险较小。

1.3.1 实际部署流程

  • 部署v1的应用(一开始的状态)
    • 所有外部请求的流量都打到这个版本上
  • 部署v2的应用
    • v2的代码与v1不同(新功能、Bug修复等)
  • 将流量从v1切换到v2
  • 如v2测试正常,就删除v1正在使用的资源(例如实例),从此正式用v2
    • 一般不会直接删除v1,因为无法保证v2会在什么时候出现问题
    • 当版本升级到v3时,就可以删除v1

1.3.2 开始部署

  • 准备YAML文件

    service的yaml要与Deployment的yaml分开,这样在升级时才不会修改service-ip

    • bluegreen.yaml

      #deploy
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: blue                # 这里的 blue 只是方便观察,实际没意义
      spec:
        strategy:         
          rollingUpdate:          # 同样是使用滚动更新的方式
            maxSurge: 1
            maxUnavailable: 2
          type: RollingUpdate
        selector:
          matchLabels:
            app: bluegreen
        replicas: 4
        template:
          metadata:
            labels:               # 关键点在于这里, 配置2个标签
              app: bluegreen      # 升级版本时这里不
              version: v1.0       # 升级版本时这里更新,Service选择标签也更新,就可以动态的切换到新版本
          spec:
            containers:
            - name: bluegreen
              image: registry.cn-hangzhou.aliyuncs.com/zhao_yang/springboot-demo-k8s:v1.0
              ports:
              - containerPort: 8080
      
    • bluegreen-service.yaml

      apiVersion: v1
      kind: Service
      metadata:
        name: bluegreen-service
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 8080
        selector:
          app: bluegreen
          version: v1.0       # 当版本升级时,修改版本即可动态升级版本,这样service-IP不会变
        type: ClusterIP
      
  • 创建资源

    [root@master-kubeadm-k8s project_deploy]# kubectl apply -f bluegreen.yaml
    deployment.apps/blue created
    
    [root@master-kubeadm-k8s project_deploy]# kubectl apply -f bluegreen-service.yaml
    service/bluegreen-service created
    
  • 查看资源

    [root@master-kubeadm-k8s project_deploy]# kubectl get pods
    NAME                    READY   STATUS    RESTARTS   AGE
    blue-8675d5c885-75shf   1/1     Running   0          2m43s
    blue-8675d5c885-j2qmm   1/1     Running   0          2m44s
    blue-8675d5c885-m9z2s   1/1     Running   0          2m44s
    blue-8675d5c885-x6ht4   1/1     Running   0          2m44s
    
    [root@master-kubeadm-k8s project_deploy]# kubectl get svc
    NAME                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
    bluegreen-service   ClusterIP   10.111.118.191           80/TCP    2m44s
    
  • 测试版本

    [root@master-kubeadm-k8s project_deploy]# curl 10.111.118.191/k8s
    hello K8S
    
  • 升级镜像

    • bluegreen.yaml

      #deploy
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: green               # 修改名称为 green 只是方便观察,实际没意义
      spec:
        strategy:         
          rollingUpdate:
            maxSurge: 1
            maxUnavailable: 2
          type: RollingUpdate
        selector:
          matchLabels:
            app: bluegreen
        replicas: 4
        template:
          metadata:
            labels:
              app: bluegreen
              version: v2.0       # 升级版本
          spec:
            containers:
            - name: bluegreen
              image: registry.cn-hangzhou.aliyuncs.com/zhao_yang/springboot-demo-k8s:v2.0             # 升级镜像版本
              ports:
              - containerPort: 8080
      
    • bluegreen-service.yaml

      apiVersion: v1
      kind: Service
      metadata:
        name: bluegreen-service
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 8080
        selector:
          app: bluegreen
          version: v2.0       # 选择新版本的Pod
        type: ClusterIP
      
  • 重新创建

    [root@master-kubeadm-k8s project_deploy]# kubectl apply -f bluegreen.yaml
    deployment.apps/green created
    
    [root@master-kubeadm-k8s project_deploy]# kubectl apply -f bluegreen-service.yaml
    service/bluegreen-service configured
    
  • 观察Pod

    image.png
  • 再次测试

    # 切换成功
    [root@master-kubeadm-k8s project_deploy]# curl 10.111.118.191/k8s
    hello K8S v2.0
    

如果发现这个版本有问题,那么直接修改service中的标签选择器为 v1.0 版本即可

1.4 金丝雀部署

金丝雀部署也叫AB测试(国内称灰度发布),是指会有2个版本的代码存在,目的是先让一部分用户来测试新功能,若新功能没问题,再全部升级为新版本的功能。

这里要使用的话可以直接使用上面的YAML文件,只需修改bluegreen-service.yaml文件中的标签选择器即可!

  • 修改service的YAML文件

    apiVersion: v1
    kind: Service
    metadata:
      name: bluegreen-service
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: bluegreen
        # version: v2.0  # 取消版本选择,让2个版本的Pod都运用起来
      type: ClusterIP
    
  • 更新资源

    [root@master-kubeadm-k8s project_deploy]# kubectl apply -f bluegreen-service.yaml
    service/bluegreen-service configured
    
  • 测试

    这样就达到了AB测试的功能,两个版本共存

    [root@master-kubeadm-k8s project_deploy]# while sleep 0.5; do curl 10.111.118.191/k8s; echo "";done
    hello K8S
    hello K8S
    hello K8S v2.0
    hello K8S
    hello K8S v2.0
    hello K8S
    hello K8S
    hello K8S v2.0
    hello K8S
    hello K8S
    hello K8S
    hello K8S v2.0
    hello K8S v2.0
    hello K8S v2.0
    hello K8S v2.0
    hello K8S v2.0
    
    # ...
    

如果想要让更少部分用户体验新版的功能,那修改新版本的YAML文件时,可以将副本数改的少点就可以了

你可能感兴趣的:(十一、Kubernetes 进阶之部署方案篇)