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 。
总结
- 应用状态一次性全部更新。
- 停机时间取决于应用程序的关闭和启动消耗的时间。
- 部署回滚需要较长时间。
滚动更新(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 将也都会被相继删掉。
总结
- 应用状态更新缓慢(以新版本增加,老版本退出的规律更新)。
- 没有停机时间。
- 无法控制流量是在新版本中,还是老版本。
- 部署回滚 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 的了。
总结
- 应用状态一次性更新,版本切换很快。
- 没有停机时间。
- 部署/回滚流量切换时间间隔小。
- 需要两倍的资源。
- 在发布到生产之前,应该对整个应用进行适当的测试
金丝雀(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 副本,从而达到控制流量分配。
总结
- 应用状态更新缓慢(新老版本流量占比)。
- 没有停机时间。
- 部署/回滚流量切换时间间隔小。
- 发布较慢。
- 有一定的流量分配。
- 部分用户获取新版本。
- 方便错误和性能监控。