十一、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  <none>        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   <none>        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   <none>        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文件时,可以将副本数改的少点就可以了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354