目录

Kubernetes 控制器核心实战手册

一 什么是控制器

核心定义(原内容 + 补充)

自主式 Pod vs 控制器管理 Pod(原内容 + 补充)

官方文档链接

二 控制器常用类型

三 replicaset 控制器

3.1 replicaset 功能(原内容 + 补充)

3.2 replicaset 参数说明

3.3 replicaset 示例(原代码 100% 完整保留,新增逐行解析)

核心代码逐行解析(Line-by-Line Breakdown)

最容易踩的坑(Gotchas)

企业级生产应用(Enterprise Scenario)

课后防宕机指南(Troubleshooting)

四 deployment 控制器

4.1 deployment 控制器的功能(原内容 + 补充)

4.2 deployment 控制器示例

核心代码逐行解析(Line-by-Line Breakdown)

最容易踩的坑(Gotchas)

4.2.1 版本迭代

4.2.2 版本回滚(原内容完整保留,新增解析)

4.2.3 滚动更新策略(原内容完整保留,新增解析)

4.2.4 暂停及恢复(原内容完整保留,新增解析)

企业级生产应用(Enterprise Scenario)

课后防宕机指南(Troubleshooting)



一 什么是控制器

核心定义(原内容 + 补充)

观察 (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.

代码逐行解释

  1. cd controler/:进入控制器实验目录
  2. kubectl run webserver --image myapp:v1:创建自主式 Pod,直接由 APIServer 管理,无控制器介入
  3. kubectl get pods:查看 Pod 状态,显示已正常运行
  4. kubectl delete pods webserver:删除自主式 Pod
  5. 再次查看 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 替代仅支持基于等式的标签选择器,无集合选择能力
ReplicaSetReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行支持基于集合的标签选择器,是 Deployment 的底层组件
Deployment一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力生产环境无状态服务首选,支持滚动更新、回滚、扩缩容
DaemonSetDaemonSet 确保全指定节点上运行一个 Pod 的副本用于部署节点级服务,如日志采集、监控代理
StatefulSetStatefulSet 是用来管理有状态应用的工作负载 API 对象为 Pod 提供稳定的网络标识、持久化存储、有序部署 / 更新
Job执行批处理任务,仅执行一次任务,保证任务的一个或多个 Pod 成功结束用于一次性任务,如数据备份、报表生成
CronJobCron 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 参数说明

参数名称字段类型参数说明底层触发动作
specObject详细定义对象,固定值就写 Spec告诉 APIServer 该资源的具体规格定义,是所有 K8s 资源的必填字段
spec.replicasinteger指定维护 pod 数量写入 etcd 作为期望状态,ReplicaSet 控制器会循环对比实际 Pod 数量与该值
spec.selectorObjectSelector 是对 pod 的标签查询,与 pod 数量匹配控制器通过该选择器筛选出自己管理的 Pod,是控制器与 Pod 关联的唯一纽带
spec.selector.matchLabelsstring指定 Selector 查询标签的名称和值,以 key : value 方式指定控制器会列出所有带有该标签的 Pod,统计数量并与 replicas 对比
spec.templateObject指定对 pod 的描述信息,比如 lab 标签,运行容器的信息等当需要创建新 Pod 时,控制器会完全按照该模板生成 Pod
spec.template.metadataObject指定 pod 属性定义 Pod 的元数据,包括标签、注解等
spec.template.metadata.labelsstring指定 pod 标签必须与 spec.selector.matchLabels 完全一致,否则控制器无法管理 Pod
spec.template.specObject详细定义对象定义 Pod 的运行规格,包括容器、存储、网络等
spec.template.spec.containerslistSpec 对象的容器列表定义定义 Pod 中运行的容器列表,支持多个容器
spec.template.spec.containers.namestring指定容器名称容器在 Pod 内的唯一标识,用于日志、监控等
spec.template.spec.containers.imagestring指定容器镜像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)

行号代码底层触发动作
1apiVersion: apps/v1告诉 APIServer 该资源属于apps/v1 API 组,APIServer 将请求路由到 apps 组的控制器处理
2kind: ReplicaSet指定资源类型为 ReplicaSet,APIServer 调用 ReplicaSet 控制器的同步逻辑
3-4metadata: name: replicaset在 default 命名空间下创建名为 replicaset 的 ReplicaSet 资源,名称必须符合 RFC 1123 规范(全小写、数字、-、.)
5-6spec: replicas: 2将期望副本数 2 写入 etcd,ReplicaSet 控制器会持续监控实际 Pod 数量
7-9selector: matchLabels: app: myapp控制器会筛选所有带有app=myapp标签的 Pod,作为自己管理的对象
10-13template: metadata: labels: app: myapp定义新 Pod 的标签,必须与 selector 完全一致,否则控制器会无限创建 Pod
14-17spec: containers: image: myapp:v1 name: myapp定义 Pod 中运行的容器,kubelet 会拉取 myapp:v1 镜像并启动名为 myapp 的容器
最容易踩的坑(Gotchas)
  1. 标签不匹配spec.selector.matchLabelsspec.template.metadata.labels不一致,会导致控制器无法找到自己创建的 Pod,从而无限创建新 Pod,最终耗尽集群资源。
  2. 名称包含大写字母:metadata.name 必须全小写,否则会报Invalid value: "ReplicaSet": a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters错误。
  3. 镜像名称错误:镜像名称拼写错误或仓库不可达,会导致 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 带来的版本管理开销。

