k8s 存储详解
k8s存储详解
博客主要介绍本地存储,网络存储,pv,pvc,nfs动态制备pv
k8s存储就是指的pod的存储,持久化存储,数据不会丢失
一、本地存储
1、emptydir类型
-
在pod所在的物理主机上生成一个随机目录,临时目录
-
主要用于缓存的,pod被删除后,临时目录也会被删除
[root@master01 pv]# kubectl run b1-emptydir --image=busybox --image-pull-policy=IfNotPresent --dry-run=client -o yaml -- /bin/sh -c "sleep 3600" > emptydir.yml
[root@master01 pv]# cat emptydir.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b1-emptydir
name: b1-emptydir
spec:
volumes:
- name: data # 指定卷的名字
emptyDir: {} # 临时目录类型
containers:
- args:
- /bin/sh
- -c
- sleep 3600
image: busybox
imagePullPolicy: IfNotPresent
name: b1-emptydir
resources: {}
volumeMounts:
- name: data # 将卷挂载到容器内部,名字需要一致
mountPath: /data # 挂载到容器的/data目录下面
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
- 可以查看到这个临时目录的位置的
[root@master01 pv]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
b1-emptydir 1/1 Running 0 4m35s 10.246.73.179 node <none> <none>
# pod调度在node节点上,docker查看
[root@node data]# docker inspect b909ada5544a
# 进入挂载目录
[root@node data]# cd /var/lib/kubelet/pods/421b2bf8-5315-47de-9f67-40485d874191/volumes/kubernetes.io~empty-dir/data
# 查看数据
[root@node data]# ls
1.txt
- 删除pod
# 进不去了,发现被删除了
[root@node pods]# cd /var/lib/kubelet/pods/421b2bf8-5315-47de-9f67-40485d874191/volumes/kubernetes.io~empty-dir/data
-bash: cd: /var/lib/kubelet/pods/421b2bf8-5315-47de-9f67-40485d874191/volumes/kubernetes.io~empty-dir/data: No such file or directory
2、hostPath类型
-
这个就是在宿主机上面创建一个目录,然后挂载到pod里面
-
有一个致命的缺陷,就是pod被再次调度到另外一个节点上面,这个节点上面没有这个目录,那就无法实现存储
-
因此这个hostPath类型需要与标签选择器一起使用,指定在某个节点上调度
-
或者是这个目录,所有节点都存在
[root@master01 pv]# cat hostpath.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b2-hostpath
name: b2-hostpath
spec:
nodeName: master02 # 标签选择器,指定节点进行调度
volumes:
- name: hostpath
hostPath: # hostPath 类型
path: /data # 宿主机目录
containers:
- image: nginx:1.25
name: b2-hostpath
resources: {}
volumeMounts:
- name: hostpath
mountPath: /data # 挂载到容器的/data目录下面
dnsPolicy: ClusterFirst
# 在容器里面写入数据,宿主机上面也会存储数据
[root@master02 data]# ls
1.txt
二、网络存储
1、nfs存储
-
为了解决上面的一些问题,pod需要被指定调度在某个节点
-
nfs就不需要指定节点了,只要网络是好的,就能任意共享

