03 (上)| Kubernetes 控制器
目录
自主式 Pod vs 控制器管理 Pod(原内容 + 补充)
3.3 replicaset 示例(原代码 100% 完整保留,新增逐行解析)
核心代码逐行解析(Line-by-Line Breakdown)
4.1 deployment 控制器的功能(原内容 + 补充)
核心代码逐行解析(Line-by-Line Breakdown)
一 什么是控制器

核心定义(原内容 + 补充)
观察 (Observe) → 比较 (Compare) → 分析 (Analyze) → 执行 (Execute)
- 监控集群状态:Pod 数量 / 状态(实际状态)
- 对比期望状态:例如
replicas:3(写入 etcd 的用户声明) - 分析差异:当前 2 个 Pod,缺少 1 个
- 执行操作:新建 1 个 Pod,拉平差异
控制器本质:用来管理期望值和现实状态之间的 Pod 差异,并且自动把这个差异拉平的自动化工具。
【生活类比】控制器就像小区的物业保安队长:你要求小区 3 个门永远各有 1 个保安在岗(期望状态),队长会实时巡逻检查(观察),如果某个门的保安去吃饭了(实际状态偏离),队长会立刻安排替补保安上岗(执行),直到所有门都符合要求。
自主式 Pod vs 控制器管理 Pod(原内容 + 补充)

[root@master -]# cp /etc/skel/.bash_profile [root@master ~]#rm -fr.bash_profile
[root@master -]# echo export KUBECONFIG=/etc/kubernetes/admin.conf >> .bash_profile
[root@master -]# echo export KUBECONFIG=/etc/kubernetes/admin.conf >>.bash_profile
代码解释:配置 kubectl 的认证文件路径,让当前用户可以直接操作 K8s 集群,无需每次指定--kubeconfig参数。底层动作:将环境变量KUBECONFIG写入用户的 bash 配置文件,每次登录时自动加载,kubectl 会从该路径读取 admin.conf 中的证书和 APIServer 地址。坑点:重复执行 echo 会导致配置文件中出现重复行,建议使用grep -q "KUBECONFIG" .bash_profile || echo ...避免重复。
【原文档乱码,建议删除或替换为实际内容】172.25.254.100 (root)4 会话尖查看 X 服务器工具设置 5 Q 用 c 0 由会话 服务工具会话夫看分执短软色设置今 17225254 100 oc4)

[root@master ~]# cd controler/
[root@master controler]#ls
[root@master controler]# kubectl run webserver --image myapp:vl
pod/webserver created
[root@master controler]# kubectl get pods
webserver NAME 1/1 READY STATUS Running RESTARTS AGE 0 3s
[ root@master controler]# kubectl delete pods webserver pod "webserver" deleted from default namespace
[root@master controler]# kubectl get pods No resources found in default namespace.
[root@master controler]#kubectl get pods No resources found in default namespace.
代码逐行解释:
cd controler/:进入控制器实验目录kubectl run webserver --image myapp:v1:创建自主式 Pod,直接由 APIServer 管理,无控制器介入kubectl get pods:查看 Pod 状态,显示已正常运行kubectl delete pods webserver:删除自主式 Pod- 再次查看 Pod,发现无资源存在
核心结论:
- 自主式 pod:pod 退出或意外关闭后不会被重新创建,生命周期完全由用户手动管理
- 控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目,Pod 故障会自动重建
控制器底层工作原理:Pod 控制器是管理 pod 的中间层,使用 Pod 控制器之后,只需要告诉 Pod 控制器,想要多少个什么样的 Pod 就可以了,它会创建出满足条件的 Pod 并确保每一个 Pod 资源处于用户期望的目标状态。如果 Pod 资源在运行中出现故障,它会基于指定策略重新编排 Pod。当建立控制器后,会把期望值写入 etcd,k8s 中的 apiserver 检索 etcd 中我们保存的期望状态,并对比 pod 的当前状态,如果出现差异,代码自驱动立即恢复。
官方文档链接
https://v1-30.docs.kubernetes.io/zh-cn/docs/concepts/workloads/controllers/

控制器也是管理pod的一种手段
- - 自主式pod:pod退出或意外关闭后不会被重新创建
- - 控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目
Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod
当建立控制器后,会把期望值写入etcd,k8s中的apiserver检索etcd中我们保存的期望状态,并对比pod的当前状态,如果出现差异代码自驱动立即恢复
二 控制器常用类型
表格
| 控制器名称 | 控制器用途 | 补充说明 |
|---|---|---|
| Replication Controller | 比较原始的 pod 控制器,已经被废弃,由 ReplicaSet 替代 | 仅支持基于等式的标签选择器,无集合选择能力 |
| ReplicaSet | ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行 | 支持基于集合的标签选择器,是 Deployment 的底层组件 |
| Deployment | 一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力 | 生产环境无状态服务首选,支持滚动更新、回滚、扩缩容 |
| DaemonSet | DaemonSet 确保全指定节点上运行一个 Pod 的副本 | 用于部署节点级服务,如日志采集、监控代理 |
| StatefulSet | StatefulSet 是用来管理有状态应用的工作负载 API 对象 | 为 Pod 提供稳定的网络标识、持久化存储、有序部署 / 更新 |
| Job | 执行批处理任务,仅执行一次任务,保证任务的一个或多个 Pod 成功结束 | 用于一次性任务,如数据备份、报表生成 |
| CronJob | Cron Job 创建基于时间调度的 Jobs | 用于定时任务,如每日凌晨数据同步 |
| HPA 全称 Horizontal Pod Autoscaler | 根据资源利用率自动调整 service 中 Pod 数量,实现 Pod 水平自动缩放 | 可与 Deployment/StatefulSet 联动,实现弹性伸缩 |
三 replicaset 控制器

【 ReplicaSet 架构图,展示 1 个 ReplicaSet 管理 3 个 Pod 的结构】
3.1 replicaset 功能(原内容 + 补充)
- ReplicaSet 是下一代的 Replication Controller, 官方推荐使用 ReplicaSet。
- ReplicaSet 和 Replication Controller 的唯一区别是选择器的支持,ReplicaSet 支持新的基于集合的选择器需求。
- ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。
- 虽然 ReplicaSets 可以独立使用,但今天它主要被 Deployments 用作协调 Pod 创建、删除和更新的机制。

