当前位置: 首页 > news >正文

K8s学习笔记(十二) volume存储卷

在 Kubernetes 中,Volume(存储卷) 是解决容器存储问题的核心组件。它的核心作用是:为 Pod 中的容器提供 “持久化” 或 “共享” 的存储空间,弥补容器文件系统的临时性(容器重启后数据丢失)和隔离性(同一 Pod 内容器无法直接共享文件)的缺陷。

1 为什么需要 Volume?

容器的文件系统是 “临时的、隔离的”,这会导致 3 个问题:

  1. 数据丢失:容器重启后,内部文件会被重置(比如 Nginx 容器重启,之前上传的静态文件会消失)。
  2. 跨容器共享:同一 Pod 内的多个容器(如 “应用容器 + 日志收集容器”)需要共享数据(如日志文件),但容器间默认无法直接访问对方的文件系统。
  3. 持久化存储:需要将数据长期保存(如数据库数据),即使 Pod 被删除,数据也不能丢失。

Volume 正是为解决这些问题而生:

  • 它是Pod 级别的存储资源(与 Pod 生命周期绑定,Pod 删除后 Volume 才会被清理,除非是持久化存储)。
  • 可以被 Pod 内的多个容器同时挂载,实现数据共享。
  • 支持多种存储类型(本地磁盘、网络存储、配置文件等),灵活满足不同场景。

2 Volume 的核心概念(必懂)

  1. 生命周期:与 Pod 一致(Pod 创建时 Volume 被创建,Pod 删除时 Volume 被清理)。但注意:若 Volume 使用的是外部存储(如 NFS、PV),则底层数据会保留(仅 K8s 的 Volume 对象被删除)。
  2. 定义方式:
    • 在 Pod 的spec.volumes中定义 “卷”(说明卷的类型、来源等)。
    • 在容器的spec.containers.volumeMounts中定义 “挂载”(说明将卷挂载到容器内的哪个路径)。
  3. 核心关联volumes.namevolumeMounts.name必须一致,用于绑定卷和挂载点。

3 常见 Volume 类型

K8s 支持数十种 Volume 类型,这里按 “使用场景” 挑出最常用的 6 种,掌握它们就能应对 80% 的需求。

3.1 emptyDir:Pod 内临时共享存储(最基础)

  • 特点:在 Pod 创建时自动创建的临时目录,存储在节点的本地磁盘(或内存),Pod 删除后数据丢失
  • 适用场景:同一 Pod 内容器间临时共享数据(如日志缓存、临时计算结果)。
示例:两个容器共享 emptyDir

创建一个 Pod,包含 “写文件容器” 和 “读文件容器”,通过 emptyDir 共享数据:

# pod-emptyDir.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-emptyDir
spec:containers:- name: writer  # 写文件的容器image: busybox:1.35command: ["sh", "-c", "while true; do echo $(date) > /shared/data.txt; sleep 5; done"]  # 每5秒写当前时间到文件volumeMounts:- name: shared-vol  # 挂载名为shared-vol的卷mountPath: /shared  # 挂载到容器内的/shared目录- name: reader  # 读文件的容器image: busybox:1.35command: ["sh", "-c", "while true; do cat /shared/data.txt; sleep 5; done"]  # 每5秒读取文件volumeMounts:- name: shared-vol  # 必须和volumes.name一致mountPath: /shared  # 挂载到容器内的/shared目录volumes:  # 定义卷- name: shared-vol  # 卷的名字,与上面的volumeMounts.name对应emptyDir:medium: ""  # 存储介质:默认磁盘;设为"Memory"则使用内存(tmpfs,速度快但容量受限于内存)
操作与验证:
# 创建Pod
kubectl apply -f pod-emptyDir.yaml# 查看reader容器的输出(会每隔5秒显示当前时间)
kubectl logs -f pod-emptyDir -c reader
# 输出示例:
# Fri Oct  2 15:30:00 UTC 2025
# Fri Oct  2 15:30:05 UTC 2025# 验证数据共享:进入writer容器,查看/shared目录
kubectl exec -it pod-emptyDir -c writer -- sh
ls /shared  # 会看到data.txt,内容与reader输出一致

3.2 hostPath:挂载节点本地目录(测试用)

  • 特点:将 Pod 所在节点的本地文件或目录挂载到容器内,数据会保留在节点上(Pod 删除后数据不丢,但 Pod 调度到其他节点时无法访问)。
  • 适用场景:测试环境中需要持久化数据(如本地数据库测试),或需要访问节点文件(如挂载节点的/var/log收集日志)。
