首先存储卷不和某个具体的K8S节点绑定,而是独立于K8S节点存在的,整个存储集群和K8S集群是两个集群,相互独立。
PV的全称是: PersistentVolume
(持久化卷),是对底层的共享存储的一种抽象,PV由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如Ceph、GlusterFS、NFS等,都是通过插件机制完成与共享存储的对接
PVC的全称是: PersistenVolumeClaim
(持久化卷声明),PVC是用户存储的一种声明,PVC和Pod比较类型,Pod是消耗节点,PVC消耗的是PV资源,Pod可以请求CPU的内存,而PVC可以请求特定的存储空间和访问模式。对于真正存储的用户不需要关心底层的存储实现细节,只需要直接使用PVC即可
首先我们看下PV和PVC的生命周期过程:
1、资源供应 (Provisioning)
资源供应 就是集群管理员(k8s集群)将volume虚拟化为很多个PV,目的就是创建合适的PV,有静态模式和动态模式。
- 静态模式:集群管理员手工创建许多PV,在定义PV时需要将后端存储的特性进行设置
- 动态模式:集群管理员无须手工创建PV,而是通过StorageClass的设置对后端存储进行描述,标记为某种 “类型(Class)”。此时要求PVC对存储的类型进行声明,系统将自动完成PV的创建及PVC的绑定。PVC可以声明Class为””,说明该PVC禁止使用动态模式
2、资源绑定 (Binding)
用户定义好PVC后,系统会根据PVC对存储的请求选择一个满足PVC要求的PV(PV的存在可能比PVC请求的大),找到就绑定,PV就被该PVC独占,不能和其他PVC绑定,如果没找到就一直处于pending中。如果资源供应使用的是动态模式,则系统在PVC找到合适的StorageClass后,将会自动创建PV并完成PVC的绑定。
3、资源使用 (Using)
POD创建可以绑定PVC,也可以多个POD挂载同一个PVC即共享多个实例共同访问一块存储空间
4、资源释放 (Releasing):
当用户对存储资源使用哪个完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为已释放,但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还留在存储设备上,只有在清除之后该PV才能继续使用
5、资源回收 (Reclaiming)
对于PV,管理员可以设定回收策略(Reclaim Policy)用于设置与之绑定的PVC释放资源之后,对于遗留数据如何处理。只有PV的存储空间完成回收,才能供新的PVC绑定和使用。
对于上述生命周期过程,对于PV的不同状态:
Available (可用): 表示可用状态,还未被任何PVC绑定 (资源供应、资源释放<数据清除完>)
Bound (已绑定):已经绑定到某个PVC (资源绑定、资源使用)
Released (已释放):对应的PVC已经删除,但资源还没有被集群收回 (资源释放<数据未清除>)
Failed:PV自动回收失败
下面说下怎么创建PV:
首先要创建存储服务,以NFS存储为例:https://www.csdn.net/gather_26/MtjaggzsOTk0NTItYmxvZwO0O0OO0O0O.html
定义好PV模型及pv的yaml文件:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1 #pv名称
spec:
capacity: #存储能力,一个pv对象都要指定一个存储能力,目前仅支持存储空间的设置
storage: 1Gi #存储空间
accessModes:
- ReadWriteOnce #访问模式
persistentVolumeReclaimPolicy: Recycle #回收策略
nfs: #服务模式 (nfs、ceph、hostpath等)
path: /data/k8s-volume #共享数据目录挂载点
server: 192.168.1.4044 #nfs服务器地址
其中访问模式有三种:
ReadWriteOnce (RWO) 读写权限,但是只能被单个节点挂载
ReadOnlyMany (ROX) 只读权限,可能被多个节点挂载
ReadWriteMany (RWX) 读写权限,可以被多个节点挂载
回收策略也有三种:
Retain (保留) 保留数据,需要管理员手动清理
Recycle (回收) 清除PV中的数据,效果相当于执行删除命令
Delete (删除) 与PV相连的后端存储完成volume的删除操作,常见于云服务商的存储服务
创建PV:
[root]# kubectl apply -f pv.yaml
persistentvolume/pv1 created
查看PV:
[root]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Recycle Available 5s
如果PV被PVC绑定,会有CLAIM信息:
创建PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
[root@harbor ~]# kubectl apply -f pv.yaml
persistentvolume/pv1 created
[root@harbor ~]# kubectl get pvc -n default
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound pv1 1Gi RWO 71s
[root@harbor ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Recycle Bound default/pvc-nfs 4m35s
# 这里我们可以看到,当我们创建pvc之后,pv的状态变成了Bound绑定状态,并且和pvc的状态相同。并且可以看到pvc已经绑定到名称为pv1的volume上,同时在pv上可以看到绑定到名称为pvc-nfs的pvc中
其中查询PVC信息要带namespaces,因为PVC被POD使用必须归属某个命名空间
但是我们怎么通过创建PVC绑定我们需要的PV呢,这边就涉及label的使用了,在k8s中pod绑定node等都是通过label来的:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
labels: #这里将pv设置一个labels
app: nfs
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/k8s-volume
server: 192.168.1.144
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc2-nfs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
selector: ##pvc匹配标签为app=nfs的pv
matchLabels:
app: nfs
下面我们创建deployment使用PVC:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pv-nfs-nginx
spec:
replicas: 3
selector:
matchLabels:
app: pv-nfs-nginx
template:
metadata:
labels:
app: pv-nfs-nginx
spec:
containers:
- name: pv-nfs-nginx
image: nginx
ports:
- containerPort: 801
volumeMounts: #挂载,首先添加需要挂载的目录
- name: pv-nginx #挂载点的名称
mountPath: /usr/share/nginx/html #挂载点的路径
volumes: #绑定
- name: pv-nginx
persistentVolumeClaim: #将镜像中的nginx目录挂载到下面名称的pvc中
claimName: pvc2-nfs #pvc名称
---
apiVersion: v1
kind: Service
metadata:
name: nfs-pvc
labels:
app: pv-nfs-nginx
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 324
selector:
app: pv-nfs-nginx
deploy是replicaset上一层的控制器,而service为deployment对外提供访问服务的能力的,而本项目是没有使用deployment而只使用了replicaset,且也没有使用service