一、K8s存储分类(修正)
K8s存储的核心分类逻辑是按生命周期与使用场景划分,而非简单"常规/特殊",更合理的分类如下:
临时存储:生命周期与Pod一致,Pod删除后数据丢失
持久化存储:生命周期独立于Pod,Pod删除后数据保留
配置存储:用于存储配置信息或敏感数据,本质是集群资源的挂载
二、临时存储(Ephemeral Storage)
1. emptyDir
作用:在Pod启动时自动创建,供Pod内所有容器共享的临时目录
特点:
生命周期与Pod完全绑定(Pod删除/重建,数据丢失)
存储位置默认由节点决定(可以是内存tmpfs或节点磁盘)
无法跨Pod共享(每个Pod有独立的emptyDir,即使是Deployment的多个副本也不共享)
错误修正:笔记中"通过Deployment创建4个副本,用emptyDir实现Pod之间文件共享"是错误的!副本Pod的emptyDir是相互独立的,无法跨Pod共享数据。
使用场景:临时缓存、容器间数据传递(同一Pod内)、临时日志存储
配置示例:
apiVersion: v1
kind: Pod
metadata:
name: emptyDir-demo-pod # Pod名称
spec:
containers:
- name: app-container # 容器1:生成临时数据
image: busybox # 基础镜像(轻量,适合测试)
command: ["/bin/sh", "-c"]
args: ["while true; do echo $(date) > /tmp/cache/date.log; sleep 10; done"] # 每10秒写时间到临时文件
volumeMounts:
- name: temp-data # 关联卷名称(与下方volumes.name一致)
mountPath: /tmp/cache # 容器内挂载路径
#===================================================================================================
- name: sidecar-container # 容器2:读取同一Pod内的临时数据(验证共享)
image: busybox
command: ["/bin/sh", "-c"]
args: ["while true; do cat /tmp/cache/date.log; sleep 10; done"] # 每10秒读取容器1写的文件
volumeMounts:
- name: temp-data # 关联同一个卷,实现容器间共享
mountPath: /tmp/cache # 与容器1挂载路径可不同,但指向同一emptyDir
#==================================================================================================
volumes: # 定义卷
- name: temp-data # 卷名称
emptyDir:
medium: Memory # 用内存存储(tmpfs),不指定则默认用节点磁盘2. 其他临时卷(补充)
downwardAPI:将Pod自身信息(如名称、IP、标签)挂载为文件供容器读取projected:将多种卷(如Secret+ConfigMap)合并挂载到同一目录ephemeral:临时存储接口,可对接临时存储类(适合短期任务)
三、配置存储(Configuration Storage)
用于存储配置信息,数据来自K8s集群资源,而非底层存储介质。
1. Secret
作用:存储敏感数据(密码、Token、证书等),避免明文出现在配置中
特点:
数据会被Base64编码(注意:不是加密,敏感场景需配合加密插件)
Base64 编码的局限性:通过
kubectl get secret my-secret -o yaml可直接看到编码后的内容属于命名空间级资源,仅同命名空间Pod可访问
配置示例:
# secret-create.yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret # Secret名称(需与Pod中secretName一致)
namespace: default # 命名空间(需与Pod一致)
type: Opaque # 通用类型(存储键值对)
data: # 数据需Base64编码(注意:不是加密)
db-username: cm9vdA== # 原内容:root(Base64编码命令:echo -n "root" | base64)
db-password: MTIzNDU2 # 原内容:123456使用场景:数据库密码、API密钥、TLS证书
在Pod中调用secret:
apiVersion: v1 kind: Pod metadata: name: secret-demo-pod # Pod名称 spec: containers: - name: app-container image: busybox command: ["/bin/sh", "-c", "sleep 3600"] # 让Pod持续运行,方便验证 volumeMounts: - name: httpstoken # 卷名称(与下方volumes.name一致) mountPath: /etc/secrets # 容器内挂载路径 readOnly: true # 只读挂载(敏感数据建议加,防止容器内误修改) volumes: - name: httpstoken # 卷名称(Pod内的“别名”) secret: secretName: my-secret # Secret名称(需与提前创建的Secret一致) optional: false # 设为false:若Secret不存在,Pod启动失败(默认值,建议保留)操作验证:
进入容器查看 Secret 数据:
kubectl exec -it secret-demo-pod -- /bin/sh查看挂载目录下的文件(键即文件名,内容即解密后的原数据):
ls /etc/secrets # 输出:db-username db-password cat /etc/secrets/db-password # 输出:123456(自动解密Base64)
2. ConfigMap
作用:存储非敏感配置信息(配置文件、环境变量、命令行参数等)
特点:
数据明文存储(不适合敏感信息)
支持热更新(当ConfigMap内容修改,挂载的文件会自动更新,无需重启Pod)
配置示例(错误修正:
configMap下直接指定name,而非列表):
# configmap-create.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config # ConfigMap名称(需与Pod中name一致)
namespace: default
data:
log-level: "info" # 明文存储(无需编码,区别于Secret)
app.properties: | # 存储多行配置(用|保留换行)
env=production
timeout=30s使用场景:应用配置文件(如nginx.conf)、环境变量配置
apiVersion: v1 kind: Pod metadata: name: configmap-demo-pod # Pod名称 spec: containers: - name: nginx-container image: nginx:alpine # 用nginx镜像验证配置挂载 volumeMounts: - name: kube-proxy-config # 卷名称(与下方volumes.name一致) mountPath: /etc/nginx/conf.d # 容器内nginx配置目录 volumes: - name: kube-proxy-config # 卷名称(Pod内“别名”) configMap: name: nginx-config # ConfigMap名称(需与提前创建的一致) items: # 可选:只挂载ConfigMap中的部分键(不写则挂载所有键) - key: nginx.conf # ConfigMap中的键 path: default.conf # 容器内的文件名(可自定义,无需与键一致)操作验证:
进入容器查看配置:
kubectl exec -it configmap-demo-pod -- /bin/sh验证配置文件:
cat /etc/nginx/conf.d/default.conf(输出提前定义的 nginx 配置)
四、持久化存储(Persistent Storage)
数据生命周期独立于Pod,核心通过PV(PersistentVolume) 和PVC(PersistentVolumeClaim) 实现"存储资源与使用分离"。
1. HostPath(节点本地存储)
作用:将Pod所在节点的本地目录挂载到Pod内
错误修正:
归类错误:HostPath不属于"永久卷",而是节点级本地存储,本质是临时存储的特殊形式(依赖节点生命周期)
配置示例:
在节点上创建目录(关键前提)
操作节点:登录 Pod 会调度到的节点(若用多节点集群,需确保目标节点有此目录)
# 在节点上执行(非kubectl命令) mkdir -p /opt/t0814 # 创建目录(需与Pod中hostPath.path一致) chmod 777 /opt/t0814 # 赋予读写权限(避免容器内权限不足)
apiVersion: v1 kind: Pod metadata: name: hostpath-demo-pod # Pod名称 spec: nodeName: worker-1 # 可选:指定调度到的节点(确保该节点有/opt/t0814目录) containers: - name: app-container image: busybox command: ["/bin/sh", "-c", "echo 'hostPath test' > /etc/nginx/test.txt && sleep 3600"] # 写文件到挂载目录 volumeMounts: - name: local-data # 卷名称(与下方volumes.name一致) mountPath: /etc/nginx # 容器内挂载路径 volumes: - name: local-data # 卷名称 hostPath: path: /opt/t0814 # 节点上的目录(需提前创建,与步骤1一致) type: Directory # 校验节点上是目录(不存在则Pod启动失败)操作验证:
登录节点查看文件(验证数据持久化):
cat /opt/t0814/test.txt(输出:hostPath test)删除 Pod 后,节点目录数据仍存在:
kubectl delete pod hostpath-demo-pod
注意事项:
仅用于开发/测试(生产环境禁用),因为:
数据依赖节点,Pod调度到其他节点时无法访问原数据
不同节点的
hostPath目录内容可能不一致
需确保节点上的目录存在且权限正确(否则Pod会启动失败)
补充:type 类型
不指定
type(默认):不校验路径类型和是否存在(路径可能不存在,或类型不符合预期,Pod 可能启动失败或运行异常)Directory:必须是已存在的目录(若不存在,Pod 启动失败)
DirectoryOrCreate:若路径不存在,则自动创建为目录(权限默认 0755,属主 root);若已存在,必须是目录
File:必须是已存在的文件(若不存在或为目录,Pod 启动失败)
FileOrCreate:若路径不存在,则自动创建为空文件(权限默认 0644,属主 root);若已存在,必须是文件
Socket:必须是已存在的 Unix 套接字文件(如
/var/run/docker.sock)CharDevice:必须是已存在的字符设备文件(如
/dev/ttyS0)BlockDevice:必须是已存在的块设备文件(如
/dev/sda1)
2. PV(PersistentVolume,持久卷)
定义:集群级资源,由管理员创建,代表底层实际存储资源(如NFS目录、CEPH存储池、云厂商磁盘等)
核心属性:
容量(capacity):存储大小(如100Gi)
访问模式(accessModes):
ReadWriteOnce(RWO):仅单节点可读写ReadOnlyMany(ROX):多节点可读ReadWriteMany(RWX):多节点可读写(需存储支持,如NFS/CEPH)ReadWriteOncePod(RWOP):仅单Pod读写
存储类(storageClassName):用于动态绑定(需配合StorageClass)
回收策略(reclaimPolicy):
Retain:PVC删除后,PV保留数据(手动清理)Delete:PVC删除后,PV自动删除(适合云存储)Recycle:已废弃(用Delete替代)
生命周期:
可用(available):PV已创建
绑定(bound):PV与PVC 捆绑
释放(release):PVC被删除
回收(reclaim):等待被处理
配置示例(NFS作为PV后端):
前提:准备 NFS 服务器(示例用 NFS 作为 PV 后端)
安装 NFS 服务器(以 CentOS 为例):
yum install -y nfs-utils创建 NFS 共享目录:
mkdir -p /nfs/data && chmod 777 /nfs/data配置 NFS 共享:
echo "/nfs/data 192.168.1.0/24(rw,sync,no_root_squash)" >> /etc/exports启动 NFS 服务:
systemctl start nfs-server && systemctl enable nfs-server
# pv-create.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv # PV名称(集群内唯一)
spec:
capacity:
storage: 100Gi # PV容量(需大于等于PVC申请的容量)
accessModes:
- ReadWriteMany # 访问模式(多节点可读写,需NFS支持)
nfs:
path: /nfs/data # NFS服务器共享目录(与前提步骤2一致)
server: 192.168.1.100 # NFS服务器IP(替换为你的NFS服务器IP)
storageClassName: "" # 不指定存储类(静态绑定,PVC需匹配)
reclaimPolicy: Retain # 回收策略:PVC删除后,PV保留数据(手动清理)部署 PV:
kubectl apply -f pv-create.yaml验证 PV:
kubectl get pv nfs-pv(状态为Available,表示可被 PVC 绑定)
3. PVC(PersistentVolumeClaim,持久卷声明)
定义:命名空间级资源,由用户创建,用于"申请"PV资源(类似"存储订单")
核心逻辑:PVC根据容量、访问模式、存储类等条件,自动绑定匹配的PV(静态绑定),或通过StorageClass动态创建PV(动态绑定)
配置示例:
# pvc-create.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-pvc # PVC名称(命名空间内唯一)
namespace: default # 命名空间(需与Pod一致)
spec:
accessModes:
- ReadWriteMany # 访问模式(需与PV完全匹配)
resources:
requests:
storage: 50Gi # 申请容量(需小于等于PV容量100Gi)
storageClassName: "" # 存储类(需与PV一致,空表示匹配无存储类的PV)部署 PVC:
kubectl apply -f pvc-create.yaml验证 PVC:
kubectl get pvc app-pvc(状态为Bound,表示已与 PV 绑定)
在 Pod 中调用 PVC(完整 Pod YAML)
# pod-with-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: pvc-demo-pod # Pod名称
spec:
containers:
- name: app-container
image: busybox
command: ["/bin/sh", "-c", "echo 'PV/PVC test' > /data/test.txt && sleep 3600"] # 写文件到PVC挂载目录
volumeMounts:
- name: app-storage # 卷名称(与下方volumes.name一致)
mountPath: /data # 容器内挂载路径
volumes:
- name: app-storage # 卷名称
persistentVolumeClaim:
claimName: app-pvc # PVC名称(需与步骤2创建的PVC一致)操作验证:
查看 NFS 共享目录(验证数据持久化):
cat /nfs/data/test.txt(输出:PV/PVC test)删除 Pod 后数据仍存在:
kubectl delete pod pvc-demo-pod删除 PVC 后,PV 状态变为
Released(数据保留,需手动清理后可重新绑定):kubectl delete pvc app-pvc
PV和PVC和StorageClass的关系
PV创建有静态(手动创建)和动态(自动创建),这个动态的就是storageclass。
五、常规网络存储(补充)
这类存储通常作为PV的后端,提供持久化、可共享的存储能力:
NFS:网络文件系统,支持多节点读写(RWX),适合中小规模集群
CEPH:分布式存储系统,支持块存储(RBD)、文件系统(CephFS),适合大规模集群
云厂商存储:如AWS EBS、阿里云OSS、Google Persistent Disk,与云平台深度集成
SCSI/iSCSI:块存储协议,通常用于高性能本地存储或SAN存储
除了作为 PV 后端,NFS 也可直接在 Pod 中挂载(无需 PV/PVC,适合简单场景):
apiVersion: v1
kind: Pod
metadata:
name: nfs-direct-pod
spec:
containers:
- name: app
image: busybox
command: ["/bin/sh", "-c", "sleep 3600"]
volumeMounts:
- name: nfs-volume
mountPath: /mnt/nfs
volumes:
- name: nfs-volume
nfs:
server: 192.168.1.100 # NFS服务器IP
path: /nfs/data # NFS共享目录常见排错
在实际使用中,存储配置失败是新手高频问题,补充 3 个典型场景的排错步骤: