← 返回 Kubernetes图解 目录
💾 K8s存储与配置图解
Volume/PV/PVC/StorageClass/ConfigMap/Secret · SVG可视化 + 生活类比 + IDE源码窗口
① Volume类型全景
把K8s存储想象成公司里的各种空间:
• emptyDir = 临时办公桌(员工来了分配,走了清空,不保留任何东西)
• hostPath = 靠墙的私人柜子(固定在大楼某个位置,只在那台机器上)
• ConfigMap = 公告栏(大家都能看到的配置信息)
• Secret = 保险柜(敏感信息,只有授权的人能看)
• PV = 仓库(实实在在的存储空间)
• PVC = 仓库申请单("我需要多大仓库、什么条件")
Volume类型全景:临时存储 vs 持久化存储 vs 配置存储
| Volume类型 | 生命周期 | 类比 | 典型场景 |
| emptyDir | 同Pod | 临时办公桌 | Pod内多容器共享临时数据 |
| hostPath | 同Node | 靠墙私人柜 | 访问Node文件系统(调试用) |
| PV/PVC | 独立 | 仓库/申请单 | 持久化业务数据 |
| ConfigMap | 同Namespace | 公告栏 | 配置文件、环境变量 |
| Secret | 同Namespace | 保险柜 | 密码、Token、证书 |
# emptyDir:Pod内共享临时数据
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
containers:
- name: app # 主容器:写日志
image: nginx
volumeMounts:
- name: log-data
mountPath: /var/log/app
- name: sidecar # Sidecar:读日志转发
image: fluentd
volumeMounts:
- name: log-data
mountPath: /var/log/app
volumes:
- name: log-data
emptyDir: {} # Pod删除→数据消失
② PV与PVC绑定流程
PV和PVC就像仓库和仓库申请单:
• PV = 公司有一间间仓库(20G SSD / 50G HDD / 100G NFS),每间仓库有标签(类型、大小、访问方式)
• PVC = 员工填一张申请单:"我要一个10G以上的SSD仓库,一个人用"
• 绑定 = 行政部门拿申请单去匹配仓库,找到最合适的就绑定
• AccessModes = 仓库使用规则:ReadWriteOnce=独享 / ReadWriteMany=共享 / ReadOnlyMany=只读共享
PV-PVC绑定三步流程:提交申请 → 控制器匹配 → 绑定成功
# ① PV:仓库实体
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-ssd-20g
spec:
capacity:
storage: 20Gi
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
nfs:
server: 10.0.0.1
path: /data/ssd-share
---
# ② PVC:仓库申请单
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-app-pvc
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 10Gi # 申请10G,匹配20G的PV
---
# ③ Pod使用PVC
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: my-app-pvc
PVC绑定时不会自动找最小匹配,而是找第一个满足条件的PV。如果PV是20Gi而PVC申请10Gi,绑定的还是20Gi的PV——这20Gi就被占用了,别人用不了剩余的10Gi。所以PV大小最好按需创建。
③ StorageClass动态供给
StorageClass = 仓库分类标准。就像公司把仓库分成"SSD仓""HDD仓""NFS仓",员工只需在申请单上写"我要SSD仓的10G",行政部门自动分配——不用提前建好每间仓库。
• 静态供给 = 管理员先建好仓库(手动创建PV),等PVC来匹配
• 动态供给 = 管理员只定好仓库模板(StorageClass),PVC来了自动创建PV
静态供给 vs 动态供给:手动建仓库 vs 自动按模板创建
# StorageClass:仓库分类模板
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs # 谁来建仓库
parameters:
type: gp3
iopsPerGB: "50"
reclaimPolicy: Delete # PVC删了,PV也删
volumeBindingMode: WaitForFirstConsumer
---
# PVC引用StorageClass(自动创建PV)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: auto-pvc
spec:
storageClassName: fast-ssd # 引用SC
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
| reclaimPolicy | PVC删除后 | 类比 | 适用场景 |
| Retain | PV保留,需手动清理 | 离职了工位还在 | 生产环境数据保护 |
| Delete | PV和底层存储一起删 | 离职了工位拆了 | 临时/开发环境 |
| Recycle | 清空数据后PV可重用(已废弃) | 工位打扫后给下个人 | 旧版K8s |
④ ConfigMap与Secret
ConfigMap = 公司公告栏:数据库地址、日志级别、功能开关——不怕人看到的配置。
Secret = 公司保险柜:数据库密码、API密钥、TLS证书——绝不能让人随便看到的敏感数据。
使用方式有两种:
• 环境变量 = 口头告知(简单,但重启才更新)
• 挂载文件 = 贴在工位上(更新后自动刷新,不用重启Pod)
ConfigMap vs Secret:公告栏 vs 保险柜,两种使用方式
# ConfigMap:公告栏
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DB_HOST: "mysql.prod.svc"
LOG_LEVEL: "info"
application.yml: |
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://${DB_HOST}:3306/mydb
---
# Secret:保险柜
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data: # 注意:值必须是Base64编码
username: YWRtaW4= # echo -n 'admin' | base64
password: c2VjcmV0 # echo -n 'secret' | base64
---
# Pod挂载ConfigMap和Secret
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: my-app:latest
# 方式1:环境变量
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: db-credentials
# 方式2:挂载文件
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
Secret的Base64不是加密!任何人 `kubectl get secret xxx -o yaml` 然后 `echo 'c2VjcmV0' | base64 -d` 就能看到明文。生产环境必须:
1. 开启 EncryptionConfiguration(etcd加密存储)
2. 配置RBAC限制Secret访问权限
3. 使用外部密钥管理(Vault/AWS Secrets Manager)
⑤ 面试速答
emptyDir和hostPath有什么区别?各适合什么场景?
emptyDir:Pod级别临时存储,Pod删除数据消失。适合:Sidecar共享日志、临时计算中间结果。
hostPath:挂载Node本地路径,Pod删除数据还在(但换了Node就找不到)。适合:访问Docker socket(/var/run/docker.sock)、系统日志(/var/log)。
关键区别:emptyDir随Pod生灭,hostPath绑定Node。
PV和PVC是什么关系?绑定规则是什么?
PV是集群级资源(仓库实体),PVC是命名空间级资源(仓库申请单)。
绑定规则:
1. storageClassName必须一致
2. PV的capacity ≥ PVC的requests
3. PV的accessModes必须包含PVC要求的模式
4. 如果PVC有selector,PV的labels必须匹配
注意:一个PV只能绑定一个PVC(1:1关系)。
StorageClass的动态供给是什么?比静态供给好在哪里?
动态供给:用户创建PVC时,K8s根据StorageClass模板自动创建PV并绑定。
静态供给:管理员手动创建PV,等PVC来匹配。
动态供给优势:
1. 按需创建:不浪费存储空间
2. 自动匹配:不需要管理员手动计算容量
3. 解耦:开发不用关心底层存储细节
关键配置:provisioner(谁来建)+ parameters(建什么样的)+ reclaimPolicy(PVC删了怎么办)。
ConfigMap和Secret有什么区别?Secret真的安全吗?
ConfigMap:存储非敏感配置,明文存储。
Secret:存储敏感数据,Base64编码。
Secret并不真正安全!
1. Base64是编码不是加密,`base64 -d` 一秒解码
2. 默认存储在etcd中是明文的
3. 有RBAC权限的人可以直接 `kubectl get secret`
生产环境安全措施:
• 开启EncryptionConfiguration(etcd加密)
• 配置RBAC限制访问
• 使用Vault等外部密钥管理系统
• 开启审计日志记录Secret访问
ConfigMap更新后Pod里的配置会自动生效吗?
取决于使用方式:
① 环境变量方式(envFrom):❌ 不会自动更新。Pod的环境变量在启动时注入,之后不会变。必须重启Pod。
② 挂载文件方式(volume):✅ 会自动更新!kubelet会定期同步(默认60秒),Pod内文件内容自动刷新。但应用本身要支持热加载(比如Spring Boot的@RefreshScope)。
最佳实践:需要热更新的配置用挂载文件方式,启动时一次性配置用环境变量。
PVC删除后PV会怎样?reclaimPolicy有什么影响?
取决于PV的reclaimPolicy:
• Retain:PV保留,数据不删,需管理员手动清理后才能重新绑定。生产环境推荐。
• Delete:PV和底层存储一起删除。开发/测试环境可用。
• Recycle(已废弃):执行rm -rf后PV可重用。
生产环境建议用Retain,防止误删PVC导致数据丢失。
ReadWriteOnce/ReadWriteMany/ReadOnlyMany分别支持什么存储后端?
RWO(ReadWriteOnce):单Node读写。AWS EBS、GCE PD、Azure Disk都支持。
RWX(ReadWriteMany):多Node同时读写。只有NFS、CephFS、GlusterFS等网络存储支持。
ROX(ReadOnlyMany):多Node只读。NFS、CephFS、托管存储支持。
关键记忆:块存储(EBS)只支持RWO,文件存储(NFS/CephFS)支持RWX。选存储后端时要先确认AccessMode需求。
volumeBindingMode的WaitForFirstConsumer是什么意思?
Immediate(默认):PVC一创建就绑定PV,不管Pod调度到哪个Node。
WaitForFirstConsumer:等到第一个使用此PVC的Pod调度完成后,才在那个Node上创建/绑定PV。
为什么需要?
比如AWS EBS是区域绑定的——如果PVC在us-east-1a创建了PV,但Pod被调度到us-east-1b的Node上,PV就挂不上了。
WaitForFirstConsumer让PV在Pod实际运行的Zone创建,避免跨Zone挂载失败。
如何给Spring Boot应用注入K8s的ConfigMap配置?
推荐方式:挂载为文件 + Spring Cloud Kubernetes
1. ConfigMap中定义application.yml
2. 挂载到/config目录
3. Spring Cloud Kubernetes自动读取
简单方式:环境变量注入
envFrom.configMapRef注入所有key为环境变量
Spring Boot用${DB_HOST}引用
注意:环境变量方式修改ConfigMap需要重启Pod才能生效;挂载文件方式kubelet会自动同步(约60秒延迟),但应用需要支持热加载。
核心三原则速记
K8s存储配置三原则:① PV 是集群资源,PVC 是用户申请,StorageClass 自动动态创建 → ② ConfigMap 存非敏感配置,Secret 存密码证书(Base64 不是加密) → ③ 持久化数据用 PVC,临时数据用 emptyDir