示例:挂载节点的/opt/hostpath-data目录
# pod-hostPath.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-hostPath
spec:containers:- name: test-containerimage: busybox:1.35command: ["sh", "-c", "while true; do echo $(date) >> /data/hostpath.log; sleep 10; done"]volumeMounts:- name: hostpath-volmountPath: /data  # 容器内的/data目录映射到节点的/opt/hostpath-datavolumes:- name: hostpath-volhostPath:path: /opt/hostpath-data  # 节点上的目录type: DirectoryOrCreate  # 目录不存在则自动创建(支持File、Directory等类型)
操作与验证:
# 创建Pod
kubectl apply -f pod-hostPath.yaml# 找到Pod所在节点
kubectl get pod pod-hostPath -o wide
# 输出示例(NODE字段为节点名):
# NAME           READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE
# pod-hostPath   1/1     Running   0          1m    10.200.166.182   192.168.121.111     <none># 登录节点k8s-node-1,查看/opt/hostpath-data目录
ssh node1
cat /opt/hostpath-data/hostpath.log  # 会看到持续追加的时间日志(证明数据持久化到节点)

注意:hostPath 的局限性 —— 多节点集群中,若 Pod 调度到其他节点,会访问新节点的/opt/hostpath-data(数据不共享),生产环境慎用!

3.3 nfs:跨节点共享的网络存储

  • 特点:挂载 NFS 服务器的共享目录,支持多节点 Pod 共享数据(无论 Pod 调度到哪个节点,都能访问同一 NFS 目录)。
  • 适用场景:需要跨节点共享数据的场景(如多 Pod 写日志、静态资源共享)。
部署 NFS 服务器

NFS 服务器 IP 为192.168.121.109,共享目录为/data/k8sdata/chenjun666(需配置允许 K8s 节点访问)。

apt install nfs-servermkdit -p /data/k8sdata/chenjun666vim /etc/export
/data/k8sdata *(rw,no_root_squash)systemctl restart nfs-server.servicesystemctl enable nfs-server.servicesystemctl status nfs-server.service# 检查挂载
root@master1:~/yaml/volume_pod# showmount -e 192.168.121.109
Export list for 192.168.121.109:
/data/k8sdata *
示例:Pod 挂载 NFS 共享目录
# pod-nfs.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-nfs
spec:containers:- name: nfs-containerimage: busybox:1.35command: ["sh", "-c", "while true; do echo $(date) >> /nfs/data.log; sleep 10; done"]volumeMounts:- name: nfs-volmountPath: /nfs  # 容器内挂载点volumes:- name: nfs-volnfs:server: 192.168.121.109  # NFS服务器IPpath: /data/k8sdata/chenjun666  # NFS共享目录
验证:

在 NFS 服务器上查看/nfs/shared/data.log,会看到 Pod 持续写入的日志(即使 Pod 调度到其他节点,数据仍会写入同一文件)。

3.4 configMap:挂载配置文件(非敏感配置)

  • 特点:将 ConfigMap(K8s 的配置资源)中的键值对或文件,以文件形式挂载到容器内,方便配置管理(无需修改镜像即可更新配置)。
  • 适用场景:应用的配置文件(如 Nginx 的nginx.conf、应用的app.properties)。
步骤 1:创建 ConfigMap(配置源)
# configmap-demo.yaml
apiVersion: v1
kind: ConfigMap
metadata:name: app-config
data:# 键值对形式(会被挂载为文件,文件名=键,内容=值)app.properties: |env=productionlog_level=info# 直接定义文件内容(如nginx.conf)nginx.conf: |server {listen 80;root /usr/share/nginx/html;}
kubectl apply -f configmap-demo.yaml
步骤 2:Pod 挂载 ConfigMap
# pod-configmap.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-configmap
spec:containers:- name: nginximage: nginx:alpinevolumeMounts:- name: config-vol  # 卷名mountPath: /etc/config  # 挂载到容器内的/etc/config目录readOnly: true  # 配置文件通常设为只读volumes:- name: config-volconfigMap:name: app-config  # 关联的ConfigMap名称# 可选:只挂载部分键(默认挂载所有)# items:# - key: nginx.conf#   path: my-nginx.conf  # 重命名为my-nginx.conf
验证:
kubectl apply -f pod-configmap.yaml# 进入容器,查看挂载的配置文件
kubectl exec -it pod-configmap -- sh
ls /etc/config  # 会看到app.properties和nginx.conf
cat /etc/config/app.properties  # 输出配置内容

注意:ConfigMap 更新后,挂载的文件会在几秒内自动同步(无需重启 Pod)。

3.5 secret:挂载敏感信息(密码、证书)

  • 特点:与 ConfigMap 类似,但用于存储敏感信息(密码、Token、证书),数据会被 Base64 编码(非加密,需配合 RBAC 控制访问)
  • 适用场景:数据库密码、API 密钥、TLS 证书等。
步骤 1:创建 Secret(敏感信息)
# secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:name: app-secret
type: Opaque  # 通用类型
data:# 注意:值必须是Base64编码(echo -n "mypass123" | base64 生成)db-password: bXlwYXNzMTIz  # 原始值:mypass123tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tC...  # 证书内容的Base64编码
kubectl apply -f secret-demo.yaml
步骤 2:Pod 挂载 Secret
# pod-secret.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-secret
spec:containers:- name: appimage: busybox:1.35command: ["sleep", "3600"]volumeMounts:- name: secret-volmountPath: /etc/secret  # 挂载到容器内的/etc/secretreadOnly: true  # 敏感信息通常只读volumes:- name: secret-volsecret:secretName: app-secret  # 关联的Secret名称
验证:
kubectl apply -f pod-secret.yaml# 进入容器,查看解密后的敏感信息
kubectl exec -it pod-secret -- sh
cat /etc/secret/db-password  # 输出:mypass123(自动解码Base64)

4 pv/pvc

在 Kubernetes 中,PV(PersistentVolume,持久卷)PVC(PersistentVolumeClaim,持久卷声明) 是解决 “持久化存储” 问题的核心机制,核心目标是解耦存储资源的 “供应” 和 “使用”—— 让运维人员负责提供存储(PV),开发人员只需声明存储需求(PVC),无需关心底层存储细节。

4.1 一句话理清关系

  • PV:相当于 “提前准备好的仓库”(由运维创建),是集群中的存储资源实体(比如一块云硬盘、一个 NFS 目录),属于 “集群级资源”(不绑定命名空间)。
  • PVC:相当于 “仓库使用申请单”(由开发创建),是 Pod 对存储的需求声明(比如 “要 10GB 空间、可读写”),属于 “命名空间级资源”(和 Pod 在同一命名空间)。
  • 绑定:PVC 会自动匹配满足条件的 PV(容量、访问模式等一致),绑定后一对一专属使用,其他 PVC 无法占用。

4.2 PV:运维视角的 “存储资源包”

PV 是对底层存储(如本地磁盘、NFS、云硬盘)的 “封装”,每个 PV 都对应一块实际存储。创建时必须明确其核心属性,这些属性直接决定能否被 PVC 匹配。

