Lework Study hard, improve every day.

k8s 应用发布策略

2021-08-08
lework
本文 3780 字,阅读全文约需 11 分钟

k8s 应用的主要发布策略

重建(recreate)

停止旧版本部署新版本

主要配置

---
kind: Service
apiVersion: v1
metadata:
  name: test-app
  labels:
    app: test-app
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:              # 匹配 pod 的标签
    app: test-app       
    
---
Kind: Deployment
apiVersion: apps/v1
metadata:
  name: test-app
spec:
  replicas: 3
  strategy:
    type: Recreate       # 重建策略
  selector:
    matchLabels:         # 匹配 pod 的标签
      app: test-app      
  template:
    metadata:
      labels:            # pod 标签
        app: test-app
        version: v1.0.0  # 版本标签

操作流程

# 1. 部署 v1.0.0 版本应用
kubectl apply -f app-v1.0.0.yaml

# 2. 观察 pod 情况
kubectl get pods --show-labels -l app=test-app 

# 3. 部署 v2.0.0 版本应用
kubectl apply -f app-v2.0.0.yaml # version 变动

# 4. 观察 pod 情况
kubectl get pods --show-labels -l app=test-app

# 这时发现之前的 pod 全部处于 Terminating 状态, 待 v1.0.0 版本的pod删除完,才会新建 v2.0.0 的 pod 。

总结

  1. 应用状态一次性全部更新。
  2. 停机时间取决于应用程序的关闭和启动消耗的时间。
  3. 部署回滚需要较长时间。

滚动更新(rolling-update)

一个接一个地以滚动更新方式发布新版本

主要配置

---
kind: Service
apiVersion: v1
metadata:
  name: test-app
  labels:
    app: test-app
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:             # 匹配 pod 的标签
    app: test-app        
    
---
Kind: Deployment
apiVersion: apps/v1
metadata:
  name: test-app
spec:
  replicas: 3
  strategy:
    type: RollingUpdate  # 滚动更新
    rollingUpdate:
      maxSurge: 1        # 一次可以添加多少个Pod
      maxUnavailable: 1  # 滚动更新期间最大多少个Pod不可用
  selector:
    matchLabels:         # 匹配 pod 的标签
      app: test-app      
  template:
    metadata:
      labels:            # pod 标签
        app: test-app
        version: v1.0.0  # 版本标签

操作流程

# 1. 部署 v1.0.0 版本应用
kubectl apply -f app-v1.0.0.yaml

# 2. 观察 pod 情况
kubectl get pods --show-labels -l app=test-app 

# 3. 部署 v2.0.0 版本应用
kubectl apply -f app-v2.0.0.yaml # version 变动

# 4. 观察 pod 情况
kubectl get pods --show-labels -l app=test-app

# 这时发现 v1.0.0 版本的 pod 有一个处于 Terminating 状态, 其他的 pod 都是 Running 。
# 有 2 个 v2.0.0 的 POD 被创建(maxSurge 为1,在同一时间内可允许最多4个pod 为 Running,但是当前只有2个pod 为 Running)。
# 待 v2.0.0 的 POD 都为 READY 时,v1.0.0 版本的 pod 将也都会被相继删掉。

总结

  1. 应用状态更新缓慢(以新版本增加,老版本退出的规律更新)。
  2. 没有停机时间。
  3. 无法控制流量是在新版本中,还是老版本。
  4. 部署回滚 rollout/rollback 需要一定时间。

蓝绿(blue/green)

新版本与旧版本一起存在,然后切换流量

主要配置文件

---
kind: Service
apiVersion: v1
metadata:
  name: test-app
  labels:
    app: test-app
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:              # 匹配 pod 的标签
    app: test-app        
    version: v1.0.0      # 版本标签      
    
---
Kind: Deployment
apiVersion: apps/v1
metadata:
  name: test-app
