v1.16.7
https://kubernetes.io/docs/concepts/storage/storage-classes/
一、PV、PVC
https://kubernetes.io/docs/concepts/storage/persistent-volumes/
https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
虽然pod也可以直接挂载存储,但是管理不方便,特别是pod的数量越来越多。 而且pod可能是由开发维护的,而存储却是由运维负责。通过PV,PVC分开就方便多了。
PV
PV(PersistentVolumes)
定义了后端存储以及其他的存储参数。用来配置存储的。只关心后端存储。
PV可以通过静态与动态两种方式创建。静态就是手动创建PV资源。
如果是静态,就需要创建大量的PV来定义不同的存储与参数,如性能,冗余等,来满足不同需求的PVC。
PV有下面几种状态:
Available(可用)-- PV是一个空闲资源,尚未绑定到任何pvc;
Bound(已绑定)-- PV已经绑定到pvc;
Released(已释放)-- 所绑定的pvc已被删除,但是资源尚未被集群回收;
Failed(失败)-- PV自动回收操作失败。
静态与动态是可以并存的,因为PVC会先匹配静态PV,如果不匹配才会尝试动态的方式。
当管理员创建的所有静态PV均与用户的PVC不匹配时,群集可能会尝试动态地为PVC专门配置一个卷。此供应基于StorageClasses:PVC必须请求
storage class
,并且管理员必须已经创建并配置了该类,才能进行动态供应。如果请求的类是""
,就是禁用了动态配置。
静态的配置方式类似于这样,这是一个连接NFS的PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadOnlyMany
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- noatime
- _netdev
nfs:
path: /data/nfs
server: 172.100.102.66
capacity
设置存储容量,只有小于这个容量的PVC才能绑定。
现在存储大小是可以设置的唯一资源。将来的属性可能包括IOPS,吞吐量等。
volumeMode
卷模式,Filesystem
, block
。Filesystem
是默认值。
storageClassName
存储的类别。手动指定。主要用来区分服务级别。只有相同存储类的PV,PVC才能绑定。 没有设置存储类的PVC,只能绑定同样没有类的PV(如果启用访问控制:DefaultStorageClass
,可以给没有提供类的PVC设置默认的类)。
注意:类只是用来区分类型的参数。不管是静态还是动态。虽然动态里面需要创建存储类,但他们都是一个意思。先找静态指定类的PV,找不到再找指定类的动态供给。单独创建类也是为了对应不同的动态供给。
以前使用annotations里的volume.beta.kubernetes.io/storage-class代替storageClassName属性。此注释现在仍然有效;但是,将来的Kubernetes版本将不再支持它。
如:
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
persistentVolumeReclaimPolicy
回收策略, PV是否自动回收。删除PVC以后是否删除对应存储里的数据,然后PV自动变为可用状态。
Retain
: 手动回收。 pvc删除以后不会删除数据,pv会变成Released状态,无法使用。 需要手动删除重建。手动删除pv不会清除数据。 或者编辑pv,把claimRef
删除。
Recycle
: 自动回收。 相当于 rm -rf /thevolume/*。 pvc删除,数据清理完毕以后Pv会自动恢复到可用状态。
Delete
: 删除pv,pv连接的卷也会自动删除。 自动供给的NFS使用的是Delete,作用是删除NFS根目录下的卷目录。手动创建的不能使用Delete,缺少删除卷的插件。
目前只有NFS 和 HostPath 支持Recycle, AWS EBS, GCE PD, Azure Disk, and Cinder volumes 只支持Delete.
注意,nfs测试发现,就算是多个pv都在使用nfs里的东西,删除一个pvc也会执行rm -rf,如果各个pv都是使用的nfs根目录,那么数据就都没了。
accessModes
访问模式. 只有相同访问模式的PV,PVC才能绑定。
ReadWriteOnce
: 该卷可以通过单个节点以读写方式安装
ReadOnlyMany
: 该卷可以被许多节点只读安装
ReadWriteMany
: –该卷可以被许多节点读写安装
在CLI中,访问模式缩写为:
RWO
-ReadWriteOnce
ROX
-ReadOnlyMany
RWX
-ReadWriteMany
存储卷一次只能使用一种模式。
测试发现nfs的pv,pvc访问模式不管用。
使用ReadWriteOnce 也可以多节点写。
ReadOnlyMany 也可以写。
这些模式应该只是一个标识, 具体的实现还是后端的存储, 在nfs的测试中发现挂载参数都是PV mountOptions
指定的, 没有只读方面的参数。
mountOptions
挂载选项
以前使用annotations里的volume.beta.kubernetes.io/mount-options代替mountOptions属性。此注释仍然有效;但是,它将在以后的Kubernetes版本中完全弃用。
PVC
PVC(PersistentVolumeClaim)
PVC与PV是一一对应的绑定关系。Pod挂载PVC。只需要创建满足需求的PVC,而PVC会再自动与满足需求的PV绑定,如果没有找到匹配的PV并且没有动态供给,Pod会一直处于Pending状态。
PVC只能手动创建,只有PV可以动态创建。 Pod使用PVC,因为PVC的名称不变,所以不管pod在哪个节点,都是使用相同的数据。
pvc创建很简单,如:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: task-pv-claim1
spec:
storageClassName: slow
accessModes:
- ReadOnlyMany
resources:
requests:
storage: 3Gi
storageClassName
、accessModes、resources: pvc与pv的匹配会根据这些参数。
二、容器是怎么使用的
pod挂载PVC。
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim1
kubele挂载存储到节点目录。 因为实际实际是kubelet执行挂载的,所以节点需要安装挂载需要的软件。 如:NFS的nfs-utils。 ceph的ceph-common。
172.100.102.66:/data/nfs nfs4 146G 1.8G 145G 2% /data/kubelet-data/pods/00a5d85d-fbc4-4c5c-b921-986b05f7b617/volumes/kubernetes.io~nfs/pv0003
mount -t nfs -o _netdev,noatime 172.100.102.66:/data/nfs /data/kubelet-data/pods/00a5d85d-fbc4-4c5c-b921-986b05f7b617/volumes/kubernetes.io~nfs/pv0003
然后docker会挂载目录到容器里。
"Mounts": [
{
"Type": "bind",
"Source": "/data/kubelet-data/pods/00a5d85d-fbc4-4c5c-b921-986b05f7b617/volumes/kubernetes.io~nfs/pv0003",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
三、动态PV
https://kubernetes.io/docs/concepts/storage/storage-classes/
动态PV又叫做动态供给。就是在创建PVC以后,自动创建出PV。
只需要两步:
- 创建一个
StorageClass
,指定一些PV的回收策略以及挂载选项。最主要的是指定Provisioner
。 Provisioner
: 用来动态创建和管理PV的插件。每个存储都有不同的插件来管理PV,毕竟不同存储指定PV的参数是不一样的,从存储里清除数据的方式也都不一样。
Kubernetes内置了一些存储的Provisioner
, 而一些没有内置的,就需要使用外部的Provisioner
,通常就是运行一个Deployment。
查看内部支持的存储:
https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
不支持的常用的有: NFS, CerphFS。
创建StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
- debug
volumeBindingMode: Immediate
只要需要StorageClass
可以动态供给PV,都需要provisioner
、parameters
和reclaimPolicy
参数。
provisioner
就是上面提到的Provisioner
。一般以kubernetes.io
开头的都是内部支持的。
reclaimPolicy
回收策略,就是PV里的回收策略。只有Retain
与Delete
两个值。默认Delete
。
allowVolumeExpansion
一些特定的存储支持卷扩展,通过修改PVC可以修改卷的大小。没有测试过。
mountOptions
挂载选项。
parameters
用来描述存储的参数,不同的存储可能会有不同的参数。
volumeBindingMode
绑卷定模式。有两个值Immediate
与WaitForFirstConsumer
。
Immediate
: 表示 PVC 创建完便会立即绑定PV和动态预配置。
WaitForFirstConsumer
: 该模式将延迟PV的绑定和供应,直到创建使用PVC的Pod。将根据Pod的调度约束所指定的拓扑来选择或设置PV。
外部Provisioner
网址里是外部Provisioner
的仓库。
https://github.com/kubernetes-incubator/external-storage
这里测试一下安装NFS的外部Provisioner
。
https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client/deploy
其实网址里已经包含了所有需要用到的yaml文件。
分别是创建StorageCalss
,Provisioner
, 以及给Provisioner
授权的RBAC文件。 外部Provisioner
就是一个deployment。
两个test文件,一个是创建PVC的,一个是创建POD使用PVC的。
[root@k8s-master nfs]# ls
class.yaml deployment.yaml rbac.yaml
[root@k8s-master nfs]#
class文件一般不需要修改,里面的name一般也不修改,担心代码里有调用这个名称的。
[root@k8s-master nfs]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"
archiveOnDelete
: 参数表示是否归档。 默认的回收模式是delete
,pvc删除以后,pv也会删除,而pv所指定的nfs目录也会删除。
这个参数如果为 "true", pv所指定的目录会重命名,不会删除。如:
如果回收模式是Retain
, 则不会重命名。
deployment里面的nfs地址与路径需要修改。如:
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 172.100.102.66
- name: NFS_PATH
value: /data/nfs
volumes:
- name: nfs-client-root
nfs:
server: 172.100.102.66
path: /data/nfs
全部应用以后,看一下storageclass。
[root@k8s-master nfs]# kubectl get sc
NAME PROVISIONER AGE
managed-nfs-storage fuseim.pri/ifs 55s
name就是创建pvc的时候需要指定的。
PROVISIONER 指定的是deployment里面那个。
[root@k8s-master nfs]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-865d4bfccc-d89w6 1/1 Running 0 35s
等deployment里的pod启动完成就可以了。
测试
创建一个pvc:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: task-pv-claim15
spec:
storageClassName: managed-nfs-storage
accessModes:
- ReadOnlyMany
resources:
requests:
storage: 4Gi
应用以后再看看pv与pvc。
[root@k8s-master pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-0b7f5bbd-b1d8-4e31-94b7-20e8b5b22ff7 4Gi ROX Delete Bound default/task-pv-claim15 managed-nfs-storage 2s
[root@k8s-master pv]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
task-pv-claim15 Bound pvc-0b7f5bbd-b1d8-4e31-94b7-20e8b5b22ff7 4Gi ROX managed-nfs-storage 12s
[root@k8s-master pv]#
自动生成了pv,并且与pvc绑定了。
NFS存储里会创建一个目录来存放这个PVC的数据。
[root@haloackup nfs]# ls
default-task-pv-claim15-pvc-0b7f5bbd-b1d8-4e31-94b7-20e8b5b22ff7
[root@haloackup nfs]#
现在PV的回收模式是Delete
, PVC一旦删除,NFS里的这个目录又会被删除。
如果担心数据,可以修改class.yaml,添加reclaimPolicy: Retain
。如:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"
reclaimPolicy: Retain
class不能更新,需要删除重建,对已存在的pv没有影响。然后再创建PVC,所生成的PV回收模式就是Retain
了。
Pod挂载PVC就不演示了, 它只是挂载PVC的名称, 动态静态都没有什么变化。
而PVC始终是要手动创建的。
注意: 如果手动创建了相同StorageClass的PV, 并且条件也匹配。 这个PVC会与PV绑定,不会再动态的创建PV。 动态与静态是没有冲突的。
删除保护
https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#storage-object-in-use-protection
pvc删除以后, 数据是否保留是通过pv的回收模式。
而pvc的删除,只有在所有使用这个pvc的pod都删除以后才会删除。
pv也是一样, 只有与pvc解绑以后才能够删除。
其它
每个 PV 卷可以通过设置 节点亲和性 来定义一些约束,进而限制从哪些节点上可以访问此卷。 使用这些卷的 Pod 只会被调度到节点亲和性规则所选择的节点上执行。
https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#node-affinity
pvc可以设置selector 来进一步的过滤pv。只有标签相匹配的pv能够绑定到pvc上。
https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#selector