Deployment 是一种面向无状态应用的多个 Pod 副本进行自动化管理的工作负载控制器。无状态应用通常要求每个 Pod 副本的工作机制相同,提供的服务也相同。Deployment 在部署 Pod之 后会持续监控副本的运行状况和数量,始终保证用户指定的副本数量的 Pod 正常运行。常见的 Deployment 应用场景如下:
- 部署一个多副本的无状态服务。
- 多副本 Pod 的版本更新,以及部署过程的暂停和回滚。
- Pod 副本数量的水平扩缩容。
1. ReplicaSet
在学习 Deployment 控制器之前先来了解一下 ReplicaSet 控制器。
在早期的 Kubernete 版本中是没有这么多 Pod 副本控制器的,只有一个 Pod 副本控制器RC (ReplicationController),这个控制器是这样设计实现的:RC 独立于所控制的 Pod 并通过标签这个松耦合关联关系控制目标 Pod 实例的创建和销毁。随着 Kubernetes 的发展 RC 逐渐被 ReplicaSet 和 Deployment 所取代,Replicaset 进一步增强了 RC 标签选择器的灵活性。之前 RC 的标签选择器只能选择一个 Pod 标签而 ReplicaSet 拥有集合式的标签选择器,可以选择多个 Pod 标签。
Deployment 也通过 ReplicaSet 实现 Pod 副本自动控制功能的。
我们不应该直接使用底层的 ReplicaSet 来控制 Pod 副本,而应该通过管理 ReplicaSet 的 Deployment 对象来控制Pod副本,这是来自官方的建议。
ReplicaSet 和 Deployment 的区别:
- ReplicaSet:
- ReplicaSet 是 Kubernetes 中的一个控制器对象,用于确保指定数量的 Pod 副本在任何时间都在运行。
- ReplicaSet 只关注 Pod 的数量和健康状态,不具备更新和滚动更新的能力。
- ReplicaSet 通常直接操作 Pod,对 Pod 的管理比较底层。
- Deployment:
- Deployment 是建立在 ReplicaSet 之上的更高级别的控制器对象,用于声明式定义 Pod 副本的创建、更新和删除。
- Deployment 可以管理 ReplicaSet,并提供了滚动更新、版本控制和回滚等功能,使应用程序的更新更加灵活和可控。
- Deployment 通过 ReplicaSet 来管理 Pod 的数量和健康状态,同时还提供了对 ReplicaSet 的声明式定义和更新能力。
ReplicaSet 和 Deployment 的联系:
- Deployment 管理 ReplicaSet:
- Deployment 通常会创建一个或多个 ReplicaSet 来管理 Pod 的副本数量,并确保 Pod 的稳定运行。
- Deployment 通过 ReplicaSet 来实现滚动更新、版本控制和回滚等功能,使应用程序的更新更加可控和安全。
- 层级关系:
- ReplicaSet 是 Deployment 的一部分,Deployment 在底层使用 ReplicaSet 来管理 Pod 的副本数量。
- Deployment 提供了对 ReplicaSet 的抽象和管理,使用户可以更方便地定义和控制应用程序的部署和更新过程。
2. Deployment 配置示例
# nginx-deployment.yaml
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.18
ports:
- containerPort: 80
YAML部署 Deployment:
kubectl apply -f nginx-deployment.yaml
ShellScript查看 Deployment状态:
kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 8m43s
ShellScript该状态说明 Kubernetes 已经根据 Deployment 的定义创建好3个 Pod 副本,并且都正常运行,也都处于Ready状态。其中几个关键字段表示的含义如下:
- NAME:Deployment 的名称。
- READY:处于 Ready 状态的 Pod 副本数量,“/”右侧为期望的 Pod 副本数量,即 spec.replicas 字段的设置值。
- UP-TO-DATE:更新到最新 Pod 模板的 Pod 副本数量。
- AVAILABLE:可供用户使用的 Pod 副本数量。
- AGE:Deployment 的运行时间。
查看系统自动创建的 ReplicaSet 信息:
kubectl get replicaSet
NAME DESIRED CURRENT READY AGE
nginx-deployment-c6554cb58 3 3 3 20m
ShellScript其中几个关键字段表示的含义如下:
- NAME:ReplicaSet 的名称。
- DESIRED:期望的 Pod 副本数量,即 spec.replicas 字段设置的值。
- CURRENT:当前处于运行状态的 Pod 副本数量。
- READY:处于 Ready 状态的 Pod 副本数量。
- AGE:Deployment 的运行时间。
查看创建的 Pod 信息:
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-c6554cb58-g7jxt 1/1 Running 0 23m
nginx-deployment-c6554cb58-hx5rz 1/1 Running 0 23m
nginx-deployment-c6554cb58-s9whz 1/1 Running 0 23m
ShellScript3. Deployment 的 yaml 文件配置信息
Deployment 资源 yaml 配置中 spec 部分的核心配置字段主要介绍如下:
- selector:标签选择器,用于关联具有指定标签的 Pod 列表。
- template:Pod 模板,其中的配置项就是 Pod 的定义,作为 Deployment 资源的一部分存在,无须再设置 apiVersion 和 kind 这两个元数据。
- replicas:期望的 Pod 副本数量,默认值为 1。通过 kubect scale 命令调整后的副本数量将会覆盖初始设置的值。如果使用自动扩缩容 (HorizontalPodAutoscaler) 来自动调整Pod副本数量,则不需要设置这个值。
- strategy:更新策略,可选项包括 Recreate 和 RollingUpdate ,详见下一小节。
- minReadySeconds:Pod 最短就绪时间,至少要达到这个时间,系统才会设置 Pod 为 Ready 状态。
- progressDeadlineSeconds:设置未能处于部署完成状态的超时时间,默认值为600s (10min)。达到这个时间之后,系统将设置 Progressing 的状态为 False 并将Reason 设置为 ProgressDeadlineExceeded。
- revisionHistoryLimit:修订历史最大数量,每个修订版本都有一个对应的 ReplicaSet 资源,保存得过多将消耗更多资源,默认值为10。
- paused:设置为 true 来表示部署过程处于暂停状态,设置为 false 来表示处于正常部署过程。Kubernetes 对处于暂停状态的 Deployment 资源将不会监控 Pod 模板变化,而对处于非暂停状态的 Pod 模板变化会触发新的 rollout 操作。
selector 是与目标 Pod 关联的核心字段,可以通过 matchLabels 或matchExpressions 字段进行设置,Pod 的标签则在spec.template.metadata.labels[] 字段中进行设置。它们的用法和处理逻辑如下:
- matchLabels:设置一个或多个 (Pod 需要具有的)标签的值,以 key: value 格式表示,如果设置了多个标签,相互为逻辑与(AND)关系,即需要满足全部条件(Pod具有全部标签)才能与 Pod 关联成功。下面的例子中要求 Pod 具有两个标签:
selector:
matchLabels:
- app: nginx
- version: v1
YAML- matchExpressions:设置一个或多个(Pod需要具有的)标签取值条件表达(key,oftor,valus)三元组格式进行设置,其中 values 可以设置多个值,可以使用的运算符包括 In、Notln、Exists 和 DoesNotExist,使用 In 和 Notln 运算时要求 values 的值不能为空。示例如下:
selecor
matchExpressions:
- key: role
operator:
values:
- manager
- key: env
operator: NotIn
values:
- test
- prod
YAML如果 matchLabels 或 matchExppressions 两组配置都设置了,则要求 Pod 的标签满足全部的条件(逻辑与运算)才能完成关联。
另外,Deployment 的标签选择器配置在创建后是不能修改的,如果需要修改只能删除 Deployment 后重新创建。
4. Deployment 的 Pod 水平扩缩
水平扩缩的几种方式:
通过命令修改预期副本数:
kubectl scale deployment nginx-deployment --replicas=5
ShellScript修改 deployment 的部署 yaml 文件通过 kubectl apply 扩缩:
# 修改文件
...
replicas: 5
...
kubectl apply -f nginx-deployment.yaml
ShellScript通过 kubectl edit 命令修改 Deployment 的配置:
# 打开 deployment 配置手动修改副本数保存退出
kubectl edit deployment/nginx-deployment
ShellScript5. Deployment 的更新机制
Deployment 支持对 Pod 进行自动更新,通常以滚动更新的方式通过多个 ReplicaSet
版本完成对 Pod 的自动更新,适用于容器镜像更新后自动部署新版本应用的场景。
以文章前面的示例为例:
现在需要将 Pod 的镜像更新为 nginx:1.26.2 一种方法是通过 kubectl set image 命令为 Deployment 设置新的镜像名称:
kubectl set image deployment/nginx-deployment nginx=nginx:1.26.2
ShellScript另一种方法是通过 kubectl edit 命令修改 Deployment 的配置:
# 打开 deployment 配置手动修改镜像,保存退出
kubectl edit deployment/nginx-deployment
ShellScript或者修改 deployment 的部署 yaml 文件通过 kubectl apply 更新:
# 修改镜像版本
vim nginx-deployment.yaml
...
image: nginx:1.26.2
...
# 更新
kubectl apply -f nginx-deployment.yaml
ShellScript镜像名称(或 Pod 定义)一旦被修改,就会触发系统完成 Deployment 所有运行 Pod 的滚动更新操作。通过 kubect rolout status 命令,可以查看 Deployment 的更新过程:
kubectl rollout status deployment/nginx-deployment
ShellScript更新后查看 Pod 使用的镜像:
kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
ShellScriptDeployment 的更新过程:
初始创建 Deployment 时,系统创建了一个 ReplicaSet,并按用户的需求创建了 3 个 Pod 副本。更新 Deployment 时,系统创建了一个新的 ReplicaSet,并将其副本数量扩
展到 1,然后将旧的 ReplicaSet 副本数量缩减为 2。之后,系统继续按照相同的更新策略
对新旧两个 ReplicaSet 进行逐个调整。最后,新的 ReplicaSet 运行了 3 个新版本的 Pod。
通过 kubectl describe 命令可以查看更新过程描述:
kubectl describe deployments/nginx-deployment
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-c6554cb58 to 3
Normal ScalingReplicaSet 9m24s deployment-controller Scaled up replica set nginx-deployment-567cbc4d7c to 1
Normal ScalingReplicaSet 9m23s deployment-controller Scaled down replica set nginx-deployment-c6554cb58 to 2 from 3
Normal ScalingReplicaSet 9m23s deployment-controller Scaled up replica set nginx-deployment-567cbc4d7c to 2 from 1
Normal ScalingReplicaSet 9m22s deployment-controller Scaled down replica set nginx-deployment-c6554cb58 to 1 from 2
Normal ScalingReplicaSet 9m22s deployment-controller Scaled up replica set nginx-deployment-567cbc4d7c to 3 from 2
Normal ScalingReplicaSet 9m21s deployment-controller Scaled down replica set nginx-deployment-c6554cb58 to 0 from 1
ShellScript查看 Deployment 的更新策略:
kubectl get deployments.apps nginx-deployment -o yaml
# 找到 spec.strategy 字段
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
# 这是 k8s 系统创建 deployment 时的默认策略,也可以自定义更新策略
ShellScript在 Deployment 的定义中,可以通过 spec.strategy 指定 Pod 的更新策略,当前支持两种
略:Recreate(重建)和 RollingUpdate(滚动更新),默认值为 RollingUpdate。在前面的例子中使用的就是 RollingUpdate 策略。
- Recreate:设置 spec.strategy.type=Recreate 则 Deployment 在更新 Pod 时,会先“杀掉”所有正在运行的旧版本 Pod,等到旧版本 Pod 全部终止后,才开始创建新版本的 Pod。
- RollingUpdate:设置 spec.strategy.type=RollingUpdate 则 Deployment 会以滚动更新的方式逐个更新 Pod。同时,可以通过设置 spec.strategy.rollingUpdate 下的两个参数(maxUnavailable 和 maxSurge)来控制滚动更新的过程。
- maxUnavailable:用于指定 Deployment 在更新过程中不可用状态的 Pod 数量的上限。maxUnavailabl e参数值可以是绝对值(例如5)或 Pod 期望副本数量的百分比(例如25%),如果该参数被设置为百分比,那么系统会先以向下取整的方式计算出绝对值。而当另一个参数 maxSurge 被设置为0时,maxUnavailable 则必须被设置为绝对值大于0。
- maxSurge:用于指定在 Deployment 更新 Pod 的过程中 Pod 总数量超过 Pod期望副本数量部分的最大值。maxSurge 参数值可以是绝对值(例如5)或 Pod 期望副本数量的百分比(例如25%)。如果该参数被设置为百分比,那么系统会先以向上取整的方式计算出绝对值。
6. Deployment 的回滚
首先查看部署这个 Deployment 的历史记录:
kubectl rollout history deployment nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
# 这里的 CHANGE-CAUSE 值为空,如果想记录变更信息可以进行如下操作
# 在创建 Deployment
kubectl apply -f nginx-deployment.yaml
# 添加当前版本变更记录
kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="kubectl apply -f nginx-deployment.yaml"
# 更新镜像
kubectl set image deployment/nginx-deployment nginx=nginx:1.26.2
# 添加当前版本镜像变更记录
kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="image updated to 1.26.2"
# 再次查看历史记录
kubectl rollout history deployment nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl apply -f nginx-deployment.yaml
2 image updated to 1.26.2
# 查看特定版本的详细信息,--revision=2 指定版本号
kubectl rollout history deployment nginx-deployment --revision=2
ShellScript回滚操作:
# 回滚到上一个版本
kubectl rollout undo deployment nginx-deployment
# 也可以使用 --to-revision 指定回滚的版本号
kubectl rollout undo deployment nginx-deployment --to-revision=1
ShellScript7. Deployment 部署的暂停和恢复
对于一次复杂的 Deployment 配置修改,为了避免频繁触发 Deployment 的更新操作可以先暂停 Deployment 的更新操作,然后进行配置修改,接着恢复 Deployment。一次性触发完整的更新操作,就可以避免触发不必要的 Deployment 更新操作。
暂停 Deployment 更新:
kubectl rollout pause deployment nginx-deployment
kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="rollout pause deployment nginx-deployment"
ShellScript执行更新操作:
# 更新镜像
kubectl set image deployment/nginx-deployment nginx=nginx:1.26.2
# 查看历史记录没有触发更新操作
kubectl rollout history deployment nginx-deployment
# 更新容器的资源限制
kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
# 暂停 Deployment 更新后可以执行多个更新操作,在恢复更新后会统一执行
ShellScript恢复 Deployment 更新:
kubectl rollout resume deployment nginx-deployment
ShellScript