
暂停和继续 Deployment
你可以先暂停一个 Deployment 然后在触发一个或多个更新,最后在继续 (resume)该 Deployment ,这种做法使得你可以在暂停和继续中间对 Deployment 做多次更新,而无需触发不必要的滚动更新
创建 Deployment(将文件命名为 nginx-deployment.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
apps: nginx
spec:
replicas: 3
selector:
matchLabels:
apps: nginx
template:
metadata:
labels:
apps: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
创建 Deployment
kubectl apply -f nginx-deployment.yaml
执行命令查看 Deployment
kubectl get deployment
执行结果
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 5s
执行命令查看 ReplicaSet 信息
kubectl get rs
输出结果
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bdb998678 3 3 3 56s
执行命令暂停 Deployment
kubectl rollout pause deployment.v1.apps/nginx-deployment
输出结果
deployment.apps/nginx-deployment paused
执行命令更新镜像版本
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.18.0
输出结果
deployment.apps/nginx-deployment image updated
执行命令查看更新版本
kubectl rollout history deployment.v1.apps/nginx-deployment
输出的结果
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
可以查看到并没有生成 Deployment 的新版本
执行命令查看 ReplicaSet 是否更新
kubectl get rs
输出结果
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bdb998678 3 3 3 7m36s
跟上执行的 ReplicaSet 信息一样 说明更新并没有执行
如果需要,你可以针对 Deployment 执行多次更新,比如,更新 Deployment 的 resource 限制
kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
输出的结果
deployment.apps/nginx-deployment resource requirements updated
执行命令,确保 Deployment 信息被修改
kubecrl describe deployment nginx-deployment
输出结果
Name: nginx-deployment
Namespace: default
CreationTimestamp: Wed, 20 May 2020 14:55:57 +0800
Labels: apps=nginx
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"apps":"nginx"},"name":"nginx-deployment","namespace":"...
Selector: apps=nginx
Replicas: 3 desired | 0 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: apps=nginx
Containers:
nginx:
Image: nginx:1.18.0
Port: 80/TCP
Host Port: 0/TCP
Limits:
cpu: 200m # 已经修改
memory: 512Mi # 已经修改
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing Unknown DeploymentPaused
OldReplicaSets: nginx-deployment-5bdb998678 (3/3 replicas created)
NewReplicaSet: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-5bdb998678 to 3
暂停 Deployment 之前的信息当前仍然在起作用,而暂停 Deployment 之后,修改的 Deployment 信息尚未生效,因为该 Deployment 被暂停了
最后执行命令,将暂停的 Deployment 继续 (resume) 运行起来,可使前面的所有的变更,一次性生效
kubectl rollout resume deployment.v1.apps/nginx-deployment
输出结果
deployment.apps/nginx-deployment resumed
执行命令 观察滚动更新的进展
kubectl get rs -w
输出结果
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bdb998678 3 3 3 3m15s
nginx-deployment-6d4df58459 1 1 0 1s
nginx-deployment-6d4df58459 1 1 1 3s
nginx-deployment-5bdb998678 2 3 3 3m17s
nginx-deployment-6d4df58459 2 1 1 3s
nginx-deployment-5bdb998678 2 3 3 3m17s
nginx-deployment-6d4df58459 2 1 1 3s
nginx-deployment-5bdb998678 2 2 2 3m17s
nginx-deployment-6d4df58459 2 2 1 3s
nginx-deployment-6d4df58459 2 2 2 3s
nginx-deployment-5bdb998678 1 2 2 3m17s
nginx-deployment-6d4df58459 3 2 2 3s
nginx-deployment-5bdb998678 1 2 2 3m17s
nginx-deployment-6d4df58459 3 2 2 3s
nginx-deployment-5bdb998678 1 1 1 3m17s
nginx-deployment-6d4df58459 3 3 2 3s
nginx-deployment-6d4df58459 3 3 3 5s
nginx-deployment-5bdb998678 0 1 1 3m19s
nginx-deployment-5bdb998678 0 1 1 3m19s
nginx-deployment-5bdb998678 0 0 0 3m19s
查看 ReplicaSet 的最终状态
kubectl get rs
输出结果
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bdb998678 0 0 0 3m31s
nginx-deployment-6d4df58459 3 3 3 17s
你不能回滚 (rollback) 一个已经暂停 (pause)的 Deployment,除非你继续 (resume)Deployment
查看 Deployment 状态
Deployment 生命周期中将会进入不同的状态,这些状态有可能是
Progressing 正在执行滚动更新 complete 已经完成 fail to progress Deployment 失败
Progressing状态
当下任何一个任务正在执行时,kubernetes 将 Deployment 的状态标记为 progressing
Deployment 正在创建一个先的 ReplicaSet Deployment 正在 scale up 其最新的 ReplicaSet Deployment 正在 scale down 其旧的 ReplicaSet 新的 Pod 变为 就绪(ready) 或者 可用 (available)
你可以使用 kubectl rollout status
监控 Deployment 滚动更新的状态
complete 状态
如果 Deployment 符合以下条件,kubernetes 将 Deployment 的状态标记为 complete
该 Deployment 中的所有 Pod 副本都已经被更新到指定的最新版本 该 Deployment 中的所有 Pod 副本都处于可用(available)状态 该 Deployment 中没有旧的 ReplicaSet 运行
你可以使用 kubectl rollout status
查看 Deployment 是否已经处于 complete 状态,如果是则命令的退出码为 0 ,例如:
# 执行命令
kubectl rollout status deployment.v1.apps/nginx-deployment
# 查看命令退出码
echo $?
# 结果
0
Failed 状态
Deployment 在更新其最新的 ReplicaSet 时,可能会卡住而不能达到一个 complete 状态,如下原因可能会导致这个状况发生:
集群资源不够用 就绪检查(readliness probe) 失败 镜像抓取失败 权限不够 资源限制 应用程序的配置错误导致启动失败
指定 Deployment 定义中的.spec.progressDeadlineSeconds
字段,Deployment Controller 在等待时长后,将Deployment 标记为处理失败,例如
# 执行命令
kubectl path deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":60}}'
# 输出结果
deployment.apps/nginx-deployment patched
等待时间到达后,Deployment Controller 将在 Deployment 的.status.conditions
字段添加如下:
DeploymentCondition
Reason=ProgressDeadlineExceeded Status=False Type=Progressing
除了添加一个 Reason=ProgressDeadlineExceeded 的 DeploymentCondition 到
.status.conditions
字段以外,kubernetes 不会对卡住的 Deployment 做任何更改,你可以执行kubectl rollout undo
命令,回滚到上一个版本如果你暂停了 Deployment kubernetes 将不会检查
.spec.progressDeadlineSeconds
如果你设定的 .spec.progressDeadlinSeconds
太短了,或者其他原因,你可能发现 Deployment 的状态改变出错。例如,假设你的集群缺乏足够的资源,执行命令 kubectl describe deployment nginx-deployment
,输出结果如下所示:
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
执行命令 kubectl get deployment nginx-deployment -o yaml
,Deployment 的 Status 结果如下所示:
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: Replica set "nginx-deployment-4262182780" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
- lastTransitionTime: 2016-10-04T12:25:42Z
lastUpdateTime: 2016-10-04T12:25:42Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
reason: FailedCreate
status: "True"
type: ReplicaFailure
observedGeneration: 3
replicas: 2
unavailableReplicas: 2
最终,一旦 Deployment 的 .spec.progressDeadlinSeconds
超时,Kubernetes 将更新 Deployment 的 Processing condition 如下:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
为了解决资源不足的问题,你可以尝试:
scale down 您的 Deployment scale down 其他的 Deployment 向集群中添加计算节点
如果资源足够,并且 Deployment 完成了其滚动更新,您将看到 Deployment 中出现一个成功的 condition (status=True 且 Reason=NewReplicaSetAvailable)
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
Type=Available
及Status=True
代表您的 Deployment 具备最小可用的 Pod 数(minimum availability)Minimum availability 由 Deployment 中的 strategy 参数决定Type=Progressing
及Status=True
代表您的 Deployment 要么处于滚动更新的过程中,要么已经成功完成更新并且 Pod 数达到了最小可用的数量
命令 kubectl rollout status
可用于检查 Deployment 是否失败,如果该命令的退出码不是 0,则该 Deployment 已经超出了 .spec.progressDeadlinSeconds
指定的等候时长,例如,执行命令 kubectl rollout status deployment.v1.apps/nginx-deployment
,输出结果如下所示:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
$ echo $?
1
操作处于 Failed 状态的 Deployment
您可以针对 Failed 状态下的 Deployment 执行任何适用于 Deployment 的指令,例如:
scale up scale down 回滚到前一个版本 暂停(pause)Deployment,以对 Deployment 的 Pod template 执行多处更新
清理策略
可以在 Deployment 中设置 .spec.revsionHistoryLimit
,指定该 Deployment 保留多少个旧的 ReplicaSet ,超出这个数字在后台进行垃圾回收,默认为10
如果改字段设置为0 kubernetes 将清理掉该 Deployment 的所有历史版本,因此你将无法对该 Deployment 进行回滚操作
kubectl rollout undo
部署策略
通过 Deployment 中 .spec.strategy
字段,可以指定使用滚动更新 RollingUpdate
的部署策略还是使用重新创建 Recreate
的部署策略
| 字段名称 | 可选值 | 字段描述 |
|---|---|---|
| type (类型) | 滚动更新(RollingUpdate)/重新创建(Recreate) | 如果选择重新创建,Deployment将先删除原有副本集中的所有 Pod,然后再创建新的副本集和新的 Pod, 此时更新过程中将出现一段应用程序不可用的情况; |
| maxSurge (最大超出副本数) | 数字/百分比 | 滚动更新过程中,可以超出期望副本数的最大值。该取值可以是一个绝对值(例如:5),也可以是一个相对于期望副本数的百分比(例如:10%);如果填写百分比,则以期望副本数乘以该百分比后向上取整的方式计算对应的绝对值;当最大超出副本数 maxUnavailable 为 0 时,此数值不能为 0;默认值为 25%。例如:假设此值被设定为 30%,当滚动更新开始时,新的副本集(ReplicaSet)可以立刻扩容,但是旧 Pod 和新 Pod 的总数不超过 Deployment 期待副本数(spec.repilcas)的 130%。一旦旧 Pod 被终止后,新的副本集可以进一步扩容,但是整个滚动更新过程中,新旧 Pod 的总数不超过 Deployment 期待副本数(spec.repilcas)的 130% |
| maxUnavailable (最大不可用副本数) | 数字/百分比 | 滚动更新过程中,不可用副本数的最大值。该取值可以是一个绝对值(例如:5),也可以是一个相对于期望副本数的百分比(例如:10%);如果填写百分比,则以期望副本数乘以该百分比后向下取整的方式计算对应的绝对值;当最大超出副本数 maxSurge 为 0 时,此数值不能为 0;默认值为 25%;例如:假设此值被设定为 30%,当滚动更新开始时,旧的副本集(ReplicaSet)可以缩容到期望 < 副本数的 70%;在新副本集扩容的过程中,一旦新的 Pod 已就绪,旧的副本集可以进一步缩容,整个滚动更新过程中,确保新旧就绪副本数之和不低于期望副本数的 70% |
金丝雀发布(灰度发布)
如果你想使用 Deployment 将最新的应用程序版本发布给一部分用户(或服务器),你可以为每个版本创建一个 Deployment 此时,应用程序的新旧两个版本都可以同时获得生产上的流量
部署第一个版本
第一个 Deployment 版本包含 3 个 Pod 副本,Service 通过 label selector
apps:nginx
选择对应的 Pod,nginx的标签为1.7.9
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
apps: nginx
spec:
replicas: 3
selector:
matchLabels:
apps: nginx
template:
metadata:
labels:
apps: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
apps: nginx
spec:
selector:
apps: nginx
ports:
- name: nginx-port
protocol: TCP
port: 80
nodePort: 32600
targetPort: 80
type: NodePort
假设此时你要发布新的版本 nginx:1.18.0 ,可以创建另一个 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-canary
labels:
apps: nginx
track: canary
spec:
replicas: 3
selector:
matchLabels:
apps: nginx
track: canary
template:
metadata:
labels:
apps: nginx
track: canary
spec:
containers:
- name: nginx
image: nginx:1.18.0
因为 Service 的 LabelsSelector 是
apps:nginx
,由nginx-deployment
和nginx-deployment-canary
创建的 Pod 都带有标签apps:nginx
,所以 Service 的流量将会在两个 release 之间分配在新旧版本之间,流量分配的比例为两个版本副本数的比例,此处为 1:3
当你确定了新的版本没有问题了之后,可以将 nginx-deployment
的镜像标签改为新版本的镜像标签,并在完成对nginx-deployment
滚动更新之后,删除nginx-deployment-canary
这个 Deployment
局限性:
安装 kubernetes 默认支持的这种方式进行金丝雀发布,有一定的局限性:
不能根据用户注册时间,地区等请求中的内容属性进行流量分配 同一个用户如果多次调用同一个 Service,有可能第一次请求到旧的 Pod,第二次请求到新的 Pod
在 kubernetes 中不能解决上述局限性的问题
kubernetes Service 只在 TCP 层面解决负载均衡的问题,并不对请求响应的消息内容做解析和识别,如果想要更完善的实现金丝雀发布,可以考虑如下三种方式:
业务代码编排实现 Spring Cloud 灰度发布 Istio 灰度发布





