PV/PVC简介
PV:PersistentVolume
PVC:PersistentVolumeClaim
用于实现pod和storage的解耦,这样我们在修改存储的同时,不需要修改pod。
与NFS的区别,可以在PV和PVC的层面上实现对存储服务器的空间分配,存储权限管理等。
kubernetes在1.0版时开始支持PV和PVC。
PV:
是集群中由kubernetes管理员配置的一个网络存储,一个集群中的存储资源,不隶属于任何namespace。
PV的数据最终存储在硬件存储上,PV不负责数据持久化。
PV需要绑定给PVC并最终由pod挂载PVC来使用。
PV支持NFS,Cehp,商业存储或云提供商的特定存储等,可以自定义PV的类型是块还是文件存储,存储空间大小,访问模式等。
PV的生命周期独立于pod,即在使用PV的pod被删除后,PV中的数据不受影响。
PVC:
是pod对存储的请求,pod挂载pvc并将数据存储在PVC,而pvc需要绑定到pv才能使用。
pvc在使用的时候需要指定namespace,即pod要和pvc运行在一个namespace。
可以对pvc设定特定的空间大小,访问模式。
使用pvc的pod在被删除时,也可以对pvc中的数据无影响。
注意:pvc的大小不能大于pv
查看编写帮助:
# kubectl explain PersistentVolume
Capacity:当前pv空间大小;kubectl explain PersistentVolume.spec.capacity
accessModes访问模式:kubectl explain PersistentVolume.spec.accessModes
ReadWriteOnce:读写单节点挂载;RWO
ReadOnlyMany:只读多节点挂载;ROX
ReadWriteMany:读写多节点挂载;RWX
persistentVolumeReclaimPolicy:删除机制,即删除pv时,数据是否保留:kubectl explain PersistentVolume.spec.persistentVolumeReclaimPolicy
Retain:删除pv后保持原状,需要管理员手动删除;
Recycle:通常不配置,空间回收,及删除存储卷上的所有数据;
Delete: 通常不配置,自动删除存储卷;
volumeMode:卷类型:kubectl explain PersistentVolume.spec.volumeMode
定义存储卷使用的文件系统是块设备还是文件系统,默认为文件系统;
mountOptions:附加的挂载选项列表,以实现更细致的权限控制;
实验:
# 创建一个pv
apiVersion:v1
kind:PersistentVolume
metadata:
name:myserver-myapp-static-pv
spec:
capacity:
storage:10Gi
accessModes:
-ReadWriteOnce
nfs:
path:/data/k8sdata/test_pv
server:192.168.1.40
# kubectl get pv
注意:如果使用nfs为后端存储,如果权限认证错误,会出现unavailable的情况;
PVC:需要定义namespace;
# kubectl explain PersistentVolumeClaim
resources:定义pvc创建存储卷的空间大小;
accessModes访问模式:kubectl explain PersistentVolume.spec.accessModes
ReadWriteOnce:读写单节点挂载;RWO
ReadOnlyMany:只读多节点挂载;ROX
ReadWriteMany:读写多节点挂载;RWX
selector:标签选择器,选择要绑定的PV;
matchLables:标签名字;
matchExpressions:基于正则表达式匹配;
volumeName:要绑定的pv名称;
volumeMode:卷类型;
定义pvc使用的文件系统是块还是文件存储,默认是文件存储;
实验
# 创建一个pvc
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:myserver-myapp-static-pvc
namespace:myserver
spec:
volumeName:myserver-myapp-static-pv
accessModes:
-ReadWriteOnce
resources:
requests:
storage:10Gi
实例,挂载pvc到pod
kind:Deployment
#apiVersion: extensions/v1beta1
apiVersion:apps/v1
metadata:
labels:
app:myserver-myapp
name:myserver-myapp-deployment-name
namespace:myserver
spec:
replicas:1
selector:
matchLabels:
app:myserver-myapp-frontend
template:
metadata:
labels:
app:myserver-myapp-frontend
spec:
containers:
-name:myserver-myapp-container
image:nginx:1.20.0
#imagePullPolicy: Always
volumeMounts:
-mountPath:"/usr/share/nginx/html/statics"
name:statics-datadir
volumes:
-name:statics-datadir
persistentVolumeClaim:
claimName:myserver-myapp-static-pvc
kind:Service
apiVersion:v1
metadata:
labels:
app:myserver-myapp-service
name:myserver-myapp-service-name
namespace:myserver
spec:
type:NodePort
ports:
-name:http
port:80
targetPort:80
nodePort:30080
selector:
app:myserver-myapp-frontend
volume存储类型:static静态,dynamin动态;
static静态:需要在使用前手动创建pv,pvc并配置绑定关系。指定pvc挂载到哪个pod;
dynamin动态:优先创建一个storageclass存储类,后期pod可以通过存储类中的规则动态创建各自所使用的pvc;
删除过程是从后往前(创建顺序相反);
动态创建pv,pvc时需要用到github的项目,地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
# 创建用户和授权
apiVersion:v1
kind:Namespace
metadata:
name:nfs
---
apiVersion:v1
kind:ServiceAccount
metadata:
name:nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace:nfs
---
kind:ClusterRole
apiVersion:rbac.authorization.k8s.io/v1
metadata:
name:nfs-client-provisioner-runner
rules:
-apiGroups: [""]
resources: ["nodes"]
verbs: ["get","list","watch"]
-apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get","list","watch","create","delete"]
-apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get","list","watch","update"]
-apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get","list","watch"]
-apiGroups: [""]
resources: ["events"]
verbs: ["create","update","patch"]
---
kind:ClusterRoleBinding
apiVersion:rbac.authorization.k8s.io/v1
metadata:
name:run-nfs-client-provisioner
subjects:
-kind:ServiceAccount
name:nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace:nfs
roleRef:
kind:ClusterRole
name:nfs-client-provisioner-runner
apiGroup:rbac.authorization.k8s.io
---
kind:Role
apiVersion:rbac.authorization.k8s.io/v1
metadata:
name:leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace:nfs
rules:
-apiGroups: [""]
resources: ["endpoints"]
verbs: ["get","list","watch","create","update","patch"]
---
kind:RoleBinding
apiVersion:rbac.authorization.k8s.io/v1
metadata:
name:leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace:nfs
subjects:
-kind:ServiceAccount
name:nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace:nfs
roleRef:
kind:Role
name:leader-locking-nfs-client-provisioner
apiGroup:rbac.authorization.k8s.io
# 创建存储类及授权;
apiVersion:storage.k8s.io/v1
kind:StorageClass
metadata:
name:managed-nfs-storage
provisioner:k8s-sigs.io/nfs-subdir-external-provisioner# or choose another name, must match deployment's env PROVISIONER_NAME'
reclaimPolicy:Retain#PV的删除策略,默认为delete,删除PV后立即删除NFS server的数据
mountOptions:
#- vers=4.1 #containerd有部分参数异常
#- noresvport #告知NFS客户端在重新建立网络连接时,使用新的传输控制协议源端口
-noatime#访问文件时不更新文件inode中的时间戳,高并发环境可提高性能
parameters:
#mountOptions: "vers=4.1,noresvport,noatime"
archiveOnDelete:"true" #删除pod时保留pod数据,默认为false时为不保留数据
# 指定到哪个nfs上创建pv;
apiVersion:apps/v1
kind:Deployment
metadata:
name:nfs-client-provisioner
labels:
app:nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace:nfs
spec:
replicas:1
strategy:#部署策略
type:Recreate
selector:
matchLabels:
app:nfs-client-provisioner
template:
metadata:
labels:
app:nfs-client-provisioner
spec:
serviceAccountName:nfs-client-provisioner
containers:
-name:nfs-client-provisioner
#image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
image:registry.cn-qingdao.aliyuncs.com/zhangshijie/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
-name:nfs-client-root
mountPath:/persistentvolumes
env:
-name:PROVISIONER_NAME
value:k8s-sigs.io/nfs-subdir-external-provisioner
-name:NFS_SERVER
value:192.168.1.40
-name:NFS_PATH
value:/data/volumes
volumes:
-name:nfs-client-root
nfs:
server:192.168.1.40
path:/data/volumes
注意:当nfs服务运行时,修改nfs配置,要使其配置生效就需要重启nfs服务,但重启服务必然会造成业务闪断,那么可以使用#exportfs -arv来让配置重新生效;
# 创建测试PVC;
kind:PersistentVolumeClaim
apiVersion:v1
metadata:
name:myserver-myapp-dynamic-pvc
namespace:myserver
spec:
storageClassName:managed-nfs-storage#调用的storageclass 名称
accessModes:
-ReadWriteMany#访问权限
resources:
requests:
storage:500Mi#空间大小
这个时候,可以在nfs服务器上/data/volumes路径下查看到出现新的路径;
# 创建pod并绑定pvc;
kind:Deployment
#apiVersion: extensions/v1beta1
apiVersion:apps/v1
metadata:
labels:
app:myserver-myapp
name:myserver-myapp-deployment-name
namespace:myserver
spec:
replicas:1
selector:
matchLabels:
app:myserver-myapp-frontend
template:
metadata:
labels:
app:myserver-myapp-frontend
spec:
containers:
-name:myserver-myapp-container
image:nginx:1.20.0
#imagePullPolicy: Always
volumeMounts:
-mountPath:"/usr/share/nginx/html/statics"
name:statics-datadir
volumes:
-name:statics-datadir
persistentVolumeClaim:
claimName:myserver-myapp-dynamic-pvc
---
kind:Service
apiVersion:v1
metadata:
labels:
app:myserver-myapp-service
name:myserver-myapp-service-name
namespace:myserver
spec:
type:NodePort
ports:
-name:http
port:80
targetPort:80
nodePort:30080
selector:
app:myserver-myapp-frontend
注意:pod和pvc一定要在同一个namespace中;