spec:
  replicas: 3
  strategy:
    type: RollingUpdate  # 滚动更新
    rollingUpdate:
      maxSurge: 2        # 一次可以添加多少个Pod
      maxUnavailable: 1  # 滚动更新期间最大多少个Pod不可用
  selector:
    matchLabels:         # 匹配 pod 的标签
      app: test-app      
      version: v1.0.0    # 版本标签     
  template:
    metadata:
      labels:            # pod 标签
        app: test-app
        version: v1.0.0  # 版本标签

操作流程

# 1. 部署 v1.0.0 版本应用
kubectl apply -f app-v1.0.0.yaml

# 2. 观察 pod 情况
kubectl get pods --show-labels -l app=test-app 

# 3. 部署 v2.0.0 版本应用
kubectl apply -f app-v2.0.0.yaml # version 变动, name 也变动。

# 4. 观察 pod 情况
kubectl get pods --show-labels -l app=test-app

# 这时发现 v1.0.0 和 v2.0.0 版本的 pod 状态 都是 Running 。

# 5. 切换流量
kubectl patch service test-app -p '{"spec":{"selector":{"version":"v2.0.0"}}}'

# 这时再去访问流量,都是 v2.0.0 的了。

总结

  1. 应用状态一次性更新,版本切换很快。
  2. 没有停机时间。
  3. 部署/回滚流量切换时间间隔小。
  4. 需要两倍的资源。
  5. 在发布到生产之前,应该对整个应用进行适当的测试

金丝雀(canary)

将新版本面向一部分用户发布,然后继续全量发布。

主要配置文件

---
kind: Service
apiVersion: v1
metadata:
  name: test-app
  labels:
    app: test-app
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:              # 匹配 pod 的标签
    app: test-app
    
---
Kind: Deployment
apiVersion: apps/v1
metadata:
  name: test-app
spec:
  replicas: 3
  strategy:
    type: RollingUpdate  # 滚动更新
    rollingUpdate:
      maxSurge: 2        # 一次可以添加多少个Pod
      maxUnavailable: 1  # 滚动更新期间最大多少个Pod不可用
  selector:
    matchLabels:         # 匹配 pod 的标签
      app: test-app      
      version: v1.0.0    # 版本标签     
  template:
    metadata:
      labels:            # pod 标签
        app: test-app
        version: v1.0.0  # 版本标签

操作流程

# 1. 部署 v1.0.0 版本应用
kubectl apply -f app-v1.0.0.yaml

# 2. 观察 pod 情况
kubectl get pods --show-labels -l app=test-app 
kubectl describe svc test-app

# 3. 部署 v2.0.0 版本应用
kubectl apply -f app-v2.0.0.yaml # version 变动, name 也变动。

# 4. 观察 pod 情况
kubectl get pods --show-labels -l 'app in (test-app, test-app2)'
kubectl describe svc test-app

# 这时发现 v1.0.0 和 v2.0.0 版本的 pod 状态 都是 Running 。
# 且 service 下的 pod 有 6个, 两个版本的流量是 1:1 。

# 5. 切换流量
kubectl scale --replicas=2 deploy test-app
# 这是,缩小 test-app(v1.0.0) 版本的 pod 副本, 两个版本的流量是 4:6 了。

# 6. 在缩小v1流量
kubectl scale --replicas=1 deploy test-app
# 这是,缩小 test-app(v1.0.0) 版本的 pod 副本, 两个版本的流量是 2.5:7.5 了。

# 通过这种方式,来调整 v1.0.0 和 v2.0.0 版本的 pod 副本,从而达到控制流量分配。

总结

  1. 应用状态更新缓慢(新老版本流量占比)。
  2. 没有停机时间。
  3. 部署/回滚流量切换时间间隔小。
  4. 发布较慢。
  5. 有一定的流量分配。
  6. 部分用户获取新版本。
  7. 方便错误和性能监控。
原文地址 https://lework.github.io/2021/08/08/k8s-deploy/

Comments

Content