上一篇在《Kubectl 部署无状态应用》中介绍了如何使用 Deployment 部署五个 hello world 实例时,我们并没有详细探讨 Deployment Controller 的各项功能。因此,本文将深入介绍 Deployment Controller 的作用以及它能够完成的任务。
本文来自官方文档梳理:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
1. 什么是 Deployment?
Deployment 为 Pod 和 Replica Set(下一代 Replication Controller)提供声明式更新。
只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和 ReplicaSet 的实际状态改变到您的目标状态。您可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。
- 定义 Deployment 来创建 Pod 和 ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续 Deployment
写到这,想起当年在某节打工时的一个场景:研发上线时,可以选择是否对当前服务进行扩缩容、按照比例对服务进行灰度、回滚服务等等。
是的,这一系列的功能,背后就是Deployment Controller在起作用。
创建Deployment
上一篇中使用了官方提供的node example例子。在本文中,此次将使用nginx镜像进行演示。
以下是部署的示例。它创建一个 ReplicaSet 来启动三个nginxPod:
vim nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
- 执行:
kubectl apply -f nginx-deployment.yaml
- 查看Deployment 是否已创建:
kubectl get deployments
------
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 2m2s
- 要查看Deployment 创建的ReplicaSet,可以运行:
kubectl get rs
------
NAME DESIRED CURRENT READY AGE
nginx-deployment-86dcfdf4c6 3 3 3 4m10s
- 要查看为每个 Pod 自动生成的标签,可以运行:
kubectl get pods --show-labels
------
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-86dcfdf4c6-2tdlj 1/1 Running 0 6m19s app=nginx,pod-template-hash=86dcfdf4c6
nginx-deployment-86dcfdf4c6-jqs52 1/1 Running 0 6m19s app=nginx,pod-template-hash=86dcfdf4c6
nginx-deployment-86dcfdf4c6-vhpsv 1/1 Running 0 6m19s app=nginx,pod-template-hash=86dcfdf4c6
2. 更新部署
注意:当且仅当 Deployment 的 Pod 模板(即.spec.template)发生更改(例如,模板的标签或容器映像更新)时,才会触发 Deployment 的推出。其他更新(例如扩展部署)不会触发部署。
- 将nginx Pod 从nginx:1.14.2更新成nginx:1.16.1
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
或者使用kubectl edit deployment/nginx-deployment
来对文件手动进行更改。
- 查看部署状态
运行kubectl get rs
可以看到 Deployment 通过创建新的 ReplicaSet 并将其扩展到 3 个副本,以及将旧的 ReplicaSet 缩减到 0 个副本来更新 Pod。
输出类似于:
NAME DESIRED CURRENT READY AGE
nginx-deployment-848dd6cfb5 3 3 3 3m10s
nginx-deployment-86dcfdf4c6 0 0 0 12m
- 下次想要更新这些Pod时,只需再次更新Deployment的Pod模板即可。
- 部署可确保更新时只有一定数量的 Pod 处于关闭状态。默认情况下,它确保至少有 75% 的所需 Pod 数量处于运行状态(最多 25% 不可用)。
- 部署还确保仅创建高于所需 Pod 数量的一定数量的 Pod。默认情况下,它确保最多 125% 的所需 Pod 数量处于启动状态(最大激增 25%)。
- 例如,如果你仔细观察上面的 Deployment,你会发现它首先创建了一个新的 Pod,然后删除了一个旧的 Pod,并创建了另一个新的 Pod。在出现足够数量的新 Pod 之前,它不会杀死旧 Pod;并且在杀死足够数量的旧 Pod 之前,它不会创建新 Pod。它确保至少有 3 个 Pod 可用,并且总共最多有 4 个 Pod 可用。如果部署有 4 个副本,Pod 的数量将在 3 到 5 之间。
- 查看部署详细信息
kubectl describe deployments
这里可以看到,当第一次创建Deployment时,它创建了一个ReplicaSet(nginx-deployment-86dcfdf4c6),并直接将其扩展到3个副本。当更新 Deployment 时,它创建了一个新的 ReplicaSet (nginx-deployment-848dd6cfb5) 并将其扩展到 1 并等待它出现。然后将旧的 ReplicaSet 缩小到 2 个,将新的 ReplicaSet 扩大到 2 个,这样每次都至少有 3 个 Pod 可用,最多创建 4 个 Pod。然后,它使用相同的滚动更新策略继续扩展和缩小新旧 ReplicaSet。最后,新的 ReplicaSet 中将有 3 个可用副本,而旧的 ReplicaSet 会缩小到 0。
3. 回滚部署
假设在更新部署时犯了拼写错误,将nginx:1.16.1写成了nginx:1.161
kubectl set image deployment/nginx-deployment nginx=nginx:1.161
执行kubectl rollout status deployment/nginx-deployment
来验证执行过程。
此时,可以 Ctrl-C 停止掉,执行kubectl get rs
查看创建的 Pod,您会发现新 ReplicaSet 创建的 1 个 Pod 陷入了镜像拉取循环。
kubectl get pods
注意:部署控制器会自动停止错误的部署,并停止扩展新的副本集。这取决于maxUnavailable指定的rollingUpdate 参数。Kubernetes 默认将该值设置为 25%。
要解决此问题,您需要回滚到之前稳定的 Deployment 版本。
1. 首先,检查此 Deployment 的历史修订
kubectl rollout history deployment/nginx-deployment
CHANGE-CAUSE在创建时,从部署注释复制kubernetes.io/change-cause到其修订版本。此处,本文并没有进行注释,因此CHANGE-CAUSE显示none。
CHANGE-CAUSE可以通过使用注释部署方式指定消息:
kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.1"
2. 查看每个修订的详细信息
kubectl rollout history deployment/nginx-deployment --revision=2
3. 回滚到以前的修订
撤消当前的修改并回滚到以前的修订版
kubectl rollout undo deployment/nginx-deployment
或者
kubectl rollout undo deployment/nginx-deployment --to-revision=2
再次执行kubectl get deployment nginx-deployment
查看是否回滚。