1. Deployment 概述
Deployment 是 Kubernetes 中用于管理**无状态应用(Stateless Application)**的控制器。
它通过管理 ReplicaSet 来保证指定数量的 Pod 副本始终运行,并提供:
- Pod 自动创建与故障恢复
- 副本数量管理
- 滚动更新
- 版本记录
- 快速回滚
核心特点
① 无状态
Pod 之间没有固定关系,每个 Pod 都是独立的。
例如:
- Nginx Web 服务
- API 服务
- 微服务接口
Pod 删除后可以重新创建,但是本地数据不会保留。
如果需要保存数据,需要依赖:
- PV/PVC
- 数据库
- 外部存储
② 自动扩缩容
通过replicas指定 Pod 副本数量。
例如:
replicas: 10表示 Kubernetes 始终保证有 10 个 Pod 运行。
同时支持:
- 手动扩缩容
- HPA(Horizontal Pod Autoscaler)自动扩缩容
③ 滚动更新
更新镜像时,不会一次删除所有旧 Pod。
Deployment 会:
- 创建新的 Pod
- 等待新 Pod Ready
- 删除旧 Pod
保证服务不中断。
④ 版本管理和回滚
Deployment 会保存历史版本:
kubectl rollout history deployment webserver出现问题可以快速恢复:
kubectl rollout undo deployment webserver2. 清理环境
删除所有 Pod:
kubectl delete pods --all3. 创建 Deployment
deploy-web.yml
apiVersion: "apps/v1" # Deployment 使用 apps/v1 API kind: "Deployment" # 创建 Deployment 资源 metadata: name: "webserver" # Deployment 名称 annotations: # 记录本次部署说明,方便后续查看版本历史 kubernetes.io/change-cause: "部署镜像httpd:dns" spec: replicas: 1 # Pod 副本数量 selector: matchLabels: # Deployment 通过标签匹配管理 Pod app: "web" template: metadata: labels: # 创建出来的 Pod 标签 app: "web" spec: containers: - name: "apache-frontend" # 容器名称 # 使用 Harbor 私有仓库镜像 image: "reg.westos.org/library/httpd:dns" ports: - containerPort: 80 # 容器监听端口4. 部署 Deployment
创建资源:
kubectl apply -f deploy-web.yml查看 Deployment 详细信息:
kubectl describe deployments webserver查看 Deployment、ReplicaSet、Pod:
kubectl get deploy,rs,po -o wide5. 测试应用
访问 Service:
curl http://192.168.36.100返回:
<html> <body> <h1>No doubt, this is homepage.</h1> </body> </html>6. Pod 故障自动恢复
删除 Pod:
kubectl delete pod -l app=web再次访问:
curl http://192.168.36.100仍然可以访问。
原因:
Deployment 发现 Pod 数量不足:
期望数量 replicas=1 当前数量=0于是通过 ReplicaSet 自动创建新的 Pod。
查看:
kubectl get pods7. Deployment 扩缩容
开启实时观察:
watch -n1 'kubectl get pods'扩容
增加副本数量:
kubectl scale --replicas=10 deployment webserver查看 Pod:
kubectl get pod -o wide --show-labels查看 Service:
kubectl get svc web-service-lb -o wide查看 Endpoint:
kubectl describe endpointslice web-service-lb测试负载均衡:
for i in {1..10}; do curl 192.168.36.100/cgi-bin/hostname; done;通过 NodePort 访问:
for i in {1..10}; do curl 192.168.36.152:30000/cgi-bin/hostname; done;可以看到请求会被分发到不同 Pod。
缩容
方法1:修改 yaml
修改:
replicas: 9重新应用:
kubectl apply -f deploy-web.yml查看:
kubectl get pods -o wide方法2:直接编辑 Deployment
kubectl edit deployments webserver修改:
spec: replicas: 8查看:
kubectl get pods -o wide8. 搁置 Pod(取消 Deployment 管理)
查看 Pod 标签:
kubectl get pod -o wide --show-labels删除标签:
kubectl label pod POD-NAME app-查看 Endpoint:
kubectl describe endpoints web-service再次查看标签:
kubectl get pod --show-labels推荐方式:
添加专用标签:
kubectl label pod POD-NAME shelved=true查询:
kubectl get pod -l shelved --all-namespaces9. Deployment 更新策略
Deployment 支持两种更新方式。
① Recreate
特点:
- 先删除旧 Pod
- 再创建新 Pod
过程:
删除旧版本 Pod ↓ 创建新版本 Pod缺点:
- 会出现服务中断
适合:
- 测试环境
- 不要求高可用的服务
② RollingUpdate(默认)
滚动更新:
旧 Pod ↓ 创建新 Pod ↓ 删除旧 Pod ↓ 直到全部更新完成maxSurge
默认:
25%含义:
允许超过 replicas 数量创建的新 Pod 数。
例如:
replicas=10 maxSurge=25% 最多可以存在13个PodmaxUnavailable
默认:
25%表示更新过程中:
允许不可用 Pod 最大数量。
例如:
replicas=10 maxUnavailable=25% 最多允许2个Pod不可用10. Deployment 镜像升级
创建新版本镜像
执行:
/resources/build-dnsv2.sh脚本:
#!/bin/bash cd mkdir dnsv2 cd dnsv2 echo "Web application v2." > index.html cat > Dockerfile <<EOF FROM reg.westos.org/library/httpd:dns COPY index.html /var/www/html/ EOF docker build -t reg.westos.org/library/httpd:dnsv2 ./ docker push reg.westos.org/library/httpd:dnsv2作用:
基于旧镜像:
httpd:dns创建新版本:
httpd:dnsv211. 修改 Deployment 镜像
保证副本:
kubectl scale --replicas=10 deployment webserver查看:
kubectl get deploy webserver -o wide结果:
NAME READY UP-TO-DATE AVAILABLE IMAGE webserver 10/10 10 10 httpd:dns更新镜像
kubectl set image deployment webserver apache-frontend=reg.westos.org/library/httpd:dnsv2 --record说明:
- Deployment 更新容器镜像
--record保存更新记录
查看:
kubectl get deploy,rs,po -o wide查看详情:
kubectl describe deployment webserver测试:
[root@k8s1 deployment]# curl http://192.168.150.241 Web application v2.说明升级成功。
12. Deployment 回滚
查看历史版本
kubectl rollout history deployment webserver示例:
REVISION CHANGE-CAUSE 1 部署镜像httpd:dns 2 更新镜像httpd:dnsv2查看指定版本
查看版本1:
kubectl rollout history deployment webserver --revision=1可以看到:
Image: httpd:dns13. 修改更新速度
编辑 Deployment:
kubectl edit deployment webserver修改:
maxSurge: 1 maxUnavailable: 0含义:
最多多创建1个Pod 不允许Pod不可用适用于对稳定性要求较高的服务。
14. 回滚 Deployment
回滚到版本1:
kubectl rollout undo deployment webserver --to-revision=1查看版本:
kubectl rollout history deployment webserver测试:
for i in {1..10}; do curl 192.168.36.100/cgi-bin/hostname; done;回滚过程中:
可能同时访问到:
旧版本Pod + 新版本Pod因为 Deployment 使用滚动更新策略。
更新过程:
旧Pod | | 创建 ↓ 新Pod 同时存在 | ↓ 逐渐删除旧Pod最终所有 Pod 都会恢复到目标版本。
你说得对,我刚才整理偏成了“说明文”,不符合你之前做博客笔记的习惯。
StatefulSet(有状态部署)
1. StatefulSet概述
StatefulSet 用于管理有状态应用,例如 MySQL、Redis、Kafka 等。
与 Deployment 不同,StatefulSet 创建的 Pod 具有固定身份:
Pod名称 = StatefulSet名称 + 序号 例如: dbserver-0 dbserver-1 dbserver-2即使 Pod 删除重新创建,名称和网络标识仍然保持不变。
主要特点:
稳定网络标识
每个 Pod 有固定 DNS 名称。
适合数据库集群节点之间通信。
稳定存储
Pod 绑定 PVC。
Pod 重建后仍然使用原来的数据。
有序创建和更新
默认按照编号顺序启动:
dbserver-0 → dbserver-1 → dbserver-22. 创建 StatefulSet
StatefulSet 通常需要配合 Headless Service 使用,因为普通 Service 只提供负载均衡,而数据库场景需要访问固定节点。
创建 StatefulSet:
# 查看StatefulSet配置 cat sts-db.yml # 创建StatefulSet kubectl apply -f sts-db.yml --record # 查看StatefulSet状态 kubectl get statefulsets -o wide # 查看创建的Pod,可以看到Pod名称固定为dbserver-0 kubectl get pod -o wide配置:
apiVersion: apps/v1 kind: StatefulSet metadata: name: dbserver spec: replicas: 1 # 创建一个数据库节点 selector: matchLabels: app: db serviceName: database # 绑定Headless Service template: metadata: labels: app: db spec: containers: - name: db-backend image: reg.westos.org/library/mysql env: - name: MYSQL_ROOT_PASSWORD value: redhat ports: - containerPort: 3306创建完成后:
StatefulSet ↓ 创建Pod ↓ 生成固定名称 dbserver-0查看:
kubectl describe statefulset dbserver可以看到:
create Pod dbserver-0 in StatefulSet dbserver successful说明 StatefulSet 控制器已经创建 Pod。
3. 创建Headless Service
为什么需要 Headless Service?
普通 Service:
客户端 ↓ Service ClusterIP ↓ Pod只能访问一个虚拟地址。
数据库集群需要:
客户端 ↓ dbserver-0.database dbserver-1.database dbserver-2.database因此需要 Headless Service。
创建:
# 创建Headless Service kubectl apply -f service-db-headless.yml # 查看Service kubectl get svc -o wide # 查看对应Pod地址 kubectl get endpointslices配置:
apiVersion: v1 kind: Service metadata: name: database spec: clusterIP: None # None表示Headless Service ports: - port: 3306 name: mysql selector: app: db此时 DNS:
dbserver-0.database dbserver-1.database会直接解析到 Pod IP。
4. StatefulSet扩容
StatefulSet扩容不会像 Deployment 一样随机创建 Pod。
它按照顺序:
dbserver-0 ↓ dbserver-1 ↓ dbserver-2执行:
# 扩容数据库节点到3个 kubectl scale --replicas=3 statefulset dbserver # 查看Pod kubectl get pods -l app=db # 查看Endpoint kubectl get endpointslices结果:
dbserver-0 Running dbserver-1 Running dbserver-2 Running5. StatefulSet更新
StatefulSet升级过程:
旧版本 dbserver-2 ↓ dbserver-1 ↓ dbserver-0 逐个更新不会同时替换所有数据库节点。
查看版本:
kubectl rollout history statefulset dbserver回滚:
kubectl rollout undo statefulset dbserver --to-revision=N创建daemonsets
先开一个新的 Shell 窗口监控 Pod:
watch kubectl -n kube-system get pod -l pod-template-generation -o wideDaemonSet 配置
# cat ds-fluentd-elasticsearch.yml apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-elasticsearch namespace: kube-system labels: k8s-app: fluentd-logging spec: selector: matchLabels: name: fluentd-elasticsearch template: metadata: labels: name: fluentd-elasticsearch spec: tolerations: - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule containers: - name: fluentd-elasticsearch image: reg.westos.org/fluentd_elasticsearch/fluentd:v5.0.1 volumeMounts: - name: varlog mountPath: /var/log terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path: /var/log配置解释
kind: DaemonSet表示创建的是 DaemonSet,而不是 Deployment。
namespace: kube-system表示 DaemonSet 创建在kube-system命名空间。
selector: matchLabels: name: fluentd-elasticsearch表示 DaemonSet 根据这个标签选择和管理 Pod。
下面:
template: metadata: labels: name: fluentd-elasticsearch是 Pod 模板中的标签,要和上面的selector对应。
tolerations
tolerations: - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule作用是允许 Fluentd Pod 调度到带有:
control-plane master污点的节点。
也就是说,控制节点即使有NoSchedule污点,Fluentd 仍然可以运行。
Fluentd 容器
containers: - name: fluentd-elasticsearch image: reg.westos.org/fluentd_elasticsearch/fluentd:v5.0.1使用 Fluentd 镜像。
你自己的 Harbor 环境如果已经把镜像上传到私有仓库,可以相应使用 Harbor 中的镜像地址。
先从官方仓库quay.io/fluentd_elasticsearch/fluentd:v5.0.1拉取,然后打标签,上传到私有仓库
挂载宿主机日志目录
volumeMounts: - name: varlog mountPath: /var/log容器内部挂载/var/log。
对应宿主机:
volumes: - name: varlog hostPath: path: /var/log也就是:
宿主机 /var/log ↓ 挂载到 ↓ Fluentd Pod /var/log这样 Fluentd 就可以读取节点上的日志。
创建 DaemonSet
kubectl apply -f ds-fluentd-elasticsearch.yml --record创建之后查看版本历史:
kubectl -n kube-system rollout history daemonset fluentd-elasticsearch结果:
daemonset.apps/fluentd-elasticsearch REVISION CHANGE-CAUSE 1 kubectl apply --filename=ds-fluentd-elasticsearch.yml --record=true说明当前 DaemonSet 已经产生第一个版本:
REVISION 1DaemonSet 更新策略
DaemonSet 有两种更新策略。
1. OnDelete
OnDelete含义:
DaemonSet 模板发生变化后,不会自动更新已有 Pod,只有手动删除旧 Pod 后,DaemonSet 才会重新创建新的 Pod。
例如:
旧 Pod ↓ 不自动删除 ↓ 手动 kubectl delete pod ↓ DaemonSet 创建新 Pod2. RollingUpdate
RollingUpdate这是默认更新策略。
DaemonSet 模板更新后:
旧 Pod ↓ 逐步删除 ↓ 创建新 Pod整个更新过程中:
每个节点最多运行一个该 DaemonSet 的 Pod。
所以可以理解为:
Node1 → 旧 Pod → 新 Pod Node2 → 旧 Pod → 新 Pod Node3 → 旧 Pod → 新 Pod而不是同一个节点同时长期运行多个版本的 DaemonSet Pod。
更新和回滚 DaemonSet
准备更新后的 YAML:
# cat ds-fluentd-elasticsearch-update.yml apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-elasticsearch namespace: kube-system labels: k8s-app: fluentd-logging spec: selector: matchLabels: name: fluentd-elasticsearch template: metadata: labels: name: fluentd-elasticsearch spec: tolerations: - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule containers: - name: fluentd-elasticsearch image: reg.westos.org/fluentd_elasticsearch/fluentd:v5.0.1 resources: limits: memory: 200Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: varlog mountPath: /var/log terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path: /var/log这里相比之前的配置,增加了:
resources: limits: memory: 200Mi requests: cpu: 100m memory: 200Mi用于设置 Fluentd Pod 的资源请求和限制。
1. 应用更新
kubectl apply -f ds-fluentd-elasticsearch-update.yml --recordDaemonSet 模板发生变化后,会按照更新策略进行更新。
2. 查看 DaemonSet 版本
kubectl -n kube-system rollout history daemonsets fluentd-elasticsearch可以看到 DaemonSet 的历史版本。
3. 查看 ControllerRevision
kubectl -n kube-system get controllerrevisionsControllerRevision用于保存控制器的历史版本信息,DaemonSet 的版本历史可以通过它进行管理。
4. 查看指定版本
例如查看第 1 个版本:
kubectl -n kube-system rollout history daemonsets fluentd-elasticsearch --revision=1可以查看该版本保存的配置。
5. 回滚到指定版本
kubectl -n kube-system rollout undo daemonsets fluentd-elasticsearch --to-revision=1表示:
当前版本 ↓ 回滚 ↓ Revision 1回滚后可以再次查看:
kubectl -n kube-system rollout history daemonsets fluentd-elasticsearch更新和回滚 daemonset
Kubernetes Job 与 CronJob
Job 和 CronJob 都属于 Kubernetes 的批处理任务控制器,主要用于执行一些不需要长期运行的任务。
可以先记住两者关系:
Job = 执行一次任务 CronJob = 按照时间周期,反复创建 Job一、Job(一次性任务)
1. 核心作用
Job 用于运行一次性任务,例如:
- 数据备份
- 数据迁移
- 批量计算
- 日志分析
- 生成报表
- 图片处理
Job 的目标不是让 Pod 一直运行,而是:
创建 Job ↓ 创建 Pod ↓ 执行任务 ↓ 任务成功 ↓ Pod Completed ↓ Job Completed所以 Job 和 Deployment 的区别可以简单理解为:
Deployment = 让程序一直运行 Job = 让任务执行完就结束2. Job 的主要特点
一次性
任务完成后:
Pod → Completed Job → Completed不会像 Deployment 一样一直保持 Pod 运行。
失败自动重试
如果 Pod 执行失败,Job 可以重新创建 Pod 执行任务。
通过:
backoffLimit: 4控制失败后的重试次数。
支持并行执行
通过:
parallelism控制同时运行多少个 Pod。
通过:
completions控制总共需要成功完成多少次任务。
例如:
completions: 6 parallelism: 2可以理解为:
总共需要成功 6 次 ↓ 每次最多同时运行 2 个 Pod ↓ 完成 6 次后 Job 完成二、Job 实例
apiVersion: batch/v1 kind: Job metadata: name: pi spec: completions: 6 # 总需完成 6 次任务 parallelism: 2 # 每次并行运行 2 个 Pod template: spec: containers: - name: pi image: reg.westos.org/library/perl:5.34.0 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4 # 最多重试 4 次(失败时)这个 Job:
Job: pi │ ├── Pod ├── Pod ├── Pod ├── Pod ├── Pod └── Pod最终需要有6 次成功完成。
由于:
parallelism: 2所以同时最多运行 2 个任务 Pod。
3. 创建 Job
# kubectl apply -f job.yml4. 监控 Job Pod
# watch kubectl get pod -l job-name也可以:
# kubectl get pod -l job-name例如:
NAME READY STATUS RESTARTS AGE pi-58r8g 0/1 Completed 0 45s pi-59lsg 0/1 Completed 0 44s pi-6sjgn 0/1 Completed 0 59s pi-b8q4x 0/1 Completed 0 52s pi-bm699 0/1 Completed 0 51s pi-j96pp 0/1 Completed 0 59s这里:
STATUS = Completed表示对应 Pod 中的任务已经执行成功。
6 个 Pod 都Completed,说明:
completions: 6已经完成。
5. 查看任务输出
# kubectl logs pi-58r8g可以查看这个任务 Pod 执行命令产生的输出。
6. 删除 Job
# kubectl delete jobs.batch pi删除 Job。
三、Job 中几个重要参数
| 参数 | 作用 |
|---|---|
completions | 总共需要成功完成多少次 |
parallelism | 同时运行多少个 Pod |
backoffLimit | 任务失败后的重试次数 |
restartPolicy | Pod 内容器失败后的重启策略 |
例如:
completions: 6 parallelism: 2 backoffLimit: 4就是:
总共成功 6 次,同时最多跑 2 个,失败后按照 Job 的重试机制处理,最多允许 4 次失败重试。
四、CronJob(定时任务)
1. 核心作用
CronJob 用于按照时间规则周期性运行任务。
它类似 Linux 中的:
crontab例如:
每天凌晨 3 点备份数据库 每小时生成一次报表 每天清理日志CronJob 的核心关系:
CronJob ↓ 按照 schedule 到时间 ↓ 创建 Job ↓ Job 创建 Pod ↓ Pod 执行任务 ↓ 任务完成所以一定要记住:
CronJob 不直接执行任务 ↓ CronJob 创建 Job ↓ Job 创建 Pod ↓ Pod 执行任务五、CronJob 的主要特点
1. 定时触发
通过:
schedule:定义执行时间。
例如:
schedule: "0 3 * * *"表示:
每天凌晨 3 点执行你这个实验:
schedule: "* * * * *"表示:
每分钟执行一次2. 基于 Job
CronJob 每到一个执行时间,就创建一个 Job。
例如:
12:00 ↓ Job 1 ↓ Pod 1 ↓ Completed 12:01 ↓ Job 2 ↓ Pod 2 ↓ Completed 12:02 ↓ Job 3 ↓ Pod 3 ↓ Completed所以执行一段时间后,会看到多个已经完成的 Job/Pod。
3. 容错机制
CronJob 可以通过:
startingDeadlineSeconds设置任务启动截止时间,用于处理错过计划执行时间的情况。
六、CronJob 实例
apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: "* * * * *" # 每分钟运行一次任务 jobTemplate: spec: template: spec: containers: - name: hello image: reg.westos.org/library/busybox:1.30.1 imagePullPolicy: IfNotPresent command: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster restartPolicy: OnFailure这里最重要的是:
kind: CronJob说明这是 CronJob。
schedule: "* * * * *"表示每分钟执行一次。
jobTemplate:表示:
到时间以后,按照这个模板创建 Job。
Job 再创建 Pod 执行:
date echo Hello from the Kubernetes cluster七、创建 CronJob
# kubectl apply -f cronjob.yml查看 CronJob:
# kubectl describe cronjobs.batch hello八、查看 CronJob 创建的 Job/Pod
查看 Pod:
# kubectl get pod -l job-name例如:
NAME READY STATUS RESTARTS AGE hello-29369598-m5jw9 0/1 Completed 0 2m36s hello-29369599-mx8j9 0/1 Completed 0 96s hello-29369600-7mnkd 0/1 Completed 0 36s可以看到不同时间创建了不同的任务 Pod。
因为:
schedule: "* * * * *"所以大约每分钟会产生一个 Job。
关系可以记成:
CronJob hello │ ├── Job 29369598 │ └── Pod │ ├── Job 29369599 │ └── Pod │ └── Job 29369600 └── Pod九、查看任务输出
例如:
# kubectl logs hello-29369599-mx8j9输出:
Mon Nov 3 13:19:00 UTC 2025说明这个 CronJob 创建的 Pod 已经执行了任务。
十、Job 和 CronJob 的区别
这是面试中非常容易问的。
| 对比 | Job | CronJob |
|---|---|---|
| 作用 | 执行一次任务 | 周期性执行任务 |
| 是否定时 | ❌ | ✅ |
| 是否创建 Pod | ✅ | 间接创建 |
| 是否基于 Job | 本身就是 Job | ✅ |
| 典型场景 | 数据迁移、批量计算 | 定时备份、日志清理 |
| 执行完成 | Job Completed | 本次 Job Completed,下一周期继续创建 |
Kubernetes 存储
官方文档:
卷 | Kubernetes
容器内部存储的生命周期是短暂的,会随着容器环境的销毁而销毁,具有不稳定性。如果多个容器希望共享同一份存储,则仅仅依赖容器本身是很难实现的。
在 Kubernetes 中,将容器应用所需的存储资源抽象为Volume(存储卷)。
Volume 的特点:
- Volume 与Pod 绑定,而不是与单独的容器绑定。
- Volume 与 Pod 具有相同的生命周期。
- 容器通过
volumeMounts将 Volume 挂载到容器中的目录或文件。 - Volume 的具体类型以及由哪个系统提供,对容器应用来说是透明的。
简单理解:
Pod │ ├── Container1 ──┐ │ │ ├── Container2 ──┤── Volume │ │ └────────────────┘一、emptyDir 卷
emptyDir是 Kubernetes 提供的一种临时存储。
当 Pod 被调度到 Node 时,Kubernetes 创建一个空目录,因此叫Empty Directory(空目录)。
特点:
- Pod 启动时目录为空。
- 同一个 Pod 中的多个容器可以共享。
- 存储空间来自 Node 本地 kubelet 根目录(通常是根磁盘)或者内存。
- Pod 删除后,emptyDir 中的数据也会删除。
Pod 创建 ↓ 创建 emptyDir ↓ 多个容器共享数据 ↓ Pod 删除 ↓ emptyDir 删除emptyDir 多容器共享实验
# cat job-emptydir.yml apiVersion: batch/v1 kind: Job metadata: name: convert spec: backoffLimit: 3 ttlSecondsAfterFinished: 100 # 100秒后自动回收job和pod template: spec: restartPolicy: OnFailure containers: - image: reg.westos.org/library/centos:7 name: create-files volumeMounts: - mountPath: /cache name: cache-volume command: - sh - -c - touch /cache/{1..30};touch /cache/trigger - image: reg.westos.org/library/centos:7 name: generate-logs volumeMounts: - mountPath: /logs name: cache-volume command: - sh - -c - until test -f /logs/trigger;do sleep 1;done;find /logs/ volumes: - name: cache-volume emptyDir: {}这里重点看
两个容器:
create-files ↓ /cachegenerate-logs ↓ /logs虽然挂载路径不同,但是它们使用的是同一个:
name: cache-volume对应:
emptyDir: {}所以两个容器实际上共享同一个目录。
第一个容器:
touch /cache/{1..30} touch /cache/trigger创建文件。
第二个容器:
until test -f /logs/trigger;do sleep 1;done不断检查trigger是否存在。
因为/cache和/logs使用的是同一个emptyDir,所以第一个容器创建的:
/cache/trigger第二个容器可以通过:
/logs/trigger看到。
注意
提前上传镜像:
centos:7然后:
# kubectl apply -f job-emptydir.yml # kubectl get pod NAME READY STATUS RESTARTS AGE convert-4f6v8 0/2 Completed 0 5s查看所有容器的日志:
# kubectl logs convert-4f6v8 --all-containers二、emptyDir 使用内存
可以将:
emptyDir:设置:
medium: Memory告诉 Kubernetes 使用tmpfs(基于内存的文件系统)。
特点:
- 速度快。
- Node 重启后数据会被清除。
- 写入的数据会计算到容器的内存消耗中。
- 可以通过
sizeLimit设置大小限制。
# cat emptydir-tmpfs.yml apiVersion: v1 kind: Pod metadata: name: emptydir-tmpfs spec: containers: - name: webapp image: reg.westos.org/library/nginx:1.29 volumeMounts: - mountPath: /usr/share/nginx/html name: cache-volume volumes: - name: cache-volume emptyDir: medium: Memory sizeLimit: 100Mi这里:
medium: Memory表示使用内存。
sizeLimit: 100Mi表示该 Volume 最大使用100Mi。
创建:
# kubectl apply -f emptydir-tmpfs.yml # kubectl exec -it emptydir-tmpfs -- bash进入容器后测试:
root@emptydir-tmpfs:/# dd if=/dev/zero of=/usr/share/nginx/html/bigfile bs=1M count=200 dd: error writing '/usr/share/nginx/html/bigfile': No space left on device 101+0 records in 100+0 records out 104857600 bytes (105 MB, 100 MiB) copied, 0.0609732 s, 1.7 GB/s root@emptydir-tmpfs:/# cd /usr/share/nginx/html root@emptydir-tmpfs:/usr/share/nginx/html# du -h bigfile 100M bigfile这里虽然尝试写入200M:
1M × 200 = 200M但是 Volume 限制:
100Mi所以写到约100M后出现:
No space left on device说明sizeLimit生效。
三、hostPath 卷
hostPath用于:
将 Node 文件系统中的目录或文件挂载到容器内部。
与emptyDir最大的区别:
emptyDir Pod 删除 → 数据删除 hostPath Pod 删除 → Node 上的数据仍然存在只要:
- Node 还存在;
- 对应路径没有被删除;
数据就会保留。
例如:
Node └── /backup/etcd ↕ hostPath ↕ Pod └── /backup/etcd四、hostPath 实现 etcd 备份
这个案例使用:
CronJob + hostPath定期备份 Kubernetes 的 etcd。
# cat etcd-backup.yml apiVersion: batch/v1 kind: CronJob metadata: name: etcd-backup spec: schedule: "*/5 * * * *" concurrencyPolicy: Forbid jobTemplate: spec: ttlSecondsAfterFinished: 100 template: spec: nodeSelector: kubernetes.io/hostname: "k8s-master" #填自己的主机名 tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule hostNetwork: true restartPolicy: Never volumes: - name: etcd-certs hostPath: path: /etc/kubernetes/pki - name: etcd-data hostPath: path: /backup/etcd type: DirectoryOrCreate containers: - name: etcd-client image: reg.westos.org/library/etcd:v3.4.13 args: - /bin/sh - -ec - ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/apiserver-etcd-client.crt --key=/etc/kubernetes/pki/apiserver-etcd-client.key --endpoints https://127.0.0.1:2379 snapshot save /backup/etcd/etcd-$(date +%s).bak # - sleep 100000 volumeMounts: - name: etcd-data mountPath: /backup/etcd - name: etcd-certs mountPath: /etc/kubernetes/pki readOnly: true关键配置
1. 固定运行节点
nodeSelector: kubernetes.io/hostname: "k8s-master"让 Pod 运行在k8s-master。
因为需要访问这个节点上的:
/etc/kubernetes/pki /backup/etcd2. 允许调度到控制平面
tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule控制平面节点通常存在NoSchedule污点,因此需要对应的容忍配置。
3. 挂载 etcd 证书
- name: etcd-certs hostPath: path: /etc/kubernetes/pki挂载:
- name: etcd-certs mountPath: /etc/kubernetes/pki readOnly: true即:
Node: /etc/kubernetes/pki ↓ Container: /etc/kubernetes/pkireadOnly: true表示容器只能读取,不能修改证书。
4. 挂载备份目录
- name: etcd-data hostPath: path: /backup/etcd type: DirectoryOrCreate- name: etcd-data mountPath: /backup/etcd其中:
type: DirectoryOrCreate表示如果 Node 上没有/backup/etcd,则创建该目录。
创建 CronJob
# kubectl apply -f etcd-backup.yml # kubectl get pod NAME READY STATUS RESTARTS AGE etcd-backup-29369685-z4drt 0/1 Completed 0 5s查看日志:
# kubectl logs etcd-backup-29369685-z4drt然后在k8s-master上查看 etcd 备份:
# ll /backup/etcd/ total 11760 -rw------- 1 root root 6017056 Nov 3 22:45 etcd-1762181102.bak备份文件:
etcd-1762181102.bak最终实际保存在:
k8s-master:/backup/etcd/因为 Pod 中的:
/backup/etcd实际上对应 Node 上的:
/backup/etcd