【生活类比】ReplicaSet 就像工厂的生产线班长:你要求这条生产线永远有 3 个工人在操作机器(期望副本数),班长会实时清点人数,如果有工人请假、离职(Pod 故障),班长会立刻从备用工人中调人补上,直到生产线满员运行。
【 ReplicaSet 自愈示意图,展示 1 个 Pod 故障后自动重建的过程】
如果有一个不能用,它会立即开一个
3.2 replicaset 参数说明
| 参数名称 | 字段类型 | 参数说明 | 底层触发动作 |
|---|---|---|---|
| spec | Object | 详细定义对象,固定值就写 Spec | 告诉 APIServer 该资源的具体规格定义,是所有 K8s 资源的必填字段 |
| spec.replicas | integer | 指定维护 pod 数量 | 写入 etcd 作为期望状态,ReplicaSet 控制器会循环对比实际 Pod 数量与该值 |
| spec.selector | Object | Selector 是对 pod 的标签查询,与 pod 数量匹配 | 控制器通过该选择器筛选出自己管理的 Pod,是控制器与 Pod 关联的唯一纽带 |
| spec.selector.matchLabels | string | 指定 Selector 查询标签的名称和值,以 key : value 方式指定 | 控制器会列出所有带有该标签的 Pod,统计数量并与 replicas 对比 |
| spec.template | Object | 指定对 pod 的描述信息,比如 lab 标签,运行容器的信息等 | 当需要创建新 Pod 时,控制器会完全按照该模板生成 Pod |
| spec.template.metadata | Object | 指定 pod 属性 | 定义 Pod 的元数据,包括标签、注解等 |
| spec.template.metadata.labels | string | 指定 pod 标签 | 必须与 spec.selector.matchLabels 完全一致,否则控制器无法管理 Pod |
| spec.template.spec | Object | 详细定义对象 | 定义 Pod 的运行规格,包括容器、存储、网络等 |
| spec.template.spec.containers | list | Spec 对象的容器列表定义 | 定义 Pod 中运行的容器列表,支持多个容器 |
| spec.template.spec.containers.name | string | 指定容器名称 | 容器在 Pod 内的唯一标识,用于日志、监控等 |
| spec.template.spec.containers.image | string | 指定容器镜像 | kubelet 会根据该镜像名称从镜像仓库拉取镜像并运行 |
3.3 replicaset 示例(原代码 100% 完整保留,新增逐行解析)
#生成yml文件
[root@k8s-master ~]# kubectl create deployment replicaset --image myapp:v1 --dry-run=client -o yaml > replicaset.yml
代码解释:使用 kubectl 的 dry-run 模式生成 Deployment 的 YAML 模板,然后修改为 ReplicaSet 格式,避免手动编写容易出错。底层动作:kubectl 在本地生成符合 Deployment 规范的 YAML 文件,不会向 APIServer 发送任何请求。坑点:生成的是 Deployment 模板,需要手动将 kind 改为 ReplicaSet,并删除 Deployment 特有的字段(如 strategy)。
[root@k8s-master ~]# vim replicaset.yml
ReplicaSet YAML 核心代码:
yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicaset #指定pod名称,一定小写,如果出现大写报错
spec:
replicas: 2 #指定维护pod数量为2
selector: #指定检测匹配方式
matchLabels: #指定匹配方式为匹配标签
app: myapp #指定匹配的标签为app=myapp
template: #模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: myapp
spec:
containers:
image: myapp:v1
name: myapp
核心代码逐行解析(Line-by-Line Breakdown)
| 行号 | 代码 | 底层触发动作 |
|---|---|---|
| 1 | apiVersion: apps/v1 | 告诉 APIServer 该资源属于apps/v1 API 组,APIServer 将请求路由到 apps 组的控制器处理 |
| 2 | kind: ReplicaSet | 指定资源类型为 ReplicaSet,APIServer 调用 ReplicaSet 控制器的同步逻辑 |
| 3-4 | metadata: name: replicaset | 在 default 命名空间下创建名为 replicaset 的 ReplicaSet 资源,名称必须符合 RFC 1123 规范(全小写、数字、-、.) |
| 5-6 | spec: replicas: 2 | 将期望副本数 2 写入 etcd,ReplicaSet 控制器会持续监控实际 Pod 数量 |
| 7-9 | selector: matchLabels: app: myapp | 控制器会筛选所有带有app=myapp标签的 Pod,作为自己管理的对象 |
| 10-13 | template: metadata: labels: app: myapp | 定义新 Pod 的标签,必须与 selector 完全一致,否则控制器会无限创建 Pod |
| 14-17 | spec: containers: image: myapp:v1 name: myapp | 定义 Pod 中运行的容器,kubelet 会拉取 myapp:v1 镜像并启动名为 myapp 的容器 |
最容易踩的坑(Gotchas)
- 标签不匹配:
spec.selector.matchLabels与spec.template.metadata.labels不一致,会导致控制器无法找到自己创建的 Pod,从而无限创建新 Pod,最终耗尽集群资源。 - 名称包含大写字母:metadata.name 必须全小写,否则会报
Invalid value: "ReplicaSet": a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters错误。 - 镜像名称错误:镜像名称拼写错误或仓库不可达,会导致 Pod 处于
ImagePullBackOff状态,控制器会不断重启 Pod。
[root@k8s-master ~]# kubectl apply -f replicaset.yml
replicaset.apps/replicaset created
代码解释:应用 ReplicaSet YAML 文件,创建 ReplicaSet 资源。底层动作:kubectl 将 YAML 文件发送给 APIServer,APIServer 验证通过后写入 etcd,ReplicaSet 控制器检测到新资源,开始创建 2 个 Pod。
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-l4xnr 1 /1 Running 0 96s app=myapp
replicaset-t2s5p 1 /1 Running 0 96s app=myapp
代码解释:查看 Pod 状态及标签,确认 2 个 Pod 已正常运行,且都带有app=myapp标签。
#replicaset是通过标签匹配pod
[root@k8s-master ~]# kubectl label pod replicaset-l4xnr app=timinglee --overwrite
pod/replicaset-l4xnr labeled
代码解释:修改其中一个 Pod 的标签为app=timinglee,使其脱离 ReplicaSet 的管理。底层动作:ReplicaSet 控制器检测到自己管理的 Pod 数量变为 1(只有 replicaset-t2s5p 还带有app=myapp标签),与期望的 2 不一致,立刻创建 1 个新 Pod。
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-gd5fh 1 /1 Running 0 #新开启的
app=myapp
2s
pod
replicaset-l4xnr 1 /1 Running 0 3m19s app=timinglee
replicaset-t2s5p 1 /1 Running 0 3m19s app=myapp
代码解释:可以看到控制器自动创建了新的 Pod replicaset-gd5fh,而原来的 replicaset-l4xnr 因为标签改变,不再被 ReplicaSet 管理。
#恢复标签后
[root@k8s2 pod]# kubectl label pod replicaset-example-q2sq9 app-
[root@k8s2 pod]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-q2sq9 1 /1 Running 0 3m14s app=nginx
replicaset-example-th24v 1 /1 Running 0 3m14s app=nginx
replicaset-example-w7zpw 1 /1 Running 0 3m14s app=nginx
代码解释:删除 Pod 的标签(app-表示删除 app 标签),或恢复为原来的标签,控制器会根据新的标签数量调整 Pod 副本数。
#replicaset自动控制副本数量,pod可以自愈
[root@k8s-master ~]# kubectl delete pods replicaset-t2s5p
pod "replicaset-t2s5p" deleted
代码解释:手动删除一个被 ReplicaSet 管理的 Pod,验证自愈能力。底层动作:ReplicaSet 控制器检测到 Pod 数量变为 1,立刻创建 1 个新 Pod,恢复到期望的 2 个。
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-l4xnr 1 /1 Running 0 5m43s app=myapp
replicaset-nxmr9 1 /1 Running 0
15s
app=myapp
代码解释:可以看到控制器自动创建了新的 Pod replicaset-nxmr9,副本数恢复为 2。
#回收资源
[root@k8s2 pod]# kubectl delete -f rs-example.yml
代码解释:删除 ReplicaSet 资源,同时会删除所有由它管理的 Pod。底层动作:ReplicaSet 控制器接收到删除信号,先删除所有管理的 Pod,然后删除自身在 etcd 中的记录。
企业级生产应用(Enterprise Scenario)
千万级并发场景下的使用:ReplicaSet几乎不会单独在生产环境中使用,它的唯一作用是作为 Deployment 的底层组件,负责 Pod 的副本管理。唯一的例外场景:需要部署固定版本、永远不需要更新的无状态服务,例如静态资源缓存服务,此时可以直接使用 ReplicaSet,避免 Deployment 带来的版本管理开销。
进阶优化空间:
- 与 HPA 联动:通过 HorizontalPodAutoscaler 根据 CPU、内存或自定义指标自动调整 ReplicaSet 的副本数,实现弹性伸缩。
- Pod 反亲和性:配置 Pod 反亲和性,让 ReplicaSet 管理的 Pod 分散在不同的节点上,避免单点故障。
- 资源限制:为容器配置 requests 和 limits,避免 Pod 占用过多资源影响其他服务。
- 镜像拉取策略:设置
imagePullPolicy: IfNotPresent,避免每次启动 Pod 都拉取镜像,加快启动速度。
课后防宕机指南(Troubleshooting)
-
错误现象:kubectl get rs 显示 DESIRED=2,CURRENT=100+,READY=0,集群资源耗尽
- 报错信息:无明确报错,但节点 CPU / 内存使用率 100%,无法创建新 Pod
- 排查思路:执行
kubectl describe rs <rs-name>查看 Events,检查spec.selector.matchLabels与spec.template.metadata.labels是否完全一致。99% 的情况是标签不匹配导致控制器无限创建 Pod。 - 解决方法:修改 YAML 文件中的标签,使其一致,然后重新 apply,再手动删除多余的 Pod。
-
错误现象:Pod 一直处于 ImagePullBackOff 状态
- 报错信息:
kubectl describe pod <pod-name>显示Failed to pull image "myapp:v1": rpc error: code = Unknown desc = Error response from daemon: pull access denied for myapp, repository does not exist or may require 'docker login' - 排查思路:检查镜像名称是否正确,节点是否能访问镜像仓库,是否需要配置镜像拉取密钥(ImagePullSecret)。
- 解决方法:修正镜像名称,或配置 ImagePullSecret 让节点有权限拉取私有镜像。
- 报错信息:
四 deployment 控制器
4.1 deployment 控制器的功能(原内容 + 补充)

【 Deployment 架构图,展示 1 个 Deployment 管理多个 ReplicaSet,每个 ReplicaSet 管理多个 Pod 的结构】
前者(ReplicaSet)的升级版
既可以维护 POD 数量,也可以维护 POD 版本
宏观调控,暂停与恢复的艺术
- - 为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。
- - Deployment控制 器并不直接管理pod,而是通过管理ReplicaSet来间接管理Pod
- - Deployment管理ReplicaSet,ReplicaSet管理Pod
- - Deployment 为 Pod 和 ReplicaSet 提供了一个申明式的定义方法
- - 在Deployment中ReplicaSet相当于一个版本
Deployment 控制器并不直接管理 pod, 而是通过管理 ReplicaSet 来间接管理 Pod。层级关系:Deployment → ReplicaSet → PodDeployment 为 Pod 和 ReplicaSet 提供了一个申明式的定义方法。在 Deployment 中,ReplicaSet 相当于一个版本,每个版本对应一个唯一的 ReplicaSet。
【生活类比】Deployment 就像连锁餐厅的区域经理:你要求区域内有 4 家门店(期望副本数),每家门店对应一个版本的菜单(ReplicaSet 版本)。当你要更新菜单时,区域经理会先开 1 家新版本的门店(创建新 ReplicaSet),然后关闭 1 家老版本的门店(缩容老 ReplicaSet),直到所有门店都更新为新版本。如果新版本出问题了,区域经理会立刻把老版本的门店再开回来(回滚)。
典型的应用场景:
- 用来创建 Pod 和 ReplicaSet
- 滚动更新和回滚
- 扩容和缩容
- 暂停与恢复
4.2 deployment 控制器示例
#生成yaml文件
[root@k8s-master ~]# kubectl create deployment deployment --image myapp:v1 --dry-run=client -o yaml > deployment.yml
代码解释:使用 dry-run 模式生成 Deployment 的 YAML 模板,这是生产环境中编写 Deployment 的标准方式。底层动作:kubectl 在本地生成符合 Deployment 规范的 YAML 文件,包含所有必填字段。
[root@k8s-master ~]# vim deployment.yml
Deployment YAML 核心代码:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
image: myapp:v1
name: myapp
核心代码逐行解析(Line-by-Line Breakdown)
| 行号 | 代码 | 底层触发动作 |
|---|---|---|
| 1 | apiVersion: apps/v1 | 告诉 APIServer 该资源属于apps/v1 API 组,路由到 Deployment 控制器处理 |
| 2 | kind: Deployment | 指定资源类型为 Deployment,APIServer 调用 Deployment 控制器的同步逻辑 |
| 3-4 | metadata: name: deployment | 在 default 命名空间下创建名为 deployment 的 Deployment 资源 |
| 5-6 | spec: replicas: 4 | 期望副本数 4,Deployment 控制器会创建一个 ReplicaSet,其 replicas 为 4 |
| 7-9 | selector: matchLabels: app: myapp | Deployment 通过该选择器筛选自己管理的 ReplicaSet,ReplicaSet 再通过该选择器筛选 Pod |
| 10-13 | template: metadata: labels: app: myapp | 定义 Pod 模板,Deployment 会将该模板传递给 ReplicaSet,用于创建 Pod |
| 14-17 | spec: containers: image: myapp:v1 name: myapp | 定义容器规格,与 ReplicaSet 中的容器定义一致 |
最容易踩的坑(Gotchas)
- replicas 字段缺失:原示例中
replicas:后面没有写数字,会导致默认创建 1 个 Pod,而不是期望的 4 个。 - selector 与 template 标签不一致:与 ReplicaSet 一样,标签不匹配会导致 Deployment 无法管理 ReplicaSet,从而无限创建新的 ReplicaSet。
- strategy 配置错误:如果将
maxUnavailable设置为 100%,会导致更新时所有老 Pod 被一次性删除,服务完全中断。
#建立pod 监控部分显示的结果
root@k8s-master ~]# kubectl apply -f deployment.yml
deployment.apps/deployment created
代码解释:应用 Deployment YAML 文件,创建 Deployment 资源。底层动作:Deployment 控制器创建一个名为deployment-<pod-template-hash>的 ReplicaSet,然后由 ReplicaSet 创建 4 个 Pod。
#查看pod信息
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
deployment-5d886954d4-2ckqw /1 Running 0 app=myapp,pod-
1
23s
template-hash=5d886954d4
deployment-5d886954d4-m8gpd 1 /1 Running 0
app=myapp,pod-
23s
template-hash=5d886954d4
deployment-5d886954d4-s7pws 1 /1 Running 0 app=myapp,pod-
23s
template-hash=5d886954d4
deployment-5d886954d4-wqnvv 1 /1 Running 0 app=myapp,pod-
23s
template-hash=5d886954d4
代码解释:查看 Pod 状态,可以看到所有 Pod 都带有pod-template-hash=5d886954d4标签,这个哈希值是根据 Pod 模板计算出来的,用于唯一标识 ReplicaSet 版本。
4.2.1 版本迭代
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP
NODE NOMINATED NODE
NODE NOMINATED NODE READINESS GATES
deployment-5d886954d4-2ckqw 1 /1 Running 0 2m40s 10.244.2.14
k8s-node2 <none> <none>
<none>
deployment-5d886954d4-m8gpd 1 /1 Running 0
2m40s
10.244.1.17
k8s-node1 <none> <none>
<none>
deployment-5d886954d4-s7pws 1 /1 Running 0 2m40s 10.244.1.16
k8s-node1 <none> <none>
<none>
deployment-5d886954d4-wqnvv 1 /1 Running 0
10.244.2.15
2m40s
k8s-node2 <none> <none>
<none>
代码解释:查看 Pod 的详细信息,包括 IP 地址和所在节点。
#pod运行容器版本为v1
[root@k8s-master ~]# curl 10.244.2.14
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
代码解释:访问 Pod 的 IP,确认当前运行的是 v1 版本的应用。
[root@k8s-master ~]# kubectl describe deployments.apps deployment
Name: deployment
Name:
default
Namespace: default
CreationTimestamp: Sun, 01 Sep 2024 23:19:10 +0800
Labels: <none>
Annotations:
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=myapp
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0
unavailable
StrategyType: RollingUpdate
StrategyType:
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge #默认每次更新
25%
代码解释:查看 Deployment 的详细信息,包括当前版本(revision:1)、更新策略(默认滚动更新,maxUnavailable=25%,maxSurge=25%)。底层动作:默认滚动更新策略表示,更新时最多可以有 25% 的 Pod 不可用,最多可以比期望副本数多 25% 的 Pod,保证更新过程中服务不会中断。
#更新容器运行版本
[root@k8s-master ~]# vim deployment.yml
更新后的 Deployment YAML(原内容完整保留):
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
minReadySeconds: 5 #最小就绪时间5秒
replicas:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
image: myapp:v2 #更新为版本2
name: myapp
代码解释:将镜像版本更新为 v2,并添加minReadySeconds: 5,表示 Pod 启动后至少等待 5 秒才会被视为就绪,接收流量。底层动作:Deployment 控制器检测到 Pod 模板发生变化,创建一个新的 ReplicaSet(版本 2),然后按照滚动更新策略,逐步扩容新 ReplicaSet,缩容老 ReplicaSet。
[root@k8s2 pod]# kubectl apply -f deployment-example.yaml
代码解释:应用更新后的 Deployment YAML 文件,触发滚动更新。
#更新过程
[root@k8s-master ~]# watch - n1 kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE
deployment-5d886954d4-8kb28 1 /1 Running 0
48s
deployment-5d886954d4-8s4h8 1 /1 Running 0
49s
1 0
deployment-5d886954d4-rclkp /1 Running
50s
deployment-5d886954d4-tt2hz 1 /1 Running 0
50s
deployment-7f4786db9c-g796x 0 /1 Pending 0
0s
代码解释:使用 watch 命令实时查看 Pod 更新过程,可以看到老版本的 Pod(5d886954d4)在逐步被删除,新版本的 Pod(7f4786db9c)在逐步创建。
#测试更新效果
[root@k8s-master ~] # kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP
NODE NOMINATED NODE
NODE NOMINATED NODE READINESS GATES
deployment-7f4786db9c-967fk 1 /1 Running 0 10.244.1.26
10s
k8s-node1 <none> <none>
<none>
deployment-7f4786db9c-cvb9k 1 /1 Running 0 10.244.2.24
10s
k8s-node2 <none> <none>
deployment-7f4786db9c-kgss4 1 /1 Running 0
9s
10.244.1.27
k8s-node1 <none> <none>
<none>
deployment-7f4786db9c-qts8c 1 /1 Running 0 10.244.2.25
9s
k8s-node2 <none> <none>
代码解释:更新完成后,所有 Pod 都变成了新版本(7f4786db9c)。
[root@k8s-master ~]# curl 10.244.1.26
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
代码解释:访问 Pod 的 IP,确认当前运行的是 v2 版本的应用。
[!NOTE]更新的过程是重新建立一个版本的 RS, 新版本的 RS 会把 pod 重建,然后把老版本的 RS 回收
4.2.2 版本回滚(原内容完整保留,新增解析)
[root@k8s-master ~]# vim deployment.yml
回滚后的 Deployment YAML(原内容完整保留):
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas: 4
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
image: myapp:v1 #回滚到之前版本
name: myapp
代码解释:将镜像版本改回 v1,触发回滚操作。底层动作:Deployment 控制器检测到 Pod 模板变回 v1,会将老版本的 ReplicaSet(版本 1)重新扩容,同时缩容新版本的 ReplicaSet(版本 2)。
[root@k8s-master ~]# kubectl apply -f deployment.yml
deployment.apps/deployment configured
代码解释:应用回滚后的 Deployment YAML 文件,触发回滚。
#测试回滚效果
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP
NODE NOMINATED NODE
NODE NOMINATED NODE READINESS GATES
deployment-5d886954d4-dr74h 1 /1 Running 0
10.244.2.26
8s
k8s-node2 <none> <none>
<none>
deployment-5d886954d4-thpf9 1 /1 Running 0
10.244.1.29
7s
k8s-node1 <none> <none>
<none>
deployment-5d886954d4-vmwl9 1 /1 Running 0
10.244.1.28
8s
k8s-node1 <none> <none>
<none>
deployment-5d886954d4-wprpd 1 /1 Running 0
10.244.2.27
6s
k8s-node2 <none> <none>
代码解释:回滚完成后,所有 Pod 都变回了老版本(5d886954d4)。
[root@k8s-master ~]# curl 10.244.2.26
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
代码解释:访问 Pod 的 IP,确认已经回滚到 v1 版本。
4.2.3 滚动更新策略(原内容完整保留,新增解析)
[root@k8s-master ~]# vim deployment.yml
自定义滚动更新策略的 Deployment YAML(原内容完整保留):
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
minReadySeconds: 5 #最小就绪时间,指定pod每隔多久更新一次
replicas:
strategy: #指定更新策略
rollingUpdate:
maxSurge: 1 #比定义pod数量多几个
maxUnavailable: 0 #比定义pod个数少几个
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
image: myapp:v1
name: myapp
代码解释:自定义滚动更新策略,maxSurge: 1表示更新时最多可以比期望副本数多 1 个 Pod,maxUnavailable: 0表示更新时不允许有任何 Pod 不可用,实现零中断更新。底层动作:Deployment 控制器会先创建 1 个新版本的 Pod,等待其就绪后,再删除 1 个老版本的 Pod,重复这个过程直到所有 Pod 都更新完成。
[root@k8s2 pod]# kubectl apply -f deployment-example.yaml
代码解释:应用自定义更新策略的 Deployment YAML 文件。
4.2.4 暂停及恢复(原内容完整保留,新增解析)
使用场景:在实际生产环境中我们做的变更可能不止一处,当修改了一处后,如果执行变更就直接触发了更新。我们期望的是当把所有修改都搞定后一次触发,所以需要先暂停 Deployment,避免触发不必要的线上更新。
[root@k8s2 pod]# kubectl rollout pause deployment deployment-example
代码解释:暂停 Deployment 的滚动更新,此时对 Deployment 的任何修改都不会触发更新。底层动作:Deployment 控制器会停止处理 Pod 模板的变化,直到恢复更新。
[root@k8s2 pod]# vim deployment-example.yaml
修改后的 Deployment YAML(原内容完整保留):
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-example
spec:
minReadySeconds: 5
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
replicas: 6
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
name: myapp
image: nginx
resources:
limits:
0.5
memory: 200Mi
requests:
cpu: 0.5
memory: 200Mi
代码解释:同时修改了副本数(从 4 改为 6)、镜像(从 myapp:v1 改为 nginx)和资源限制。
[root@k8s2 pod]# kubectl apply -f deployment-example.yaml
代码解释:应用修改后的 YAML 文件,由于 Deployment 处于暂停状态,只会更新副本数(扩容到 6 个),不会触发镜像和资源限制的更新。
#调整副本数,不受影响
[root@k8s-master ~]# kubectl describe pods deployment-7f4786db9c-8jw22
Name: deployment-7f4786db9c-8jw22
Name:
default
Namespace: default
Priority: 0
Service Account: default
default
Node:
Node: k8s-node1/172.25.254.10
Start Time: Mon, 02 Sep 2024 00:27:20 +0800
Labels: app=myapp
pod-template-hash=7f4786db9c
Annotations: <none>
<none>
Status:
Status: Running
10.244.1.31
IP:
IPs:
10.244.1.31
IP:
Controlled By: ReplicaSet/deployment-7f4786db9c
Containers:
myapp:
Container ID:
docker://01ad7216e0a8c2674bf17adcc9b071e9bfb951eb294cafa2b8482bb8b4940c1d
Image: myapp:v2
Image:
Image ID: docker-
docker-
pullable://myapp@sha256:5f4afc8302ade316fc47c99ee1d41f8ba94dbe7e3e7747dd87215a15
429b9102
Port: <none>
<none>
State: Running
Host Port: <none>
Started: Mon, 02 Sep 2024 00:27:21 +0800
Ready: True
Restart Count: 0
Environment: <none>
<none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-mfjjp
(ro)
Conditions:
Type Status
PodReadyToStartContainers True
True
Initialized True
True
Ready True
True
ContainersReady True
PodScheduled True
True
Volumes:
kube-api-access-mfjjp:
Type: Projected (a volume that contains injected data from
multiple sources)
TokenExpirationSeconds: 3607
Confi gMapName:
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
<nil>
DownwardAPI: true
Qos Class: BestEffort
Node-Selectors: <none>
<none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists
for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists
for 300s
Events:
Type Reason Age From Message
Normal Scheduled 6m22s default-scheduler Successfully assigned
default/deployment-7f4786db9c-8jw22 to k8s-node1
Normal Pulled 6m22s kubelet
"myapp:v2"
already present on machine
Normal Created 6m21s kubelet Created container myapp
Normal Created 6m21s kubelet
Normal Started 6m21s kubelet Started container myapp
Normal Started 6m21s kubelet
代码解释:查看 Pod 的详细信息,可以看到镜像仍然是 myapp:v2,资源限制也没有变化,说明暂停状态下只有副本数的修改生效了。
#但是更新镜像和修改资源并没有触发更新
[root@k8s2 pod]# kubectl rollout history deployment deployment-example
deployment.apps/deployment-example
REVISION CHANGE-CAUSE
3 <none>
4 <none>
代码解释:查看 Deployment 的更新历史,可以看到当前有 2 个版本。
#恢复后开始触发更新
[root@k8s2 pod]# kubectl rollout resume deployment deployment-example
代码解释:恢复 Deployment 的滚动更新,此时之前所有的修改(镜像、资源限制)会一次性触发更新。底层动作:Deployment 控制器开始处理之前积累的修改,创建新的 ReplicaSet,按照滚动更新策略替换老的 Pod。
[root@k8s2 pod]# kubectl rollout history deployment deployment-example
deployment.apps/deployment-example
REVISION CHANGE-CAUSE
3 <none>
4 <none>
5 <none>
代码解释:恢复更新后,生成了新的版本 5。
#回收
[root@k8s2 pod]# kubectl delete -f deployment-example.yaml
代码解释:删除 Deployment 资源,同时会删除所有由它管理的 ReplicaSet 和 Pod。
企业级生产应用(Enterprise Scenario)
千万级并发场景下的使用:Deployment 是生产环境中无状态服务的绝对首选,例如电商的商品详情页、API 网关、微服务接口等。在千万级并发场景下,Deployment 配合以下组件可以实现高可用、高性能的服务部署:
- 与 HPA 联动:根据 CPU、内存、QPS 等指标自动扩缩容,应对流量洪峰。
- 与 Service/Ingress 联动:通过 Service 提供稳定的访问入口,Ingress 实现七层负载均衡和域名路由。
- 多可用区部署:配置 Pod 拓扑分布约束,让 Pod 分散在不同的可用区,避免单可用区故障导致服务中断。
进阶优化空间:
- 金丝雀发布:通过修改 Deployment 的
maxSurge和maxUnavailable,先发布少量新版本 Pod,验证无误后再全量更新。 - 蓝绿部署:创建两个独立的 Deployment,分别对应蓝绿版本,通过切换 Service 的标签选择器实现流量切换。
- 镜像预热:提前将镜像拉取到所有节点,避免更新时因为拉取镜像导致 Pod 启动缓慢。
- 健康检查:配置
livenessProbe和readinessProbe,及时发现故障 Pod 并重启,避免将流量转发到不可用的 Pod。 - PodDisruptionBudget(PDB):配置 PDB,保证更新或节点维护时至少有 N 个 Pod 可用,避免服务中断。
- 资源超配:根据业务特点合理配置 requests 和 limits,提高集群资源利用率。
课后防宕机指南(Troubleshooting)
-
错误现象:Deployment 更新卡住,一直显示
Progressing状态,超过progressDeadlineSeconds(默认 600 秒)后报错- 报错信息:
kubectl describe deployment <deployment-name>显示ProgressDeadlineExceeded - 排查思路:
- 执行
kubectl get pods查看是否有 Pod 处于ImagePullBackOff、CrashLoopBackOff状态 - 执行
kubectl describe pod <pod-name>查看 Pod 的 Events,确认是镜像问题、资源问题还是健康检查问题 - 检查节点资源是否充足,是否有节点处于
NotReady状态
- 执行
- 解决方法:根据具体问题修复,例如修正镜像名称、增加节点资源、调整健康检查参数。
- 报错信息:
-
错误现象:更新时服务出现 503 错误,部分请求失败
- 报错信息:客户端访问返回 503 Service Unavailable
- 排查思路:
- 检查 Deployment 的
maxUnavailable是否设置过大,导致更新时可用 Pod 数量不足 - 检查是否配置了
readinessProbe,如果没有配置,Pod 启动后会立刻接收流量,但此时应用可能还未完全初始化 - 检查
minReadySeconds是否设置过短,导致 Pod 还未完全就绪就被加入 Service 的负载均衡
- 检查 Deployment 的
- 解决方法:将
maxUnavailable设置为 0,配置合理的readinessProbe,适当增加minReadySeconds,保证 Pod 完全启动后再接收流量。
更多推荐
所有评论(0)