引言:为什么需要控制器?
在Kubernetes中,Pod是最小的可部署计算对象。但直接管理Pod是一件繁琐且不靠谱的事情------当Pod所在的节点发生故障时,所有该节点上的Pod都会失败,即使节点后来恢复,你也需要手动创建新的Pod来恢复应用。
为了解决这个问题,Kubernetes引入了控制器的概念。控制器是管理Pod的中间层,它通过配置控制器来确保正确类型的、处于运行状态的Pod个数是正确的,与用户所指定的状态相一致。简单来说,你只需要告诉控制器"我想要多少个什么样的Pod",剩下的工作都由控制器来完成。
控制器的工作机制基于声明式模型:当建立控制器后,期望值会被写入etcd,kube-apiserver检索etcd中保存的期望状态,并与Pod的当前状态进行对比,如果出现差异,控制器会立即自动进行恢复。
Kubernetes提供了多种内置的工作负载资源(控制器),本文将从原理到实战,逐一介绍最常用的几种控制器。
一、ReplicaSet:最基础的副本控制器
1.1 什么是ReplicaSet?
ReplicaSet是下一代Replication Controller的替代品,官方推荐使用ReplicaSet。它与Replication Controller的唯一区别在于选择器的支持------ReplicaSet支持新的基于集合的选择器需求。
ReplicaSet的核心功能是确保在任何给定时间都有指定数量的Pod副本在运行。当Pod数量不足时,它会根据模板创建新的Pod;当Pod数量过多时,它会终止多余的Pod。
虽然ReplicaSet可以独立使用,但今天它主要被Deployment用作协调Pod创建、删除和更新的机制。
1.2 ReplicaSet的关键参数
ReplicaSet的规约(spec)包含以下关键字段:
|----------|-----------------|--------------------|
| 参数 | 类型 | 说明 |
| replicas | int32 | 指定维护的Pod数量,默认为1 |
| selector | LabelSelector | 对Pod的标签查询,应与副本计数匹配 |
| template | PodTemplateSpec | 描述Pod的对象,副本不足时据此创建 |
1.3 实战示例
bash
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: webcluster
spec:
replicas: 2
selector:
matchLabels:
app: webcluster
template:
metadata:
labels:
app: webcluster
spec:
containers:
- image: myapp:v1
name: myapp
创建ReplicaSet后,可以通过kubectl scale命令动态调整副本数量:
bash
# 扩容到4个副本
kubectl scale replicaset webcluster --replicas 4
# 缩容到2个副本
kubectl scale replicaset webcluster --replicas 2
最佳实践提示:虽然ReplicaSet可以独立使用,但官方强烈建议通过Deployment来管理ReplicaSet,而不是直接使用ReplicaSet。
二、Deployment:生产环境的首选
2.1 什么是Deployment?
Deployment是Kubernetes在V1.2版本开始引入的控制器,它为解决服务编排问题而生。Deployment控制器并不直接管理Pod,而是通过管理ReplicaSet来间接管理Pod。在Deployment中,每个ReplicaSet相当于一个版本。
Deployment为Pod和ReplicaSet提供了声明式的定义方法,是生产环境中运行无状态应用的首选方式。
2.2 典型应用场景
Deployment的典型应用场景包括:
-
创建Pod和ReplicaSet:通过声明式配置一键部署
-
滚动更新和回滚:平滑升级应用版本,出问题可快速回退
-
扩容和缩容:根据负载动态调整副本数量
-
暂停与恢复:在复杂变更时暂停滚动更新,待所有修改完成后再恢复
2.3 滚动更新与回滚实战
创建Deployment:
bash
apiVersion: apps/v1
kind: Deployment
metadata:
name: webcluster
spec:
minReadySeconds: 5
replicas: 4
selector:
matchLabels:
app: webcluster
template:
metadata:
labels:
app: webcluster
spec:
containers:
- image: myapp:v1
name: myapp
版本升级 :将镜像从myapp:v1更新为myapp:v2,重新apply即可触发滚动更新。在更新过程中,Deployment会逐步创建新版本的Pod并删除旧版本的Pod,确保服务不中断。
版本回滚 :只需要将镜像版本改回myapp:v1,再次apply即可完成回滚。
2.4 滚动更新策略详解
Deployment支持两种更新策略,默认为RollingUpdate(滚动更新):
bash
spec:
strategy:
rollingUpdate:
maxSurge: 1 # 更新时Pod数量最多比期望值多1个
maxUnavailable: 0 # 更新时不可用Pod数量不能超过0个
-
maxSurge:滚动更新开始时,新的ReplicaSet可以立即扩容,使得新旧Pod总数不超过期望Pod数量的指定比例。默认值为25%。
-
maxUnavailable:滚动更新期间,可以有多少比例的Pod处于不可用状态。默认值为25%。
2.5 暂停与恢复
在实际生产环境中,我们可能需要对Deployment做多处变更(如更新镜像、调整资源限制、修改副本数等)。如果每修改一处就触发一次滚动更新,会造成不必要的版本混乱。
解决方案是先暂停,再恢复:
bash
# 暂停滚动更新
kubectl rollout pause deployment webcluster
# 进行多处配置修改(此时不会触发更新)
kubectl apply -f deployment.yml
# 恢复滚动更新,一次性应用所有变更
kubectl rollout resume deployment webcluster
三、DaemonSet:节点级守护进程
3.1 什么是DaemonSet?
DaemonSet确保全部(或者某些)节点上运行一个Pod的副本。当有节点加入集群时,会自动为该节点新增一个Pod;当节点从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。
DaemonSet中的每个Pod执行的任务类似于传统Unix/POSIX服务器上的系统守护进程。
3.2 典型使用场景
DaemonSet的典型用法包括:
-
集群存储:在每个节点上运行glusterd、ceph等存储守护进程
-
日志收集:在每个节点上运行fluentd、logstash等日志采集代理
-
监控采集:在每个节点上运行Prometheus Node Exporter、Zabbix agent等监控组件
-
网络插件:作为集群网络方案的一部分
3.3 实战示例
bash
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-example
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
当你向集群中添加一个新节点时,如果该节点与DaemonSet的规约匹配,控制平面会自动为该DaemonSet调度一个Pod到新节点上运行。
四、Job:一次性任务
4.1 什么是Job?
Job用于执行批处理任务,保证任务的一个或多个Pod成功结束。当Job创建的Pod执行成功结束时,Job会记录成功结束的Pod数量;当成功结束的Pod达到指定数量时,Job即完成执行。
4.2 关键参数
|---------------|----------------------|
| 参数 | 说明 |
| completions | 一共需要完成的任务数 |
| parallelism | 每次并行执行的任务数 |
| backoffLimit | 运行失败后的重试次数 |
| restartPolicy | 重启策略:Never或OnFailure |
4.3 重启策略说明
-
OnFailure:Pod出现故障时重启容器而不是创建新Pod,failed次数不变
-
Never:Pod出现故障时创建新的Pod,故障Pod不会消失也不会重启,failed次数加1
-
Always:一直重启(不适用于Job)
4.4 实战示例
bash
apiVersion: batch/v1
kind: Job
metadata:
name: testjob
spec:
completions: 6 # 总共完成6个任务
parallelism: 2 # 每次并行执行2个
backoffLimit: 4 # 失败后重试4次
template:
spec:
containers:
- image: busybox
name: testjob
command: ["/bin/sh", "-c"]
args:
- |
echo this is testjob message
sleep 10
restartPolicy: Never
五、CronJob:定时任务
5.1 什么是CronJob?
CronJob创建基于时间调度的Job。它以Job控制器资源为管控对象,可以像Linux的Cron一样,在特定的时间点(反复地)运行Job任务。
5.2 实战示例
bash
apiVersion: batch/v1
kind: CronJob
metadata:
name: cronjob
spec:
schedule: "* * * * *" # 每分钟执行一次
jobTemplate:
spec:
template:
spec:
containers:
- image: busybox
name: cronjob
command:
- /bin/sh
- -c
- echo "hello from cronjob"
restartPolicy: OnFailure
六、控制器选择指南
面对不同的应用场景,如何选择合适的控制器?
|-----------------|---------|-------------------------|
| 控制器 | 适用场景 | 特点 |
| Deployment | 无状态应用 | 支持滚动更新、回滚、扩缩容,生产环境首选 |
| StatefulSet | 有状态应用 | 每个Pod有唯一标识,支持持久化存储 |
| DaemonSet | 节点级守护进程 | 每个节点运行一个Pod,适合日志、监控等 |
| Job | 一次性任务 | 任务执行完即停止,适合批处理、数据迁移 |
| CronJob | 定时任务 | 按时间表周期性执行Job,适合定时备份、报表等 |
七、最佳实践总结
-
优先使用Deployment:不要直接使用ReplicaSet,而是通过Deployment来管理。
-
合理设置滚动更新策略 :根据业务对可用性的要求,调整
maxSurge和maxUnavailable参数。默认均为25%,对于关键服务可以设置maxUnavailable: 0确保零停机。 -
善用暂停与恢复:在进行多项变更时,先暂停Deployment的滚动更新,完成所有修改后再恢复,避免产生过多版本记录。
-
为Pod打上合理的标签:标签是控制器选择和管理Pod的关键,确保标签命名规范且具有辨识度。
-
根据场景选择控制器:无状态应用用Deployment,有状态应用用StatefulSet,节点级服务用DaemonSet,任务型用Job/CronJob。
Kubernetes的控制器体系体现了声明式管理的核心思想------你只需要描述"想要什么",控制器会自动帮你实现"如何做到"。掌握这些控制器,就掌握了Kubernetes应用编排的基石。
延伸阅读: