☰
Kubernetes 工作负载
2026/9/26 9:42:41 网站建设 项目流程

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 会:

  1. 创建新的 Pod
  2. 等待新 Pod Ready
  3. 删除旧 Pod

保证服务不中断。

④ 版本管理和回滚

Deployment 会保存历史版本:

kubectl rollout history deployment webserver

出现问题可以快速恢复:

kubectl rollout undo deployment webserver

2. 清理环境

删除所有 Pod:

kubectl delete pods --all

3. 创建 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 wide

5. 测试应用

访问 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 pods

7. 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 wide


8. 搁置 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-namespaces

9. Deployment 更新策略

Deployment 支持两种更新方式。

① Recreate

特点:

  • 先删除旧 Pod
  • 再创建新 Pod

过程:

删除旧版本 Pod ↓ 创建新版本 Pod

缺点:

  • 会出现服务中断

适合:

  • 测试环境
  • 不要求高可用的服务

② RollingUpdate(默认)

滚动更新:

旧 Pod ↓ 创建新 Pod ↓ 删除旧 Pod ↓ 直到全部更新完成

maxSurge

默认:

25%

含义:

允许超过 replicas 数量创建的新 Pod 数。

例如:

replicas=10 maxSurge=25% 最多可以存在13个Pod

maxUnavailable

默认:

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:dnsv2

11. 修改 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:dns

13. 修改更新速度

编辑 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-2

2. 创建 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 Running

5. 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 wide

DaemonSet 配置

# 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 1

DaemonSet 更新策略

DaemonSet 有两种更新策略。

1. OnDelete

OnDelete

含义:

DaemonSet 模板发生变化后,不会自动更新已有 Pod,只有手动删除旧 Pod 后,DaemonSet 才会重新创建新的 Pod。

例如:

旧 Pod ↓ 不自动删除 ↓ 手动 kubectl delete pod ↓ DaemonSet 创建新 Pod

2. 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 --record

DaemonSet 模板发生变化后,会按照更新策略进行更新。


2. 查看 DaemonSet 版本

kubectl -n kube-system rollout history daemonsets fluentd-elasticsearch

可以看到 DaemonSet 的历史版本。


3. 查看 ControllerRevision

kubectl -n kube-system get controllerrevisions

ControllerRevision用于保存控制器的历史版本信息,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.yml

4. 监控 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任务失败后的重试次数
restartPolicyPod 内容器失败后的重启策略

例如:

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 的区别

这是面试中非常容易问的。

对比JobCronJob
作用执行一次任务周期性执行任务
是否定时❌✅
是否创建 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 ↓ /cache
generate-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/etcd

2. 允许调度到控制平面

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/pki

readOnly: 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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询