K8S 企业容器云03 - 部署策略
版本发布的多种部署策略
常见部署策略比较
Canary Deployment
金丝雀部署是一种分阶段增量部署:
-
新增小规模新版本环境承担一小部分用户(金丝雀)流量;
-
经过测试观察,若新版本环境功能正常稳定,将新版本部署完全展开并删除旧环境;
-
若不符合预期,则删除小集群,将影响范围控制在少量用户群;
有时会用单独一个集群作为金丝雀分析基准环境(canary analysis下图蓝色阴影区)
This technique is mostly used when the tests are lacking or not reliable or if there is little confidence about the stability of the new release on the platform.
动态示意图
新版本集群承担少量流量,逐渐展开
K8S Native
通过 v1 & v2 两个版本模拟实验
# vim app-v1.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app
labels:
app: my-app
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: http
selector:
app: my-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-v1
labels:
app: my-app
spec:
replicas: 10
selector:
matchLabels:
app: my-app
version: v1.0.0
template:
metadata:
labels:
app: my-app
version: v1.0.0
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9101"
spec:
containers:
- name: my-app
image: containersol/k8s-deployment-strategies
ports:
- name: http
containerPort: 8080
- name: probe
containerPort: 8086
env:
- name: VERSION
value: v1.0.0
livenessProbe:
httpGet:
path: /live
port: probe
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: probe
periodSeconds: 5
创建 10 个 v1 副本提供服务
# kubectl apply -f app-v1.yaml
# watch kubectl get pod -l app=my-app
Every 2.0s: kubectl get pod -l app=my-app
k01: Sun Sep 29 15:38:12 2019
NAME READY STATUS RESTARTS AGE
my-app-v1-5b4755fccf-2qqwd 1/1 Running 0 73s
my-app-v1-5b4755fccf-5hqvj 1/1 Running 0 73s
my-app-v1-5b4755fccf-g6r6n 1/1 Running 0 73s
my-app-v1-5b4755fccf-gqpjc 1/1 Running 0 73s
my-app-v1-5b4755fccf-hv69c 1/1 Running 0 73s
my-app-v1-5b4755fccf-kv24m 1/1 Running 0 73s
my-app-v1-5b4755fccf-l9n4j 1/1 Running 0 73s
my-app-v1-5b4755fccf-p2zp8 1/1 Running 0 73s
my-app-v1-5b4755fccf-px747 1/1 Running 0 73s
my-app-v1-5b4755fccf-qdwv9 1/1 Running 0 73s
# kubectl get service -l app=my-app
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-app NodePort 10.110.141.72 <none> 80:31541/TCP 2m9s
持续访问业务,查看响应节点
# while sleep 1; do curl 10.110.141.72; done
Host: my-app-v1-5b4755fccf-g6r6n, Version: v1.0.0
Host: my-app-v1-5b4755fccf-p2zp8, Version: v1.0.0
Host: my-app-v1-5b4755fccf-l9n4j, Version: v1.0.0
Host: my-app-v1-5b4755fccf-kv24m, Version: v1.0.0
Host: my-app-v1-5b4755fccf-hv69c, Version: v1.0.0
Host: my-app-v1-5b4755fccf-px747, Version: v1.0.0
Host: my-app-v1-5b4755fccf-px747, Version: v1.0.0
Host: my-app-v1-5b4755fccf-2qqwd, Version: v1.0.0
Host: my-app-v1-5b4755fccf-kv24m, Version: v1.0.0
...
再写一个 v2 版本
# vim app-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-v2
labels:
app: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
version: v2.0.0
template:
metadata:
labels:
app: my-app
version: v2.0.0
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9101"
spec:
containers:
- name: my-app
image: containersol/k8s-deployment-strategies
ports:
- name: http
containerPort: 8080
- name: probe
containerPort: 8086
env:
- name: VERSION
value: v2.0.0
livenessProbe:
httpGet:
path: /live
port: probe
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: probe
periodSeconds: 5
# kubectl apply -f app-v2.yaml
新增一个 v2 副本
# watch kubectl get pod -l app=my-app
Every 2.0s: kubectl get pod -l app=my-app
k01: Sun Sep 29 15:55:39 2019
NAME READY STATUS RESTARTS AGE
my-app-v1-5b4755fccf-2qqwd 1/1 Running 0 18m
my-app-v1-5b4755fccf-5hqvj 1/1 Running 0 18m
my-app-v1-5b4755fccf-g6r6n 1/1 Running 0 18m
my-app-v1-5b4755fccf-gqpjc 1/1 Running 0 18m
my-app-v1-5b4755fccf-hv69c 1/1 Running 0 18m
my-app-v1-5b4755fccf-kv24m 1/1 Running 0 18m
my-app-v1-5b4755fccf-l9n4j 1/1 Running 0 18m
my-app-v1-5b4755fccf-p2zp8 1/1 Running 0 18m
my-app-v1-5b4755fccf-px747 1/1 Running 0 18m
my-app-v1-5b4755fccf-qdwv9 1/1 Running 0 18m
my-app-v2-759bffd84f-fs79p 1/1 Running 0 17s
返回少量 v2 响应
# while sleep 1; do curl 10.110.141.72; done
Host: my-app-v1-5b4755fccf-p2zp8, Version: v1.0.0
Host: my-app-v1-5b4755fccf-qdwv9, Version: v1.0.0
Host: my-app-v1-5b4755fccf-2qqwd, Version: v1.0.0
Host: my-app-v1-5b4755fccf-px747, Version: v1.0.0
Host: my-app-v1-5b4755fccf-hv69c, Version: v1.0.0
Host: my-app-v1-5b4755fccf-g6r6n, Version: v1.0.0
Host: my-app-v2-759bffd84f-fs79p, Version: v2.0.0
Host: my-app-v1-5b4755fccf-qdwv9, Version: v1.0.0
Host: my-app-v2-759bffd84f-fs79p, Version: v2.0.0
Host: my-app-v1-5b4755fccf-gqpjc, Version: v1.0.0
Host: my-app-v1-5b4755fccf-kv24m, Version: v1.0.0
Host: my-app-v1-5b4755fccf-p2zp8, Version: v1.0.0
Host: my-app-v1-5b4755fccf-hv69c, Version: v1.0.0
Host: my-app-v1-5b4755fccf-l9n4j, Version: v1.0.0
Host: my-app-v1-5b4755fccf-p2zp8, Version: v1.0.0
...
经过测试和等待观察,若 v2 版本功能正常稳定
将 v2 副本扩展到 10 个
# kubectl scale --replicas=10 deploy my-app-v2
目前环境中 v1 & v2 多副本并存
# watch kubectl get pod -l app=my-app
Every 2.0s: kubectl get pod -l app=my-app
k01: Sun Sep 29 16:02:19 2019
NAME READY STATUS RESTARTS AGE
my-app-v1-5b4755fccf-2qqwd 1/1 Running 0 25m
my-app-v1-5b4755fccf-5hqvj 1/1 Running 0 25m
my-app-v1-5b4755fccf-g6r6n 1/1 Running 0 25m
my-app-v1-5b4755fccf-gqpjc 1/1 Running 0 25m
my-app-v1-5b4755fccf-hv69c 1/1 Running 0 25m
my-app-v1-5b4755fccf-kv24m 1/1 Running 0 25m
my-app-v1-5b4755fccf-l9n4j 1/1 Running 0 25m
my-app-v1-5b4755fccf-p2zp8 1/1 Running 0 25m
my-app-v1-5b4755fccf-px747 1/1 Running 0 25m
my-app-v1-5b4755fccf-qdwv9 1/1 Running 0 25m
my-app-v2-759bffd84f-24rhg 1/1 Running 0 82s
my-app-v2-759bffd84f-8rkbl 1/1 Running 0 81s
my-app-v2-759bffd84f-97wxf 1/1 Running 0 81s
my-app-v2-759bffd84f-fs79p 1/1 Running 0 6m57s
my-app-v2-759bffd84f-jt4pk 1/1 Running 0 81s
my-app-v2-759bffd84f-lbsvx 1/1 Running 0 81s
my-app-v2-759bffd84f-ncmr5 1/1 Running 0 81s
my-app-v2-759bffd84f-qrxnv 1/1 Running 0 81s
my-app-v2-759bffd84f-tggtq 1/1 Running 0 81s
my-app-v2-759bffd84f-vqxn9 1/1 Running 0 81s
返回响应基本均摊
# while sleep 1; do curl 10.110.141.72; done
Host: my-app-v1-5b4755fccf-hv69c, Version: v1.0.0
Host: my-app-v1-5b4755fccf-g6r6n, Version: v1.0.0
Host: my-app-v2-759bffd84f-qrxnv, Version: v2.0.0
Host: my-app-v2-759bffd84f-jt4pk, Version: v2.0.0
Host: my-app-v2-759bffd84f-vqxn9, Version: v2.0.0
Host: my-app-v1-5b4755fccf-hv69c, Version: v1.0.0
Host: my-app-v1-5b4755fccf-l9n4j, Version: v1.0.0
Host: my-app-v1-5b4755fccf-qdwv9, Version: v1.0.0
Host: my-app-v2-759bffd84f-vqxn9, Version: v2.0.0
Host: my-app-v1-5b4755fccf-p2zp8, Version: v1.0.0
Host: my-app-v1-5b4755fccf-gqpjc, Version: v1.0.0
Host: my-app-v2-759bffd84f-ncmr5, Version: v2.0.0
Host: my-app-v2-759bffd84f-97wxf, Version: v2.0.0
...
下线全部 v1 副本
# kubectl delete deploy my-app-v1
# while sleep 1; do curl 10.110.141.72; done
Host: my-app-v2-759bffd84f-fs79p, Version: v2.0.0
Host: my-app-v2-759bffd84f-97wxf, Version: v2.0.0
Host: my-app-v2-759bffd84f-qrxnv, Version: v2.0.0
Host: my-app-v2-759bffd84f-tggtq, Version: v2.0.0
Host: my-app-v2-759bffd84f-ncmr5, Version: v2.0.0
Host: my-app-v2-759bffd84f-97wxf, Version: v2.0.0
Host: my-app-v2-759bffd84f-fs79p, Version: v2.0.0
Host: my-app-v2-759bffd84f-lbsvx, Version: v2.0.0
Host: my-app-v2-759bffd84f-24rhg, Version: v2.0.0
...
清除实验环境
# kubectl delete all -l app=my-app
pod "my-app-v2-759bffd84f-24rhg" deleted
pod "my-app-v2-759bffd84f-8rkbl" deleted
pod "my-app-v2-759bffd84f-97wxf" deleted
pod "my-app-v2-759bffd84f-fs79p" deleted
pod "my-app-v2-759bffd84f-jt4pk" deleted
pod "my-app-v2-759bffd84f-lbsvx" deleted
pod "my-app-v2-759bffd84f-ncmr5" deleted
pod "my-app-v2-759bffd84f-qrxnv" deleted
pod "my-app-v2-759bffd84f-tggtq" deleted
pod "my-app-v2-759bffd84f-vqxn9" deleted
service "my-app" deleted
deployment.apps "my-app-v2" deleted
replicaset.apps "my-app-v2-759bffd84f" deleted
Istio & Helm
补充
Blue/Green Deployment
蓝绿部署
-
在线上版本集群(蓝)之外单独部署新版本集群(绿);
-
经过测试新版本符合要求,通过 LB 将流量完全切换到新版本;
-
观察无误后,删除旧版本集群;
动态示意图
流量直接全量切换
Single Service
复用前面的 app-v1&v2.yaml
Service 的选择器同时匹配 app & version
# vim app-v1.yaml
...
selector:
app: my-app
version: v1.0.0
...
将副本数均设为 3
# vim app-v1.yaml & app-v2.yaml
...
spec:
replicas: 3
...
创建 app-v1 业务集群
# kubectl apply -f app-v1.yaml
# kubectl get pods -l app=my-app
NAME READY STATUS RESTARTS AGE
my-app-v1-5b4755fccf-22fz4 1/1 Running 0 29s
my-app-v1-5b4755fccf-mkjqr 1/1 Running 0 29s
my-app-v1-5b4755fccf-s8d5g 1/1 Running 0 29s
# kubectl get service my-app -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
my-app NodePort 10.104.179.119 <none> 80:30784/TCP 35m app=my-app,version=v1.0.0
创建 app-v2 业务集群
# kubectl apply -f app-v2.yaml
# kubectl rollout status deploy my-app-v2 -w
Waiting for deployment "my-app-v2" rollout to finish: 0 of 3 updated replicas are available...
Waiting for deployment "my-app-v2" rollout to finish: 1 of 3 updated replicas are available...
Waiting for deployment "my-app-v2" rollout to finish: 2 of 3 updated replicas are available...
deployment "my-app-v2" successfully rolled out
目前存在 my-app-v1 & my-app-v2 (蓝绿)两个集群
但业务流量只走 v1
# kubectl get pods -l app=my-app
NAME READY STATUS RESTARTS AGE
my-app-v1-5b4755fccf-22fz4 1/1 Running 0 42m
my-app-v1-5b4755fccf-mkjqr 1/1 Running 0 42m
my-app-v1-5b4755fccf-s8d5g 1/1 Running 0 42m
my-app-v2-759bffd84f-q8lxg 1/1 Running 0 114s
my-app-v2-759bffd84f-x8w8d 1/1 Running 0 114s
my-app-v2-759bffd84f-zz244 1/1 Running 0 114s
# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
my-app-v1 3/3 3 3 3h16m my-app containersol/k8s-deployment-strategies app=my-app,version=v1.0.0
my-app-v2 3/3 3 3 156m my-app containersol/k8s-deployment-strategies app=my-app,version=v2.0.0
# while sleep 1; do curl 10.104.179.119; done
Host: my-app-v1-5b4755fccf-s8d5g, Version: v1.0.0
Host: my-app-v1-5b4755fccf-22fz4, Version: v1.0.0
Host: my-app-v1-5b4755fccf-22fz4, Version: v1.0.0
Host: my-app-v1-5b4755fccf-s8d5g, Version: v1.0.0
Host: my-app-v1-5b4755fccf-22fz4, Version: v1.0.0
Host: my-app-v1-5b4755fccf-mkjqr, Version: v1.0.0
...
对 v2 集群进行功能测试及验证,确认正常后
将业务切到 v2,观察响应变化
# kubectl patch service my-app -p '{"spec":{"selector":{"version":"v2.0.0"}}}'
service/my-app patched
# while sleep 1; do curl 10.104.179.119; done
Host: my-app-v1-5b4755fccf-22fz4, Version: v1.0.0
Host: my-app-v1-5b4755fccf-s8d5g, Version: v1.0.0
Host: my-app-v1-5b4755fccf-22fz4, Version: v1.0.0
Host: my-app-v1-5b4755fccf-mkjqr, Version: v1.0.0
Host: my-app-v2-759bffd84f-zz244, Version: v2.0.0
Host: my-app-v2-759bffd84f-q8lxg, Version: v2.0.0
Host: my-app-v2-759bffd84f-q8lxg, Version: v2.0.0
Host: my-app-v2-759bffd84f-x8w8d, Version: v2.0.0
Host: my-app-v2-759bffd84f-zz244, Version: v2.0.0
Host: my-app-v2-759bffd84f-zz244, Version: v2.0.0
...
若需要回滚,则切回 v1 集群
# kubectl patch service my-app -p '{"spec":{"selector":{"version":"v1.0.0"}}}'
service/my-app patched
# while sleep 1; do curl 10.104.179.119; done
Host: my-app-v2-759bffd84f-zz244, Version: v2.0.0
Host: my-app-v2-759bffd84f-q8lxg, Version: v2.0.0
Host: my-app-v2-759bffd84f-x8w8d, Version: v2.0.0
Host: my-app-v2-759bffd84f-zz244, Version: v2.0.0
Host: my-app-v2-759bffd84f-x8w8d, Version: v2.0.0
Host: my-app-v2-759bffd84f-zz244, Version: v2.0.0
Host: my-app-v1-5b4755fccf-s8d5g, Version: v1.0.0
Host: my-app-v1-5b4755fccf-mkjqr, Version: v1.0.0
Host: my-app-v1-5b4755fccf-22fz4, Version: v1.0.0
Host: my-app-v1-5b4755fccf-22fz4, Version: v1.0.0
Host: my-app-v1-5b4755fccf-s8d5g, Version: v1.0.0
...
长期观察无误后,删除旧版本集群,释放资源
# kubectl delete deploy my-app-v1
清除实验环境
# kubectl delete all -l app=my-app
pod "my-app-v2-759bffd84f-q8lxg" deleted
pod "my-app-v2-759bffd84f-x8w8d" deleted
pod "my-app-v2-759bffd84f-zz244" deleted
service "my-app" deleted
deployment.apps "my-app-v2" deleted
replicaset.apps "my-app-v2-759bffd84f" deleted
Multiple Services
补充
Ramped Deployment
渐进部署也称滚动部署:
-
线上业务由 LB 管理的 v1 实例集群承担;
-
新增一个 v2 业务实例,等服务就绪后,加入 LB 池;
-
下线一个 v1 实例,释放资源;
-
直到所有 v1 实例逐一被全部替换
通过业务前端负载均衡配合新、旧版本实例替换,承载流量
滚动发布
maxSurge: 单次加入负载的新版本实例数量
maxUnavailable: 滚动更新过程中允许的不可访问实例数量
# vim app-v1.yaml
复用 app-v1.yaml,Deployment 的 selector 去掉 ‘version’ 字段
deployment name 去掉 v1 标识
apiVersion: v1
kind: Service
metadata:
name: my-app
labels:
app: my-app
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: http
selector:
app: my-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 10
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
version: v1.0.0
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9101"
spec:
containers:
- name: my-app
image: containersol/k8s-deployment-strategies
ports:
- name: http
containerPort: 8080
- name: probe
containerPort: 8086
env:
- name: VERSION
value: v1.0.0
livenessProbe:
httpGet:
path: /live
port: probe
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: probe
periodSeconds: 5
创建 v1 业务实例,查看各项信息
# kubectl apply -f app-v1.yaml
# kubectl get deployment -l app=my-app -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
my-app 10/10 10 10 10m my-app containersol/k8s-deployment-strategies app=my-app
# kubectl get pods -l app=my-app
NAME READY STATUS RESTARTS AGE
my-app-5b4755fccf-2clg2 1/1 Running 0 12m
my-app-5b4755fccf-579cp 1/1 Running 0 12m
my-app-5b4755fccf-6p52j 1/1 Running 0 12m
my-app-5b4755fccf-dks9q 1/1 Running 0 12m
my-app-5b4755fccf-dlq74 1/1 Running 0 12m
my-app-5b4755fccf-kbf87 1/1 Running 0 12m
my-app-5b4755fccf-kpm8x 1/1 Running 0 12m
my-app-5b4755fccf-mjp6g 1/1 Running 0 12m
my-app-5b4755fccf-s4z6l 1/1 Running 0 12m
my-app-5b4755fccf-wlpsj 1/1 Running 0 12m
# kubectl get service -l app=my-app -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
my-app NodePort 10.110.122.235 <none> 80:31495/TCP 13m app=my-app
编辑 v2 业务,在 ‘strategy’ 中定义 ‘maxSurge’ & ‘maxUnavailable’ 参数
此外, readinessProbe 指针区的 ‘initialDelaySeconds’ 设置大一些,观察效果更明显
# vim app-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 10
# define the rolling update strategy
# 'maxSurge': how many pod add at a time
# 'maxUnavailable': how many pod can be unavailable during the rolling update
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
version: v2.0.0
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9101"
spec:
containers:
- name: my-app
image: containersol/k8s-deployment-strategies
ports:
- name: http
containerPort: 8080
- name: probe
containerPort: 8086
env:
- name: VERSION
value: v2.0.0
livenessProbe:
httpGet:
path: /live
port: probe
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: probe
# set 'initialDelaySeconds' to a high value
# to have a better visibility of the ramped deployment
initialDelaySeconds: 15
periodSeconds: 5
应用 v2 模板,查看更替情况
# kubectl apply -f app-v2.yaml
deployment.apps/my-app configured
实时监控 pods 变化
# watch kubectl get pods -l app=my-app
Every 2.0s: kubectl get pods -l app=my-app
k01: Sat Oct 12 11:11:24 2019
NAME READY STATUS RESTARTS AGE
my-app-5b4755fccf-2clg2 1/1 Running 0 16m
my-app-5b4755fccf-579cp 1/1 Running 0 16m
my-app-5b4755fccf-6p52j 1/1 Running 0 16m
my-app-5b4755fccf-dks9q 1/1 Running 0 16m
my-app-5b4755fccf-dlq74 1/1 Running 0 16m
my-app-5b4755fccf-kbf87 1/1 Running 0 16m
my-app-5b4755fccf-kpm8x 1/1 Running 0 16m
my-app-5b4755fccf-mjp6g 1/1 Running 0 16m
my-app-5b4755fccf-s4z6l 1/1 Running 0 16m
my-app-5b4755fccf-wlpsj 1/1 Running 0 16m
新增一个 v2 实例,正常运行后,销毁一个 v1 实例,同时创建新实例
Every 2.0s: kubectl get pods -l app=my-app
k01: Sat Oct 12 13:40:48 2019
NAME READY STATUS RESTARTS AGE
my-app-5b4755fccf-2clg2 1/1 Running 0 166m
my-app-5b4755fccf-579cp 1/1 Running 0 166m
my-app-5b4755fccf-6p52j 1/1 Running 0 166m
my-app-5b4755fccf-dks9q 1/1 Running 0 166m
my-app-5b4755fccf-dlq74 1/1 Running 0 166m
my-app-5b4755fccf-kbf87 1/1 Running 0 166m
my-app-5b4755fccf-kpm8x 1/1 Running 0 166m
my-app-5b4755fccf-mjp6g 0/1 Terminating 0 166m
my-app-5b4755fccf-s4z6l 1/1 Running 0 166m
my-app-5b4755fccf-wlpsj 1/1 Running 0 166m
my-app-7555568f55-565c5 1/1 Running 0 30s
my-app-7555568f55-62f9r 0/1 ContainerCreating 0 2s
全部逐一完成替换
Every 2.0s: kubectl get pods -l app=my-app
k01: Sat Oct 12 14:07:48 2019
NAME READY STATUS RESTARTS AGE
my-app-7555568f55-565c5 1/1 Running 0 27m
my-app-7555568f55-62f9r 1/1 Running 0 27m
my-app-7555568f55-8nc6s 1/1 Running 0 25m
my-app-7555568f55-9r8zv 1/1 Running 0 23m
my-app-7555568f55-cv4qg 1/1 Running 0 26m
my-app-7555568f55-gmfvb 1/1 Running 0 23m
my-app-7555568f55-h65w9 1/1 Running 0 25m
my-app-7555568f55-j2m44 1/1 Running 0 26m
my-app-7555568f55-kps4p 1/1 Running 0 24m
my-app-7555568f55-lv7h5 1/1 Running 0 24m
流量全部迁至 v2 业务
# while sleep 1; do curl 10.110.122.235; done
Host: my-app-7555568f55-h65w9, Version: v2.0.0
Host: my-app-7555568f55-565c5, Version: v2.0.0
Host: my-app-7555568f55-9r8zv, Version: v2.0.0
Host: my-app-7555568f55-j2m44, Version: v2.0.0
Host: my-app-7555568f55-lv7h5, Version: v2.0.0
Host: my-app-7555568f55-j2m44, Version: v2.0.0
Host: my-app-7555568f55-gmfvb, Version: v2.0.0
...
回滚 & 暂停 & 发布
如果发现新版本有问题,可以回滚到原始版本
# kubectl rollout undo deploy my-app
开始自动替换 v2 实例
Every 2.0s: kubectl get pods -l app=my-app
k01: Sat Oct 12 14:53:54 2019
NAME READY STATUS RESTARTS AGE
my-app-5b4755fccf-5jxdh 1/1 Running 0 29s
my-app-5b4755fccf-hrghv 0/1 ContainerCreating 0 2s
my-app-5b4755fccf-zn7nd 1/1 Running 0 16s
my-app-7555568f55-565c5 1/1 Running 0 73m
my-app-7555568f55-62f9r 1/1 Running 0 73m
my-app-7555568f55-8nc6s 1/1 Running 0 71m
my-app-7555568f55-cv4qg 1/1 Running 0 72m
my-app-7555568f55-gmfvb 1/1 Terminating 0 69m
my-app-7555568f55-h65w9 1/1 Running 0 71m
my-app-7555568f55-j2m44 1/1 Running 0 72m
my-app-7555568f55-kps4p 1/1 Running 0 70m
my-app-7555568f55-lv7h5 1/1 Running 0 70m
暂停发布,业务保持 v1 & v2 共存的 10 个实例状态
# kubectl rollout pause deploy my-app
deployment.apps/my-app paused
Every 2.0s: kubectl get pods -l app=my-app
k01: Sat Oct 12 16:13:10 2019
NAME READY STATUS RESTARTS AGE
my-app-5b4755fccf-2xs7k 1/1 Running 0 78m
my-app-5b4755fccf-5jxdh 1/1 Running 0 79m
my-app-5b4755fccf-874q9 1/1 Running 0 78m
my-app-5b4755fccf-hrghv 1/1 Running 0 79m
my-app-5b4755fccf-qnccz 1/1 Running 0 78m
my-app-5b4755fccf-s68lq 1/1 Running 0 79m
my-app-5b4755fccf-xlwb5 1/1 Running 0 78m
my-app-5b4755fccf-zn7nd 1/1 Running 0 79m
my-app-7555568f55-ddz84 1/1 Running 0 12m
my-app-7555568f55-dp4w2 1/1 Running 0 11m
my-app-7555568f55-z59jf 1/1 Running 0 12m
访问结果 v1 & v2 共存,效果类似 A/B 测试
# while sleep 1; do curl 10.110.122.235; done
Host: my-app-5b4755fccf-qnccz, Version: v1.0.0
Host: my-app-7555568f55-ddz84, Version: v2.0.0
Host: my-app-5b4755fccf-2xs7k, Version: v1.0.0
Host: my-app-7555568f55-ddz84, Version: v2.0.0
Host: my-app-5b4755fccf-s68lq, Version: v1.0.0
...
解除暂停,继续滚动发布
# kubectl rollout resume deploy my-app
deployment.apps/my-app resumed
Every 2.0s: kubectl get pods -l app=my-app k01: Sat Oct 12 16:54:18 2019
NAME READY STATUS RESTARTS AGE
my-app-5b4755fccf-2xs7k 1/1 Running 0 119m
my-app-5b4755fccf-5jxdh 1/1 Running 0 120m
my-app-5b4755fccf-hrghv 1/1 Running 0 120m
my-app-5b4755fccf-qnccz 1/1 Running 0 119m
my-app-5b4755fccf-s68lq 1/1 Running 0 120m
my-app-5b4755fccf-xlwb5 1/1 Terminating 0 119m
my-app-5b4755fccf-zn7nd 1/1 Running 0 120m
my-app-7555568f55-cqzdc 1/1 Running 0 36s
my-app-7555568f55-ddz84 1/1 Running 0 53m
my-app-7555568f55-dp4w2 1/1 Running 0 52m
my-app-7555568f55-swfs7 0/1 ContainerCreating 0 3s
my-app-7555568f55-z59jf 1/1 Running 0 53
清除实验环境
# kubectl delete all -l app=my-app
pod "my-app-7555568f55-29lw2" deleted
pod "my-app-7555568f55-cqzdc" deleted
pod "my-app-7555568f55-ddz84" deleted
pod "my-app-7555568f55-dp4w2" deleted
pod "my-app-7555568f55-l7pdb" deleted
pod "my-app-7555568f55-sj72h" deleted
pod "my-app-7555568f55-swfs7" deleted
pod "my-app-7555568f55-sz758" deleted
pod "my-app-7555568f55-vtlkn" deleted
pod "my-app-7555568f55-z59jf" deleted
service "my-app" deleted
deployment.apps "my-app" deleted
replicaset.apps "my-app-5b4755fccf" deleted
replicaset.apps "my-app-7555568f55" deleted