k8sday13数据存储(1.5/2)
目录
二、高级核心存储
1、PV
1.1配置文件
①、访问模式(accessModes)
②、回收策略(persistentVolumeReclaimPolicy)
③、存储类别
④、状态(Status)
1.2创建测试
①、准备NFS环境
②、创建PV
③、验证
2、PVC
1.1配置文件
1.2绑定引用测试
①、创建PVC
②、测试绑定
③、创建Pod准备测试
④、测试链路打通
3、注意事项
PV和PVC未绑定检查步骤
1、容量(Capacity)
2、访问模式(AccessModes)
3、可用状态(Status)
4、StorageClassName 必须完全一致
4、生命周期
①、资源供应
②、资源绑定
③、资源使用
④、资源释放
⑤、资源回收
二、高级核心存储
之前学过NFS提供存储配置,我们知道要进行存储数据要求用户会自己搭建NFS服务器,会在YAML文件中配置NFS,这显然对于用户来说,要求过高,而且k8s支持的存储系统类型多,要求用户熟知每个存储系统那是不现实的,所以k8s提出高级核心存储的概念(主要包含PV和PVC),二者通过连接绑定,最终实现用户只需要提出Pod的存储要求,而其底层实现由对应的管理员实现。如图:
1、PV
集群级资源,独立于 Pod 生命周期。可由管理员静态提前创建,也可通过 StorageClass 让系统自动动态供给。
1.1配置文件
以下给出一个NFS 类型的 PV 示例,供集群管理员提前“静态”创建,
# persistent-volume-nfs.yaml# 应用侧只需在 PVC 中声明相同 storageClassName 即可绑定。apiVersion: v1kind: PersistentVolume # 声明资源类型是 PVmetadata:name: pv-nfs-share # PV 对象在集群中的名称,可自定义# 由于 PV 是集群级资源,所以没有 namespace 的概念labels:app: nfs-pv-demo # 可按需添加 label,方便选择器匹配spec:capacity:storage: 2Gi # 声明的容量,PVC 申请量需 ≤ 该值accessModes: # 访问模式- ReadWriteMany # 允许多节点同时读写persistentVolumeReclaimPolicy: Retain # 回收策略storageClassName: nfs-slow # 必须与下方对应 PVC 的 storageClassName 一致mountOptions:- nfsvers=4.1 # 挂载参数,按需调整- noatimenfs: # 存储类型server: 192.168.10.5 # NFS 服务器 IP 或域名path: /data/nfs/share # NFS 导出的共享目录
①、访问模式(accessModes)
用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
-
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
-
ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
-
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
需要注意的是,底层不同的存储类型可能支持的访问模式不同
②、回收策略(persistentVolumeReclaimPolicy)
当 PV 不再被使用了之后,对其的处理方式。目前支持三种策略:
-
Retain(保留):PVC 删除后仅解除绑定,数据仍在,需要管理员手工清理数据
-
Recycle(回收):清除 PV 中的数据,已废弃,不推荐使用
-
Delete(删除):与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务
需要注意的是,底层不同的存储类型可能支持的访问模式不同
③、存储类别
PV可通过storageClassName参数指定一个存储类别
-
具有了特定类别的PV只能与请求了改特定类别的PVC绑定
-
没有指定类别的PV只能与不请求任何类别的PVC绑定
④、状态(Status)
一个PV的生命周期内,可能会有4个状态阶段:
-
Available(可用):未被任何PVC绑定
-
Bound(已绑定):PV已经和PVC绑定
-
Released(已释放):PV和PVC已解绑,PVC被删除,但是资源未被集群重新声明
-
Failed(失败):PV自动回收失败
1.2创建测试
①、准备NFS环境
# 获取已有节点,找到control-plane容器记下输出容器内 IP( INTERNAL-IP )例如 172.18.0.4 kubectl get node -o wide# 进入控制面(control-plane)容器docker exec -it my-multi-node-cluster1-control-plane bash# ---- 容器内执行 ------# 更新并安装NFS服务(如果你已经安装过了就不用这一步了)apt update && apt install -y nfs-kernel-server# 创建共享目录mkdir /tmp/logs/{pv1,pv2,pv3} -pv# 把共享目录权限改成 “任何人可读可写可执行”chmod 777 /tmp/logs# 向 /etc/exports 追加一行 导出规则# 当然也可以手动进入 /etc/exports 然后编辑添加规则# 建议使用精准的网络白名单# 如172.18.0.0/24 只允许这一网段访问;写成 * 就是全网放通,风险高echo "/tmp/logs 172.18.0.0/24(rw,sync,no_subtree_check,no_root_squash)" > /etc/exports# 重新加载 /etc/exports 并立即生效exportfs -rav # 重启 NFS 服务进程systemctl restart nfs-kernel-server# 如果不可用systemctl,可改为:service nfs-kernel-server restart# 退出控制面容器exit
②、创建PV
# pv-nfs.yamlapiVersion: v1kind: PersistentVolume # 声明资源类型是 PVmetadata:name: pv1-nfs # PV 对象在集群中的名称,可自定义# 由于 PV 是集群级资源,所以没有 namespace 的概念labels:app: pv1 # 可按需添加 label,方便选择器匹配spec:capacity:storage: 1Gi # 声明的容量,PVC 申请量需 ≤ 该值accessModes: # 访问模式- ReadWriteMany # 允许多节点同时读写persistentVolumeReclaimPolicy: Retain # 回收策略nfs: # 存储类型server: 172.18.0.4 # NFS 服务器 IP 或域名path: /tmp/logs/pv1 # NFS 导出的共享目录storageClassName: nfs-static # 存储类别---apiVersion: v1kind: PersistentVolume # 声明资源类型是 PVmetadata:name: pv2-nfs # PV 对象在集群中的名称,可自定义# 由于 PV 是集群级资源,所以没有 namespace 的概念labels:app: pv2 # 可按需添加 label,方便选择器匹配spec:capacity:storage: 2Gi # 声明的容量,PVC 申请量需 ≤ 该值accessModes: # 访问模式- ReadWriteMany # 允许多节点同时读写persistentVolumeReclaimPolicy: Retain # 回收策略nfs: # 存储类型server: 172.18.0.4 # NFS 服务器 IP 或域名path: /tmp/logs/pv2 # NFS 导出的共享目录storageClassName: nfs-static # 存储类别---apiVersion: v1kind: PersistentVolume # 声明资源类型是 PVmetadata:name: pv3-nfs # PV 对象在集群中的名称,可自定义# 由于 PV 是集群级资源,所以没有 namespace 的概念labels:app: pv3 # 可按需添加 label,方便选择器匹配spec:capacity:storage: 3Gi # 声明的容量,PVC 申请量需 ≤ 该值accessModes: # 访问模式- ReadWriteMany # 允许多节点同时读写persistentVolumeReclaimPolicy: Retain # 回收策略nfs: # 存储类型server: 172.18.0.4 # NFS 服务器 IP 或域名path: /tmp/logs/pv3 # NFS 导出的共享目录storageClassName: nfs-static # 存储类别
③、验证
# 创建PVkubectl create -f pv-nfs.yaml# 查看PVkubectl get pv -o wide
2、PVC
命名空间级资源,由用户/应用开发者创建。Kubernetes 的调度器负责把合适的 PV 绑定到这个 PVC 上。Pod 通过挂载 PVC,从而间接使用 PV。
1.1配置文件
# PVC 示例# 功能:向集群申请一块 3 GiB 的 NFS 存储,用于 Pod 挂载apiVersion: v1kind: PersistentVolumeClaim # 声明资源类型是 PVCmetadata:name: pvc-logs # PVC 在集群里的名字,Pod 通过这个名字引用namespace: default # PVC 是命名空间级资源,按需改成自己的 nsspec:accessModes:- ReadWriteMany # 必须与目标 PV 的 accessModes 完全一致resources: # 请求空间requests:storage: 3Gi # 申请的容量。只要 ≤ PV 的 capacity.storage 即可storageClassName: nfs-rwo # 存储类别# 1. 如果集群里给 NFS 手动创建的 PV 写了 storageClassName: nfs-rwo,# 这里就要写同样的值,才能匹配到该 PV(静态绑定)。# 2. 如果想走动态供给(StorageClass + NFS provisioner),# 则 storageClassName 指向对应的 StorageClass 名称即可;# 留空或写 "" 会落到集群的「默认 StorageClass」。# volumeName: pv-nfs-001 # 可选字段,强制绑定到某一台特定 PV# 写死后即使其他 PV 更匹配也不会变,一般不建议用# selector: # 可选,用 label 做更灵活的选择# matchLabels:# app: nfs-pv-demo
PVC的存储类别、访问模式、回收策略都与PV相同
1.2绑定引用测试
①、创建PVC
# pvc-nfs.yamlapiVersion: v1kind: PersistentVolumeClaim # 声明资源类型是 PVCmetadata:name: pvc1-nfs # PVC 在集群里的名字,Pod 通过这个名字引用namespace: default # PVC 是命名空间级资源,按需改成自己的 nsspec:accessModes:- ReadWriteMany # 必须与目标 PV 的 accessModes 完全一致resources: # 请求空间requests:storage: 1Gi # 申请的容量。只要 ≤ PV 的 capacity.storage 即可storageClassName: nfs-static # 存储类别---apiVersion: v1kind: PersistentVolumeClaim # 声明资源类型是 PVCmetadata:name: pvc2-nfs # PVC 在集群里的名字,Pod 通过这个名字引用namespace: default # PVC 是命名空间级资源,按需改成自己的 nsspec:accessModes:- ReadWriteMany # 必须与目标 PV 的 accessModes 完全一致resources: # 请求空间requests:storage: 1Gi # 申请的容量。只要 ≤ PV 的 capacity.storage 即可storageClassName: nfs-static # 存储类别---apiVersion: v1kind: PersistentVolumeClaim # 声明资源类型是 PVCmetadata:name: pvc3-nfs # PVC 在集群里的名字,Pod 通过这个名字引用namespace: default # PVC 是命名空间级资源,按需改成自己的 nsspec:accessModes:- ReadWriteMany # 必须与目标 PV 的 accessModes 完全一致resources: # 请求空间requests:storage: 4Gi # 申请的容量。只要 ≤ PV 的 capacity.storage 即可# 当前第三个pvc的申请容量,超过所有pv的容量,所以无法绑定storageClassName: nfs-static # 存储类别
②、测试绑定
# 创建PVCkubectl create -f pvc-nfs.yaml# 查看PVCkubectl get pvc -o wide# 查看PV绑定情况kubectl get pv -o wide
如图:
③、创建Pod准备测试
# 提供一个 Pod 准备进行 PVC → PV → NFS 链路打通测试apiVersion: v1kind: Podmetadata:name: test-pvc-mount # Pod 名称,可随意改spec:containers:- name: nginximage: nginx:1.24.0ports:- containerPort: 80volumeMounts:- name: html # 与 volumes.name 对应mountPath: /usr/share/nginx/html # 容器内挂载点volumes:- name: htmlpersistentVolumeClaim:claimName: pvc1-nfs # 必须和已存在的 PVC 名字一致restartPolicy: Never # 测试用,跑完即停;生产可用 Always
④、测试链路打通
# 1. 应用文件,部署 Podkubectl apply -f pod-test-pvc.yaml# 2. 验证部署成功kubectl get pod test-pvc-mount -w# 3. 进入 Pod 写文件kubectl exec -it test-pvc-mount -- sh -c 'echo "hello from pod" > /usr/share/nginx/html/index.html'# 4. 在 NFS 服务器或任何节点验证# 注意 my-multi-node-cluster1-control-plane 是我的 NFS 服务器名称,记得改为你自己的docker exec -it my-multi-node-cluster1-control-plane bashcat /tmp/logs/pv1/index.html# 应输出:hello from pod# 5. 清理kubectl delete -f pod-test-pvc.yaml
测试结果如下:
说明PVC → PV → NFS 链路打通,用户对于 Pod 的数据操作,实际存储在了与 Pod 连接的 PV,与 PV 绑定的 PVC 的存储系统之中,即 :用户→Pod→ PVC → PV → NFS(底层存储系统)
3、注意事项
PV和PVC未绑定检查步骤
1、容量(Capacity)
PVC 申请的 storage
必须 ≤ PV 声明的 capacity.storage
,否则不会绑定。
kubectl get pv,pvc -o wide
2、访问模式(AccessModes)
PVC 的 accessModes
必须是 PV 声明的访问模式的子集。例:PV 只有 RWO
,PVC 却要求 RWX
,就会一直 Pending
。
kubectl describe pvc <pvc-name>
3、可用状态(Status)
PV 必须是 Available
;如果已被别的 PVC 绑走,就会是 Bound
。• 若 PV 是 Released
(前一个 PVC 被删但 reclaimPolicy=Retain),需要手动把它重新设为 Available
:
4、StorageClassName 必须完全一致
• 如果 PV 写了 storageClassName: nfs-rwo
,PVC 必须也写 storageClassName: nfs-rwo
。• 如果 PV 的 storageClassName: ""
(空串),PVC 也必须写 storageClassName: ""
,不能省略。
kubectl get pv <pv-name> -o jsonpath='{.spec.storageClassName}'kubectl get pvc <pvc-name> -o jsonpath='{.spec.storageClassName}'
资源 | YAML 里 不写 storageClassName 字段时,实际值 | 说明 |
---|---|---|
PV | "" (空字符串) | 明确等于空串,不会被当成任何 StorageClass,只能与同样为 "" 的 PVC 匹配。 |
PVC | 集群中 标记为 default 的 StorageClass(通常是 standard ) | 如果集群设置了 default StorageClass,PVC 会自动填上它的名字;如果没有 default,则也为 "" 。 |
-
PVC 没写 ⇒ 自动落到
standard
-
PV 也没写 ⇒ 等于
""
(空串)可能会导致二者无法匹配绑定
4、生命周期
PV和PVC遵循类似的生命周期:
①、资源供应
-
PV已创建,未绑定待使用
②、资源绑定
-
PV和对应的PVC绑定,如果找不到应绑定的PV,PVC会一直处于Pending状态,一旦绑定,PVC独占PV
③、资源使用
-
Pod使用PVC
④、资源释放
-
PVC使用完PV后,释放PV,PV处于Released状态
⑤、资源回收
-
通过提前设定的回收策略回收PV,只有PV存储空间回收完成,才能提供给新的PVC绑定