进阶优化空间

  1. 与 HPA 联动:通过 HorizontalPodAutoscaler 根据 CPU、内存或自定义指标自动调整 ReplicaSet 的副本数,实现弹性伸缩。
  2. Pod 反亲和性:配置 Pod 反亲和性,让 ReplicaSet 管理的 Pod 分散在不同的节点上,避免单点故障。
  3. 资源限制:为容器配置 requests 和 limits,避免 Pod 占用过多资源影响其他服务。
  4. 镜像拉取策略:设置imagePullPolicy: IfNotPresent,避免每次启动 Pod 都拉取镜像,加快启动速度。

课后防宕机指南(Troubleshooting)

  1. 错误现象:kubectl get rs 显示 DESIRED=2,CURRENT=100+,READY=0,集群资源耗尽

    • 报错信息:无明确报错,但节点 CPU / 内存使用率 100%,无法创建新 Pod
    • 排查思路:执行kubectl describe rs <rs-name>查看 Events,检查spec.selector.matchLabelsspec.template.metadata.labels是否完全一致。99% 的情况是标签不匹配导致控制器无限创建 Pod。
    • 解决方法:修改 YAML 文件中的标签,使其一致,然后重新 apply,再手动删除多余的 Pod。
  2. 错误现象: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)

行号代码底层触发动作
1apiVersion: apps/v1告诉 APIServer 该资源属于apps/v1 API 组,路由到 Deployment 控制器处理
2kind: Deployment指定资源类型为 Deployment,APIServer 调用 Deployment 控制器的同步逻辑
3-4metadata: name: deployment在 default 命名空间下创建名为 deployment 的 Deployment 资源
5-6spec: replicas: 4期望副本数 4,Deployment 控制器会创建一个 ReplicaSet,其 replicas 为 4
7-9selector: matchLabels: app: myappDeployment 通过该选择器筛选自己管理的 ReplicaSet,ReplicaSet 再通过该选择器筛选 Pod
10-13template: metadata: labels: app: myapp定义 Pod 模板,Deployment 会将该模板传递给 ReplicaSet,用于创建 Pod
14-17spec: containers: image: myapp:v1 name: myapp定义容器规格,与 ReplicaSet 中的容器定义一致
最容易踩的坑(Gotchas)
  1. replicas 字段缺失:原示例中replicas:后面没有写数字,会导致默认创建 1 个 Pod,而不是期望的 4 个。
  2. selector 与 template 标签不一致:与 ReplicaSet 一样,标签不匹配会导致 Deployment 无法管理 ReplicaSet,从而无限创建新的 ReplicaSet。
  3. 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 配合以下组件可以实现高可用、高性能的服务部署:

  1. 与 HPA 联动:根据 CPU、内存、QPS 等指标自动扩缩容,应对流量洪峰。
  2. 与 Service/Ingress 联动:通过 Service 提供稳定的访问入口,Ingress 实现七层负载均衡和域名路由。
  3. 多可用区部署:配置 Pod 拓扑分布约束,让 Pod 分散在不同的可用区,避免单可用区故障导致服务中断。

进阶优化空间

  1. 金丝雀发布:通过修改 Deployment 的maxSurgemaxUnavailable,先发布少量新版本 Pod,验证无误后再全量更新。
  2. 蓝绿部署:创建两个独立的 Deployment,分别对应蓝绿版本,通过切换 Service 的标签选择器实现流量切换。
  3. 镜像预热:提前将镜像拉取到所有节点,避免更新时因为拉取镜像导致 Pod 启动缓慢。
  4. 健康检查:配置livenessProbereadinessProbe,及时发现故障 Pod 并重启,避免将流量转发到不可用的 Pod。
  5. PodDisruptionBudget(PDB):配置 PDB,保证更新或节点维护时至少有 N 个 Pod 可用,避免服务中断。
  6. 资源超配:根据业务特点合理配置 requests 和 limits,提高集群资源利用率。

课后防宕机指南(Troubleshooting)

  1. 错误现象:Deployment 更新卡住,一直显示Progressing状态,超过progressDeadlineSeconds(默认 600 秒)后报错

    • 报错信息kubectl describe deployment <deployment-name>显示ProgressDeadlineExceeded
    • 排查思路
      1. 执行kubectl get pods查看是否有 Pod 处于ImagePullBackOffCrashLoopBackOff状态
      2. 执行kubectl describe pod <pod-name>查看 Pod 的 Events,确认是镜像问题、资源问题还是健康检查问题
      3. 检查节点资源是否充足,是否有节点处于NotReady状态
    • 解决方法:根据具体问题修复,例如修正镜像名称、增加节点资源、调整健康检查参数。
  2. 错误现象:更新时服务出现 503 错误,部分请求失败

    • 报错信息:客户端访问返回 503 Service Unavailable
    • 排查思路
      1. 检查 Deployment 的maxUnavailable是否设置过大,导致更新时可用 Pod 数量不足
      2. 检查是否配置了readinessProbe,如果没有配置,Pod 启动后会立刻接收流量,但此时应用可能还未完全初始化
      3. 检查minReadySeconds是否设置过短,导致 Pod 还未完全就绪就被加入 Service 的负载均衡
    • 解决方法:将maxUnavailable设置为 0,配置合理的readinessProbe,适当增加minReadySeconds,保证 Pod 完全启动后再接收流量。

更多推荐