K8s Volume 存储
一、Volume 作用
容器内数据是临时的,容器重启数据丢失;Volume 给Pod提供存储,实现容器之间共享文件、数据持久化。
Pod中配置两处:
- spec.volumes:定义卷,是默认卷类型。
- spec.containers.volumeMounts:引用卷
二、3种基础卷(emptyDir / hostPath / nfs)
1)emptyDir 临时卷
- Pod调度到节点上自动创建,存于当前节点本地磁盘
- ✅用途:同一个Pod内部多个容器之间共享临时目录
- 生命周期:容器重启数据还在;Pod被删除/漂移,数据直接全部丢失
- 不能做持久化存储
2)hostPath 节点本地卷
- 把宿主机Node真实目录直接挂载进Pod
- Pod删除,宿主机上的数据仍然保留
- ❌缺点:强绑定当前节点;Pod漂移到别的节点,读不到这份数据
- 适合:单节点测试、访问宿主机日志、宿主机系统文件;多生产集群不推荐
- 可设置
readOnly:true实现只读挂载
3)NFS 网络共享存储
- 数据存放在远端NFS服务器,所有集群节点都可以访问
- Pod删除,NFS服务器数据不会丢失
- ✅支持Pod跨节点调度,Pod飘到任意节点都可以访问数据
- NFS支持访问模式:RWO、ROX、RWX
三、PV / PVC 持久存储架构
目的:解耦存储管理员 和 开发人员。管理员维护底层存储;开发只需要申请存储,不用关心底层存储实现。
-
PV(PersistentVolume 持久卷)
- 集群级别资源,管理员创建,代表后端真实存储(NFS/云盘等)
- PV生命周期独立于Pod
-
PVC(PersistentVolumeClaim 持久卷声明)
- 命名空间Namespace级别资源,开发编写,相当于"存储申请单"
- 写明需要多大容量、访问模式
-
完整流程:
① 管理员创建PV
② 用户创建PVC申请存储
③ k8s控制器自动匹配PV与PVC,状态变为
Bound绑定④ Pod在volumes中引用PVC,使用存储
Pod不直接使用PV,Pod只挂载PVC
四、PV accessModes 访问模式
| 缩写 | 名称 | 含义 |
|---|---|---|
| RWO | ReadWriteOnce | 一个节点读写;同一个节点上允许多个Pod读写 |
| ROX | ReadOnlyMany | 多个节点可以只读挂载 |
| RWX | ReadWriteMany | 多个节点同时读写(NFS支持) |
| RWOP | ReadWriteOncePod | 整个集群只允许1个Pod读写;仅CSI卷,k8s1.22+ |
重点:一个卷同一时刻只能使用一种访问模式,不能混用多种模式
五、volumeMode 卷模式
Filesystem【默认】:格式化为文件系统,挂载到目录,日常业务使用。Block:原始裸块设备,不做格式化,不挂载目录 ;容器内用volumeDevices+devicePath写设备路径,适合数据库底层直接操作磁盘。
注意:Block模式不用
volumeMounts,改用volumeDevices
六、PV与PVC匹配条件
- PV访问模式 ≥ PVC申请的访问模式
- PV存储容量 ≥ PVC申请存储大小,优先匹配刚好够用的最小PV
- 如果写了
storageClassName,PV和PVC的storageClassName必须完全一致
七、PV回收策略(PVC删除之后,PV如何处理数据)
- Retain(默认策略,保留)
- 删除PVC后,PV状态变成
Released;后端数据保留。 - ⚠️ PV带有旧PVC的
claimRef绑定信息,不能直接给新PVC绑定 - 需要手动删除PV中的
claimRef字段,PV才能再次分配给别的PVC。
- 删除PVC后,PV状态变成
- Recycle:已经废弃,不再使用。
- Delete
- 删除PVC,k8s会同时删除后端存储设备(如云盘EBS)
- ⚠️NFS不支持Delete,会报错;NFS后端文件不会自动删除。
思考题:怎么让一个PV只能被指定的PVC绑定?
答:在PV中写
claimRef,指定PVC名称+命名空间。
九、命令
bash
kubectl get pv
kubectl get pvc
kubectl describe pv xxx
kubectl edit pv xxx # 修改pv清除claimRef
kubectl delete ns storage #清理实验环境
Kubernetes Configure
核心思想:配置与镜像解耦,不把配置写死在镜像/Pod YAML中
ConfigMap:存放普通明文配置
Secret:存放密码、证书等敏感信息(仅base64编码,≠加密)
两者都是命名空间Namespace级别资源,Pod必须同命名空间才能引用
一、ConfigMap(CM)
1. 字段说明
data:普通UTF‑8文本配置binaryData:二进制数据,base64编码;不能和data出现相同keyimmutable:true:不可变更CM,创建后不能修改,只能删除重建;适合不会变动的配置
2. 三种创建方式
--from‑literal=key=值→ 键值对
bash
kubectl create configmap mysql --from-literal=password=redhat
data 里面直接:password: redhat
--from-file=文件名→ 单个文件,文件名 = key,文件内容 = value
bash
kubectl create configmap web1 --from-file=./index.html
CM 的 data 键就是index.html,值是文件全部内容。
--from-file=目录→ 整个目录下所有文件,每个文件名都是 key
bash
kubectl create configmap web2 --from-file=./web2
目录里有index.html、error.html,CM 就有两个 key。
查看:
kubectl get cm xxx -o yaml
3、Pod引用ConfigMap两种方式
① 环境变量 configMapKeyRef(容器级别)
bash
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
configMapKeyRef:
name: mysql # cm名称
key: password # cm内的key
✅只会读取单个key
⚠️缺点:Pod启动瞬间把值复制到内存;修改CM,Pod环境变量不会自动更新,必须重启Pod才生效
② Volume卷挂载(Pod级别,适合配置文件)
将CM的key变成容器内磁盘上的文件
A、挂载全部key(不使用subPath,推荐)
bash
volumes:
- name: webcontent
configMap:
name: web2
containers:
volumeMounts:
- name: webcontent
mountPath: "/usr/share/nginx/html"
✅CM更新,kubelet周期性同步,容器内文件自动刷新,无需重启Pod
B、只引用部分key
方式1:volumes下写items过滤key(不用subPath,依然支持自动更新)
bash
volumes:
- name: webcontent
configMap:
name: web2
items:
- key: index.html
path: index.html
方式2:subPath挂载单个文件
bash
volumeMounts:
- name: webcontent
mountPath: "/usr/share/nginx/html/index.html"
subPath: index.html
⚠️使用subPath:修改ConfigMap,容器内文件不会自动更新,需要重建Pod
底层Linux挂载限制,subPath只适合静态不变文件
二、Secret
⚠️重点:Secret只是base64编码,可以直接解码
Secret三种类型
generic(Opaque):通用,密码、敏感键值对,最常用docker‑registry:私有镜像仓库账号密码,配合Pod的imagePullSecrets拉取私有镜像tls:存放HTTPS证书crt +私钥key,给Ingress做HTTPS
2、Secret创建方式
① --from‑literal 直接指定键值对
bash
kubectl create secret generic mysecret \
--from-literal=user=tom \
--from-literal=password=redhat
② --from‑file 从文件创建
规则:文件名作为key,文件内容作为value
bash
# 基础写法
kubectl create secret generic mysecret2 \
--from-file=./user \
--from-file=./password
# 自定义key名字,不使用原文件名
kubectl create secret generic mysecret3 \
--from-file=username=./user \
--from-file=password=./password
③ --from‑env‑file 读取env格式文件批量生成键值
bash
kubectl create secret generic mysecret4 --from-env-file=./env.txt
④ docker‑registry 类型:私有镜像仓库凭证
bash
kubectl create secret docker-registry my-registry-secret \
--docker-username=xxx \
--docker-password=xxx \
--docker-email=xxx \
--docker-server=仓库地址
⑤ tls 类型:https证书 + 私钥
bash
kubectl create secret tls www-tls \
--cert=./www.crt \
--key=./www.key
🔧 base64 编解码命令
bash
#编码
echo -n redhat | base64
#解码
echo "cmVkaGF0" | base64 -d
查看secret常用命令
bash
kubectl get secrets
kubectl get secret mysecret -o yaml
kubectl describe secrets mysecret
小提示:secret yaml中data字段全部为base64编码,不是加密,可以直接解码拿到明文。
3、Pod引用Secret(规则和ConfigMap完全一致)
① 环境变量 secretKeyRef
bash
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret1
key: password1
⚠️修改Secret,环境变量不会自动更新,重启Pod生效
② Volume卷挂载Secret
bash
volumes:
- name: webcontent
secret:
secretName: web
volumeMounts:
- name: webcontent
mountPath: "/usr/share/nginx/html"
- 不使用subPath:Secret更新,容器文件自动刷新
- 使用subPath挂载单个文件:❌不会自动更新
Secret挂载文件权限
-
默认权限十进制
420→ 八进制644 -
defaultMode:256:设置该secret全部文件权限(256=0400) -
items.mode:511:设置单个key文件权限(511=0777)
yaml里面权限写十进制数字,不能写八进制
五、命令速查
bash
# configmap
kubectl create configmap
kubectl get cm
kubectl get cm xxx -o yaml
# secret
kubectl create secret generic|docker-registry|tls
kubectl get secrets
kubectl get secret xxx -o yaml
# base64解码
echo "字符串" | base64 -d
# 清理实验环境
kubectl delete ns configure