一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
一、 前言
使用 Deployment
进行 Pod
的部署、升级与回滚。
Deployment
为Pod
和ReplicaSet
提供了声明式定义方法,可以替代之前使用的ReplicationController(RC)
来管理应用。
Deployment
资源对象为 Pod
和 ReplicaSet
(ReplicationController
的升级版)提供了声明式定义,在 Deployment YAML
文件中描述期望达到的目标状态。
Deployment Controller
会创建符合目标状态的ReplicaSet
和Pod
,如果更新Deployment
,对应的ReplicaSet
和Pod
的状态也会改变以符合新的目标状态。
(1)典型应用场景
- 定义
Deployment
来创建ReplicaSet
和Pod
使用
Deployment
来创建ReplicaSet
,ReplicaSet
又会在后台创建Pod
。可以检查Pod
的启动状态,观察是成功还是失败。也可以根据Deployment
的状态判断上线是否hang
住了。
- 滚动升级和回滚应用
通过更新
Deployment
的PodTemplateSpec
字段来声明Pod
的新状态,更新Deployment
后会创建一个新的ReplicaSet
,Deployment
会按照控制的速率删除由旧的ReplicaSet
创建的Pod
、并使用新的ReplicaSet
创建新的Pod
,当新生成的Pod
达到要求的目标状态后,会清除旧的ReplicaSet
。如果当前状态不稳定,可以回滚到之前的
Deployment revision
,每次回滚都会更新Deployment
的revision
。
- 扩容和缩容
根据系统负载进行
Deployment
的扩容和缩容。
- 暂停和继续
Deployment
暂停
Deployment
并修改PodTemplateSpec
字段,然后重新恢复上线。
(2)举个例子
- 定应
Deployment
文件nginx-deployment.yaml
它可以创建一个
Replica Set
来启动 3个nginx pod
扫描二维码关注公众号,回复: 13779827 查看本文章
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
复制代码
- 执行创建
$ kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created
复制代码
- 查看
Deployment
的状态、RS的状态,以及运行的Pod
副本数量
# 可以看到已经创建了 3 个符合要求的 Pod,这 3 个 Pod 都是最新的、都处于可用状态
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 39s
# 该 RS 需要 3 个 Pod,当前符合要求的有 3 个 Pod 并且已经创建好,RS 名字的组成:<Deployment 的名字>-<Pod template 的 hash 值>
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5754944d6c 3 3 3 6m18s
# 使用 nginx-deployment-5754944d6c RS 创建的 3 个 Pod
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5754944d6c-gv8x8 1/1 Running 0 6m36s
nginx-deployment-5754944d6c-hsp99 1/1 Running 0 6m36s
nginx-deployment-5754944d6c-qqh42 1/1 Running 0 6m36s
复制代码
- 查看
nginx-deployment
的详细信息
$ kubectl describe deployment nginx-deployment
# 在 Annotations 记录了版本 revision: 1
# 默认更新策略使用的是 RollingUpdate
# max unavailable 和 max surge 的默认值都为 25%
# ReplicaSet 为 nginx-deployment-5754944d6c
复制代码
二、Deployment
升级
Kubernetes
提供滚动升级,就不用暂停与该服务相关的所有pod
通常使用
Deployment
来创建Pod
资源对象,当Pod
在运行中,可以修改Deployment
的Pod
定义或是镜像名称,并应用到Deployment 对象上,这样就完成了 Deployment
的自动更新操作。
(1)举个栗子
- 将
pod
的镜像更新为nginx:1.9.1
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.extensions/nginx-deployment image updated
# 也可以使用 kubectl edit 命令进行更新,把 image 字段下的 nginx:1.7.9 更改为 nginx:1.9.1
$ kubectl edit deployment/nginx-deployment
deployment.extensions/nginx-deployment edited
复制代码
- 修改了镜像名,就会触发系统完成
Deployment
所有运行pod
的滚动升级操作,查看rollout
状态
Tips: 当且仅当
Deployment
的.spec.template
字段下的labels
或是image
更新时才会触发rollout
,其它的更新并不会触发rollout
。
$ kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out
复制代码
- 查看更新后的
Deployment
、RS
、Pod
:
# 可以看到 UP-TO-DATE 的数量已经变成了 3,说明已经全部更新完成
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 143m
# 查看两个 RS 的最终状态,可以看到旧的 RS 已经没有 Pod 在运行了,新的 RS 创建好了 3 个新的 Pod
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5754944d6c 0 0 0 143m
nginx-deployment-7448597cd5 3 3 3 6m11s
# 由新 nginx-deployment-7448597cd5 RS 创建出来的 3 个 Pod
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-7448597cd5-7c9ms 1/1 Running 0 6m19s
nginx-deployment-7448597cd5-h6k89 1/1 Running 0 5m58s
nginx-deployment-7448597cd5-m8dnk 1/1 Running 0 5m25s
复制代码
- 查看
nginx-deployment
详细信息
$ kubectl describe deployments/nginx-deployment
# ReplicaSet 更新为 nginx-deployment-7448597cd5
复制代码
(2)分析更新过程
Event
事件,可以看到Pod
的更新过程:
- 系统创建了一个新的
RS(nginx-deployment-7448597cd5)
,将其副本数量扩展到 1;将旧的RS(nginx-deployment-5754944d6c)
副本数量缩减为 2 - 新的
RS
副本数量扩展到了 2,旧的RS
副本数量缩减为 1 - 新的
RS
副本数量扩展到了 3,旧的RS
副本数量缩减为 0
(3)更新策略
Deployment
通过字段 spec.strategy
设置 Pod
更新策略。
上面创建的 Deployment
的相关默认设置如下:
spec:
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
复制代码
Deployment
的更新策略有两种:
Recreat
(重建): 先kill
掉所有正在运行的Pod
,然后创建新的Pod
。RollingUpdate
(滚动更新): 逐个更新Pod
。可以在字段spec.strategy.rollingUpdate
下设置两个参数maxSurge
和maxUnavailable
来控制滚动更新的过程。
关于两个参数的详细说明:
maxUnavailable
:
指定更新过程中不可用状态的 Pod
数量上限。默认值 25% 指的是:Pod
期望副本数的 25%,然后系统会以向下取整的方式计算出绝对值(整数)。对于这里而言,当开始滚动更新时,旧的 RS
立即将副本数缩小到所需副本总数的 75%(3 * 75% = 2.25,然后向下取整,绝对值为 2),一旦新的 Pod
创建并准备好,旧的 RS
会进一步缩容,新的 RS 会进一步扩容,整个过程中系统在任意时刻都可以确保可用状态的 Pod
总数至少占 Pod
期望副本总数的 75%。
maxSurge
:指定更新过程中Pod
总数超过Pod
期望副本数部分的最大值。默认值 25% 指的是:Pod
期望副本数的 25%,然后系统会以向上取整的方式计算出绝对值(整数)。对于这里而言,新的RS
可以在滚动更新开始时立即进行副本数扩容,只要保证新旧RS
的Pod
副本总数之和不超过期望副本数的 125% 即可。一旦旧的 Pod 被 kill 掉,新的RS
会进一步扩容。在整个过程中系统在任意时刻都能确保新旧RS
的Pod
副本总数之和不超过所需副本数的 125%。
(4)多重更新(Rollover)
“多重更新”也就是多个滚动更新(Rollout
)同时进行。
每当 Deployment Controller
检测到有新的 Deployment
创建时,如果没有已存在的 ReplicaSet
来创建期望个数的Pod
,Deployment Controller
就会创建一个新的 ReplicaSet
来执行改变,已存在的 ReplicaSet
控制 ``label匹配字段
spec.selector但是
template不匹配字段
spec.template的
Pod进行缩容,然后新的
ReplicaSet将会扩容出匹配字段
spec.replicas指定数目的
Pod,旧的
ReplicaSet` 将会缩容到 0。
举个例子:比如创建了一个有 5 个 nginx:1.7.9 replica
的 Deployment
,当刚刚创建到 3 个 nginx:1.7.9 replica
时,开始更新 Deployment
将其镜像修改为 nginx:1.9.1
。在这种情况下,Deployment
会立即 kill
掉已创建的 3 个 nginx:1.7.9
的 Pod
,并开始创建 nginx:1.9.1
的 Pod
,它不会等到所有 5 个 nginx:1.7.9
的 Pod
都创建完成后才开始执行滚动更新。
更新 Deployment
的标签选择器(Label Selector
)
通常情况下不建议更新
Deployment
的标签选择器,因为这样会导致Deployment
选择的Pod
列表发生变化,可能与其他控制器发生冲突。
步骤如下:
- 添加标签选择器
在添加标签选择器时,注意要同步修改
Deployment
配置的Pod
标签,为Pod
添加新的标签。
这里有点不同的是,添加标签选择器无法向后兼容,新的标签选择器不会匹配和使用旧选择器创建的 ReplicaSets
和 Pod
,因此添加新的选择器会导致所有旧版本的 ReplicaSets
和由旧 ReplicaSets
创建的 Pod
处于孤立状态,即:不会被系统自动删除,也不受新的 ReplicaSet
控制。
向字段 spec.selector.matchLabels
和字段 spec.template.matedata.labels
同时添加标签 k8s: nginx-pod
,使用如下命令进行修改:
$ kubectl edit deployment/nginx-deployment
deployment.extensions/nginx-deployment edited
复制代码
查看更新后的 Deployment
、RS
、Pods
:
# 可以看到更新完成
$ kubectl get deployment/nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 3h58m
# 创建了新的 RS:
$ kubectl get rs nginx-deployment-8ff4cd577
NAME DESIRED CURRENT READY AGE
nginx-deployment-5754944d6c 0 0 0 3h58m
nginx-deployment-7448597cd5 3 3 3 101m
nginx-deployment-8ff4cd577 3 3 3 88s
# 使用新的 RS nginx-deployment-8ff4cd577 创建了 3 个 Pod,可以发现之前的 3 个 Pod 依然存在着,没有被删除
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-7448597cd5-7c9ms 1/1 Running 0 101m
nginx-deployment-7448597cd5-h6k89 1/1 Running 0 100m
nginx-deployment-7448597cd5-m8dnk 1/1 Running 0 100m
nginx-deployment-8ff4cd577-8gxw2 1/1 Running 0 95s
nginx-deployment-8ff4cd577-8plkw 1/1 Running 0 95s
nginx-deployment-8ff4cd577-g7bc2 1/1 Running 0 95s
复制代码
- 更新标签选择器
比如更新选择器中标签的键或值,这种做法产生的效果与添加新选择器标签类似。
- 删除标签选择器
从
Deployment
的标签选择器中删除一个或多个标签,该Deployment
的ReplicaSet
和Pod
不会受到任何影响,只是被删除的标签依然会存在与现有的ReplicaSet
和Pod
上。