4.2.1 PV 核心属性(绑定的关键)
属性作用重点值 / 示例
capacity存储容量(最基础的匹配条件)storage: 10Gi(支持 Gi、Ti)
accessModes访问模式(决定 PV 能被如何挂载,核心匹配条件3 种模式(下文详解)
persistentVolumeReclaimPolicy回收策略(PV 释放后如何处理数据,防数据泄露)Retain(保留数据)、Delete(删除)
storageClassName存储类(关联 StorageClass,用于动态供应;空则为 “裸 PV”)fast(自定义存储类)或空
claimRef已绑定的 PVC(自动生成,无需手动设置)-
关键:accessModes(访问模式)

决定 PV 的 “共享能力”,PVC 的访问模式必须是 PV 的子集(比如 PV 支持RWO,PVC 只能请求RWO)。

模式含义(核心!)适用场景支持存储类型举例
ReadWriteOnce (RWO)只允许1 个节点以 “读写” 挂载(同一节点的多个 Pod 可共享)单实例应用(MySQL、Redis 主节点)云硬盘(EBS)、本地磁盘
ReadOnlyMany (ROX)允许多个节点以 “只读” 挂载多节点共享静态资源(如图片)NFS、GlusterFS
ReadWriteMany (RWX)允许多个节点以 “读写” 挂载(最灵活,但支持的存储少)分布式应用(Hadoop、多 Pod 写日志)NFS、CephFS

注意:RWO的 “One” 指 “一个节点”,不是 “一个 Pod”—— 同一节点的多个 Pod 可以共享挂载。

4.2.2 静态供应 PV 示例(手动创建)

hostPath(仅测试用,生产不推荐)创建 PV:

# pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:name: pv-demo
spec:capacity:storage: 10Gi  # 容量10GBaccessModes:- ReadWriteOnce  # 单节点读写persistentVolumeReclaimPolicy: Retain  # 释放后保留数据storageClassName: ""  # 不关联存储类(裸PV)hostPath:  # 实际存储是节点的/opt/pv-data目录path: /opt/pv-datatype: DirectoryOrCreate  # 目录不存在则自动创建

操作:

kubectl apply -f pv-demo.yaml
kubectl get pv pv-demo  # 状态为Available(等待PVC绑定)

4.3 PVC:开发视角的 “存储需求单”

PVC 是对存储的 “需求声明”,开发只需定义 “要什么”(容量、访问模式等),K8s 会自动匹配合适的 PV。

4.3.1 PVC 核心属性(匹配 PV 的条件)
属性作用示例
resources.requests请求的容量(必须≤PV 的 capacity)storage: 10Gi
accessModes请求的访问模式(必须是 PV 访问模式的子集)- ReadWriteOnce
storageClassName请求的存储类(必须和 PV 的一致;空则匹配 “裸 PV”)fast(匹配对应存储类的 PV)
4.3.2 PVC 绑定 PV 示例

创建 PVC 匹配上面的pv-demo

# pvc-demo.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc-demonamespace: default  # 必须和Pod同命名空间
spec:accessModes:- ReadWriteOnce  # 和PV的访问模式一致resources:requests:storage: 10Gi  # 和PV的容量一致storageClassName: ""  # 和PV的存储类一致(空)

操作:

kubectl apply -f pvc-demo.yaml
kubectl get pvc pvc-demo  # 状态变为Bound(绑定成功)
kubectl get pv pv-demo    # PV状态也变为Bound,CLAIM列显示绑定的PVC
4.3.3 Pod 如何使用 PVC?

Pod 通过volumes引用 PVC,将 PV 挂载到容器内:

# pod-using-pvc.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-using-pvcnamespace: default
spec:containers:- name: nginximage: nginx:alpinevolumeMounts:- name: data-vol  # 卷名(和下面volumes.name对应)mountPath: /usr/share/nginx/html  # PV挂载到容器内的目录volumes:- name: data-volpersistentVolumeClaim:claimName: pvc-demo  # 引用的PVC名称

验证:在 Pod 内创建文件,会同步到 PV 对应的节点目录(/opt/pv-data)。

4.4 动态供应:用 StorageClass 自动创建 PV

静态供应(手动创建 PV)适合少量存储,生产环境更推荐动态供应—— 通过 StorageClass 自动创建 PV,无需运维手动干预。

4.4.1 StorageClass 的作用
  • 作为 “PV 模板”:定义存储类型(如 NFS、云盘)、访问模式、回收策略等。
  • 动态创建 PV:当 PVC 请求某个 StorageClass 时,K8s 自动调用存储插件(如 NFS-Provisioner)创建 PV 并绑定。
4.4.2 动态供应示例(NFS 为例)

假设已部署 NFS 服务器(192.168.1.100:/nfs/data)和 NFS 插件(nfs-subdir-external-provisioner)。

创建 StorageClass:

# storageclass-nfs.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-sc
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner  # NFS插件的provisioner
parameters:archiveOnDelete: "true"  # 删除PV时归档数据
reclaimPolicy: Delete  # 动态PV的回收策略
allowVolumeExpansion: true  # 允许PVC扩容

创建 PVC 引用 StorageClass:

# pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc-nfs
spec:accessModes:- ReadWriteMany  # NFS支持RWXresources:requests:storage: 5GistorageClassName: nfs-sc  # 引用上面的StorageClass

操作:

kubectl apply -f storageclass-nfs.yaml
kubectl apply -f pvc-nfs.yaml
kubectl get pvc pvc-nfs  # 会快速Bound(自动创建PV)
kubectl get pv  # 能看到一个自动生成的PV(名称类似pvc-xxx)

4.5 PV/PVC 生命周期(从创建到释放)

  1. 供应:静态(手动创 PV)或动态(StorageClass 自动创 PV),状态为Available
  2. 绑定:PVC 匹配到 PV 后,二者状态变为Bound(一对一绑定)。
  3. 使用:Pod 引用 PVC 挂载 PV,数据写入底层存储。
  4. 释放:删除 PVC 后,PV 状态变为Released,数据处理由reclaimPolicy决定:
    • Retain:保留数据,PV 需手动清理后才能复用。
    • Delete:自动删除 PV 和底层存储(慎用,数据会丢失)。

4.6 常见问题与排错

  1. PVC 一直 Pending
    • 原因:无匹配的 PV(容量不足、访问模式不兼容、存储类不匹配)。
    • 排查:kubectl describe pvc 你的PVC名,看 Events(如 “no PV matches access modes [RWX]”)。
  2. PV 绑定后无法使用
    • 原因:底层存储不可用(如 NFS 服务器宕机、云盘未挂载)。
    • 排查:检查存储后端状态,或查看 Pod 事件(kubectl describe pod 你的Pod名)。
  3. PVC 扩容失败
    • 前提:StorageClass 开启allowVolumeExpansion: true,且底层存储支持扩容。
    • 操作:编辑 PVC 的resources.requests.storage(如从 10Gi 改为 20Gi)。

总结

  • 核心分工:运维管 PV/StorageClass(供应存储),开发管 PVC/Pod(使用存储)。
  • 绑定关键:容量、访问模式、存储类必须匹配。

5 Volume vs 容器文件系统 vs PV/PVC(关键区别)

对比项容器文件系统Volume(如 emptyDir、hostPath)PV/PVC(通过 persistentVolumeClaim 类型)
生命周期与容器一致(容器重启丢失)与 Pod 一致(Pod 删除后清理)独立于 Pod(PV 由集群管理,数据长期保留)
数据持久化能力有限(hostPath 仅节点内持久化)强(依赖外部存储,如 NFS、云盘)
跨节点共享不支持hostPath 不支持,nfs 支持支持(取决于 PV 的存储类型)
适用场景临时缓存(无需持久化)同一 Pod 内共享、节点级临时持久化生产环境持久化存储(数据库、业务数据)

6 常见问题与注意事项

  1. Volume 挂载后权限问题:容器内挂载目录的权限可能与预期不符(如 root 权限),可通过volumeMounts.readOnly: true设为只读,或在 Pod 的securityContext中调整用户 ID(runAsUser)。
  2. emptyDir 占满磁盘:emptyDir 默认使用节点磁盘,若写入大量数据可能占满磁盘,建议重要数据用 PV 或 NFS,临时数据可设medium: Memory(但受限于内存大小)。
  3. ConfigMap/Secret 更新延迟:更新后通常 10 秒内同步到容器,但如果是 “子路径挂载”(subPath),则不会自动同步(需重启 Pod)。

7 总结

  • 临时共享数据(同一 Pod 内)→ emptyDir
  • 节点级测试持久化 → hostPath
  • 跨节点共享数据 → nfs
  • 非敏感配置文件 → configMap
  • 敏感信息 → secret
  • 生产环境持久化存储 → persistentVolumeClaim(关联 PV)
http://www.dtcms.com/a/438071.html

相关文章:

  • 十分钟搭建thinkphp开发框架
  • JVM中的内存区域划分
  • 做网站用小图标在什么网下载电脑如何做网站
  • FFmpeg 全面教程:从安装到高级应用
  • 10月3号
  • QT肝8天15--左侧静态菜单
  • 开源安全工具推荐:afrog- 主要用于 Bug Bounty、Pentest 和 Red Teaming 的安全工具
  • Go中的字符串
  • 为什么要做外贸网站公司邮箱域名是什么
  • 《政企API网关:安全与性能平衡的转型实践》
  • 安卓基础组件026-TabLayout
  • Day03_刷题niuke20251004
  • LeetCode:88.乘积最大子数组
  • 7.Java线程中的重要方法(interrupt、isInterrupted、interrupted)
  • 【深度学习计算机视觉】09:语义分割和数据集
  • Vue3 + Three.js 实现 3D 汽车个性化定制及展示
  • 外贸网站 费用广告公司取名字
  • 金融分析师技能提升路径与学习资源指南
  • MySQL processes, threads, connections的区别
  • 自己做的网站首页变成符号了工程与建设
  • P6374 「StOI-1」树上询问(倍增+LCA)
  • epoll_ctl函数中`sockfd` 和 `ev.data.fd`的疑问解析
  • 做元器件上什么网站做网站公司的排名
  • hadoop-hdfs-secondaryNameNode
  • 每日一个网络知识点:OSI参考模型
  • 怎么在国外网站做推广wordpress企业主题制作视频教程
  • K8s不同工作负载对应LOL里哪位英雄
  • 【探寻C++之旅】第十六章:unordered系列的认识与模拟实现
  • 用terraform 创建一个GKE private cluster
  • [优选算法专题三.二分查找——NO.22寻找峰值]