1、配置nfs服务器
yum -y install nfs-utils
mkdir /nfsdata
chmod o+w /nfsdata
[root@master01 pv]# cat /etc/exports
/nfsdata *(rw)
systemctl enable nfs-server --now
systemctl enable rpcbind --now
# 测试
[root@master01 pv]# showmount -e localhost
Export list for localhost:
/nfsdata *
2、使用nfs作为后端存储
[root@master01 pv]# cat nfs.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b3-nfs
name: b3-nfs
spec:
volumes:
- name: nfs-data
nfs:
path: /nfsdata # nfs存储目录
server: 192.168.50.20 # nfs服务器地址
containers:
- image: nginx:1.25
name: b3-nfs
resources: {}
volumeMounts:
- name: nfs-data
mountPath: /nfs # 挂载到容器nfs目录
dnsPolicy: ClusterFirst
restartPolicy: Always
# 查看pod详细,也可以看到挂载的详细信息
- 写入数据
# 发现有数据
[root@master01 pv]# ls /nfsdata/
1.txt nfs.txt
2、ceph存储
-
可以使用rbd,cephfs这些作为后端的存储
-
在下一篇的博客会详细的介绍
-
只不过是写法不一样而已
三、pv和pvc
1、什么是pv和pvc?
-
是k8s的资源对象,namespace级别的,pv不是ns级别的,pv全局可见的
-
专门用来作为pod的后端存储的,pv是实际的存储,pvc是申请
-
pv和pvc进行绑定,pod直接使用pvc存储
-
pv的后端还是nfs或者rbd存储,所以底层还是之前学过的
-
这样做的一个好处就是
-
pod直接使用pvc进行存储,不需要管后端使用的什么存储
-
实现了存储的提供方和使用方的分离,方便管理,迁移
-
2、pv和pvc实验
- pv的后端使用的是nfs存储
1、创建pv
[root@master01 pv]# cat b1-pvc.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01
spec:
capacity:
storage: 5Gi # 大小为5G
accessModes: # 访问模式,声明,没有实际的意义
- ReadWriteOnce
nfs: # 使用的nfs作为后端存储
path: /nfsdata
server: 192.168.50.20
# pv全局可见的
[root@master01 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01 5Gi RWO Retain Available 104s
# RWO权限
# Retain 默认策略,还有delete,recyle策略
# claim 为空,表示还没有pvc进行绑定
# 状态是avaliable 可用的
1、pv的状态
-
available 没有被pvc绑定,可以被使用的
-
bound 已经与pvc进行绑定了
-
released 绑定的pvc被删除了,但是这个pv里面的数据还在,pv还在,但pv的策略是Retain时,触发这种,无法被pvc绑定,因此需要删除pv才能再次使用
2、pv的策略(persistentVolumeReclaimPolicy)
-
Retain 保留策略,删除pvc后,pv里面的数据保留,但是pv的状态变成了released状态,就不可用了,pvc无法进行绑定,必须是available状态才行,需要删除pv,重新创建,才能再次使用
-
Delete 删除策略,pvc删除,pv也被删除,动态制备这个是默认策略,
-
Recyle 回收策略,删除数据,nfs或者hostpath支持
3、pv的访问模式
跟后面的pvc访问模式都是一样的意思, 就是一个声明的意思,没有任何意义
-
ReadWriteOnce RWO 单节点读写
-
ReadOnlyMany ROX 多节点只读
-
ReadWriteMany RWX 多节点读写
-
ReadWriteOncePod 单节点pod读写
2、创建一个pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc01
spec:
accessModes:
- ReadWriteOnce # 访问模式需要保持一样的
resources:
requests:
storage: 5Gi # 申请的大小
[root@master01 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01 5Gi RWO Retain Bound default/pvc01 20m
# 发现pv被绑定了
[root@master01 pv]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc01 Bound pv01 5Gi RWO 4s
1、为什么会自动绑定了
-
通过权限进行匹配
-
pvc的容器大小 小于等与 pv的大小即可
-
如果有多个pvc的话,随机匹配,谁创建的快就优先匹配
-
一个pvc只能绑定一个pv,一个pv也是一样的,只能绑定一个pv
-
还受到storagename的影响,这个优先级是最高的,pv和pvc里面写这个字段,指定绑定的pv
2、pvc的状态
-
pending pvc没有被绑定
-
bound 成功被绑定
-
lost 删除了pv
-
terminating pvc正在被删除
3、pod使用pvc
apiVersion: v1
kind: Pod
metadata:
name: b1-pvc
spec:
volumes:
- name: pvc
persistentVolumeClaim: # 使用的pvc
claimName: pvc01 # pvc是哪一个
containers:
- name: b1-pvc
image: nginx:1.25
imagePullPolicy: IfNotPresent
volumeMounts:
- name: pvc
mountPath: /pvc # 挂载到容器里面
- 写入数据
[root@master01 pv]# kubectl exec -ti b1-pvc -- /bin/bash
root@b1-pvc:/# cd /pvc/
root@b1-pvc:/pvc# ls
1.txt nfs.txt
root@b1-pvc:/pvc# echo pvc > pvc.txt
- 查看后端的存储情况
# 也有数据
[root@master01 pv]# ls /nfsdata/
1.txt nfs.txt pvc.txt
4、删除pod,pvc
kubectl delete pod b1-pvc
[root@master01 pv]# kubectl delete pvc pvc01
# 查看pv状态,发现变成了released
[root@master01 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01 5Gi RWO Retain Released default/pvc01 36m
# 删除pv,再次创建pv,才能被使用
[root@master01 pv]# kubectl delete pv pv01
# 这个后端存储的数据还是没有变的,还是存在的
5、总结
-
pv是实际存储的,pvc是申请存储,与pv进行绑定才能被pod使用
-
pv底层的存储可以是nfs,rbd,cephfs
-
pv,pvc都是k8s的资源对象,虚拟出来的
-
nfs映射到pv,pv映射到pvc,最后以卷的形式挂载pod即可
四、nfs动态制备
-
就是上面创建pvc,pv还是有点麻烦的,每次创建一个pvc,还需要创建一个pv才行,pod只需要pvc即可
-
那么就有一个动态制备了,就是创建了一个pvc就能自动的创建一个pvc进行绑定,无需手动创建
-
nfs-csi,ceph-csi都可以实现的
-
nfs动态制备原理
-
创建一个pvc之后,先去找storageClassName
-
绑定了nfs驱动,里面定义了后端的nfs服务器的一些信息
-
在nfs服务器的共享目录下创建目录
-
pv使用这个目录,pvc绑定pv
-

-
存储类怎么关联的nfs驱动呢?
- 有参数指定的
1、nfs服务器部署
[root@master01 hpa]# cat /etc/exports
/nfsdata *(rw)
systemctl enable nfs-server --now
systemctl enable rpcbind --now
[root@master01 hpa]# showmount -e localhost
Export list for localhost:
/nfsdata *
2、部署nfs驱动
[root@master01 nfs]# git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
[root@master01 deploy]# pwd
/root/nfs/nfs-subdir-external-provisioner/deploy
- 都是部署在default下的
[root@master01 deploy]# kubectl apply -f rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
- 修改deployment.yaml文件
# 修改镜像
image: registry.cn-hangzhou.aliyuncs.com/cloudcs/nfs-subdir-external-provisioner:v4.0.2
# 对接nfs服务器配置
- name: NFS_SERVER
value: 192.168.50.20
- name: NFS_PATH
value: /nfsdata
volumes:
- name: nfs-client-root
nfs:
server: 192.168.50.20
path: /nfsdata
[root@master01 deploy]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-5cf5744c5f-78svw 1/1 Running 0 51s
2、创建storageClass
[root@master01 nfs]# cat class.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: "true" # 添加这个为默认的
name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiverOnDelete: "false"
[root@master01 nfs]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 3s
3、创建一个pvc出来
[root@master01 nfs]# cat pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc3
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-client # 使用的存储类是nfs-client,就会自动的创建pv
resources:
requests:
storage: 5Gi
[root@master01 nfs]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-b8640026-13ec-4cfa-bee8-e6363e634cd3 5Gi RWO Delete Bound default/pvc3 nfs-client 25s
# 自动创建出了pv
[root@master01 nfs]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc3 Bound pvc-b8640026-13ec-4cfa-bee8-e6363e634cd3 5Gi RWO nfs-client 26s
# nfs服务器自动创建了一个目录,用作pv的存储
[root@master01 nfs]# cd /nfsdata/
[root@master01 nfsdata]# ls
default-pvc3-pvc-b8640026-13ec-4cfa-bee8-e6363e634cd3
五、总结
-
在没有pv,pvc之前,pod需要直接使用存储,各种存储的写法不一样
-
有了pv,pvc之后,pod直接使用pvc,pv使用后端的存储,各个存储不一样,pod只关心有没有pvc,就可以了
-
pvc创建后,自动的创建pv
ceph
nfs
ceph支撑nfs

浙公网安备 33010602011771号