千家信息网

kubernetes的存储类介绍

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,k8s有很多的服务,很多的资源对象。如果要去创建服务,做数据持久化,需要预先知道可用PV有哪些?如果为了这个服务去提前创建PV,那么我们还需要知道,这个服务,大概需要多大的空间?环境介绍主机IP地址服
千家信息网最后更新 2024年11月27日kubernetes的存储类介绍

k8s有很多的服务,很多的资源对象。

如果要去创建服务,做数据持久化,需要预先知道可用PV有哪些?

如果为了这个服务去提前创建PV,那么我们还需要知道,这个服务,大概需要多大的空间?

环境介绍

主机IP地址服务
master192.168.1.21k8s
node01192.168.1.22k8s
node02192.168.1.23k8s

基于[ https://blog.51cto.com/14320361/2464655]() 的实验继续进行

存储类介绍

Kubernetes集群管理员通过提供不同的存储类,可以满足用户不同的服务质量级别、备份策略和任意策略要求的存储需求。动态存储卷供应使用StorageClass进行实现,其允许存储卷按需被创建。如果没有动态存储供应,Kubernetes集群的管理员将不得不通过手工的方式类创建新的存储卷。通过动态存储卷,Kubernetes将能够按照用户的需要,自动创建其需要的存储。

基于StorageClass的动态存储供应整体过程如下图所示:

1)集群管理员预先创建存储类(StorageClass);
2)用户创建使用存储类的持久化存储声明(PVC:PersistentVolumeClaim);
3)存储持久化声明通知系统,它需要一个持久化存储(PV: PersistentVolume);
4)系统读取存储类的信息;
5)系统基于存储类的信息,在后台自动创建PVC需要的PV;
6)用户创建一个使用PVC的Pod;
7)Pod中的应用通过PVC进行数据的持久化;
8)而PVC使用PV进行数据的最终持久化处理。

先来简单看一下这张图实现的过程,然后我们再来研究一下

说在前面的话,静态供给的话,会需要我们手动去创建pv,如果没有足够的资源,找不到合适的pv,那么pod就会处于pending等待的状态,就是说找不到合适的伴侣了,所以解决这两种问题,就给出了这种动态供给,主要是能够自动帮你创建pv
,就是你需要多大的容量,就自动给你创建多大的容量,也就是pv,k8s帮你创建了,创建pvc的时候就需要找pv了,这个时候就交给这个存储类了,而存储类呢,去帮你创建这些pv,存储类呢,就是实现了对指定存储的一个支持,直接帮你去调用api去创建存储类,所以就不需要人工的去帮你创建pv了。
而你去想想,当节点比较多,业务比较多的时候,再去人工手动创建pv,量还是很大的,而且也不是很好去维护。
而动态供给主要的一个实现就是StorageClass存储对象,其实它就是声明你使用哪个存储,然后呢帮你去连接,再帮你去自动创建pv。

举个例子更好去理解
话不多说下图

其实它是一个基于NFS实现的一个pv供给,它大概流程是这样的,我们可能会创建一个statefulset有状态的应用存储,然后有一个管理的nfs-storageClass,因为nfs目前是不支持这个自动的创建pv的,我们可以利用社区实现的插件来完成这个pv的自动创建,也就是StorageClass这一块,创建完之后,然后pod再去引用。

一,Storage Class(存储类)

作用:它可以动态的自动的创建所需要的PV

Provisioner(供给方,提供者):及提供了存储资源的存储系统。k8s内建有多重供给方,这些供给方的名字都以"kubernetes.io"为前缀。并且还可以自定义。

Parameters(参数):存储类使用参数描述要关联到的存储卷,注意不同的供给方参数也不同。

ReclaimPlicy: PV的回收策略,可用值有Delete(默认)和Retain

(1)确定基于NFS服务来做的SC。NFS开启

[root@master yaml]# showmount -e

(2)需要RBAC权限。

RBAC:rbac是k8s的API的安全策略,是基于用户的访问权限的控制。规定了谁,可以有什么样的权限。

为了给SC资源操作k8s集群的权限。

[root@master yaml]# vim rbac-rolebind.yamlkind: NamespaceapiVersion: v1metadata:  name: bdqn-test---apiVersion: v1kind: ServiceAccountmetadata:  name: nfs-provisioner  namespace: bdqn-test---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:  name: nfs-provisioner-runner  namespace: bdqn-testrules:   -  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: ["watch", "create", "update", "patch"]   -  apiGroups: [""]      resources: ["services", "endpoints"]      verbs: ["get","create","list", "watch","update"]   -  apiGroups: ["extensions"]      resources: ["podsecuritypolicies"]      resourceNames: ["nfs-provisioner"]      verbs: ["use"]---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:  name: run-nfs-provisionersubjects:  - kind: ServiceAccount    name: nfs-provisioner    namespace: bdqn-testroleRef:  kind: ClusterRole  name: nfs-provisioner-runner  apiGroup: rbac.authorization.k8s.io

运行一下

[root@master yaml]# kubectl apply -f rbac-rolebind.yaml 

(3)nfs-deployment

作用:其实它是一个NFS客户端。但它通过K8S的内置的NFS驱动挂载远端的NFS服务器到本地目录;然后将自身作为storage provider,关联storage class。

[root@master yaml]# vim nfs-deployment.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: nfs-client-provisioner  namespace: bdqn-testspec:  replicas: 1  strategy:    type: Recreate  template:    metadata:      labels:        app: nfs-client-provisioner    spec:      serviceAccount: nfs-provisioner    #指定账户      containers:        - name: nfs-client-provisioner          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner          volumeMounts:            - name: nfs-client-root              mountPath:  /persistentvolumes   #指定容器内的挂载目录          env:            - name: PROVISIONER_NAME            #这是这个容器内置的变量              value: bdqn-test                  #这是上面变量的值(名字)            - name: NFS_SERVER                  #内置变量,用于指定nfs服务的IP              value: 192.168.1.21            - name: NFS_PATH                    #内置变量,指定的是nfs共享的目录              value: /nfsdata      volumes:                                  #这下面是指定上面挂载到容器内的nfs的路径及IP        - name: nfs-client-root          nfs:            server: 192.168.1.21            path: /nfsdata

执行一下

[root@master yaml]# kubectl apply -f nfs-deployment.yaml

(4)创建storageclass

[root@master yaml]# vim test-storageclass.yamlapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:  name: stateful-nfs  namespace: bdqn-testprovisioner: bdqn-test  #这里要和第三个nfs-client-provisioner的env环境变量中的value值对应。reclaimPolicy: Retain   #回收策略为:retain,还有一个默认的值为"default"

执行一下

[root@master yaml]# kubectl apply -f test-storageclass.yaml

(5)创建PVC

[root@master yaml]# vim test-pvc.yamlapiVersion: v1kind: PersistentVolumeClaimmetadata:  name: test-claim  namespace: bdqn-testspec:  storageClassName: stateful-nfs   #定义存储类的名字,要和SC的名字对应  accessModes:    - ReadWriteMany         #访问模式为RWM  resources:    requests:      storage: 500Mi

执行一下

[root@master yaml]# kubectl apply -f test-pvc.yaml 

查看一下

[root@master yaml]# kubectl get pvc

(6)创建一个Pod

[root@master yaml]# vim test-pod.yamlkind: PodapiVersion: v1metadata:  name: test-pod  namespace: bdqn-testspec:  containers:  - name: test-pod    image: busybox    args:      - /bin/sh      - -c      - sleep 30000    volumeMounts:      - name: nfs-pvc        mountPath: /test  restartPolicy: OnFailure  volumes:    - name: nfs-pvc      persistentVolumeClaim:        claimName: test-claim  #这的名字要和PVC的名字一致

执行一下

[root@master yaml]# kubectl apply -f  test-pod.yaml 

查看一下

[root@master yaml]# kubectl get pod -n bdqn-test 

(7)容器中添加内容,并查看挂载目录

进入容器修改页面内容

[root@master yaml]# kubectl exec -it test-pod -n bdqn-test /bin/sh/ # cd test//test # touch test-file/test # echo 123456 > test-file /test # cat test-file 123456

查看挂载目录

[root@master yaml]# ls /nfsdata/bdqn-test-test-claim-pvc-79ddfcf1-65ae-455f-9e03-5bcfe6c6ce15web1web2[root@master yaml]# cat /nfsdata/bdqn-test-test-claim-pvc-79ddfcf1-65ae-455f-9e03-5bcfe6c6ce15/test-file 123456

如果,K8S集群中, 有很多类似的PV, PVC在去向PV申请空间的时候,不仅会考虑名称以及访问控制模式,还会考虑你申请空间的大小,会分配给你最合适大小的PV。

运行一个web服务,采用Deployment资源,基于nginx镜像,replicas为3个。数据持久化目录为nginx服务的主访问目录:/usr/share/nginx/html

创建一个PVC,与上述资源进行关联。

1. 基于nfs服务来做的PV和pvc

下载nfs所需安装包

[root@node02 ~]# yum -y install nfs-utils  rpcbind

创建共享目录

[root@master ~]# mkdir /nfsdata

创建共享目录的权限

[root@master ~]# vim /etc/exports/nfsdata *(rw,sync,no_root_squash)

开启nfs和rpcbind

[root@master ~]# systemctl start nfs-server.service [root@master ~]# systemctl start rpcbind

测试一下

[root@master ~]# showmount -e

2.先创建两个PV, web- pV1(1G) ,web-pv2 (2G)

web1

[root@master yaml]# vim web.yaml apiVersion: v1kind: PersistentVolumemetadata:  name: web-pvspec :  capacity:    storage: 1Gi  accessModes:    - ReadWriteOnce  persistentVolumeReclaimPolicy: Recycle  storageClassName: nfs  nfs:    path: /nfsdata/web1    server: 192.168.1.21

web2

[root@master yaml]# vim web2.yaml apiVersion: v1kind: PersistentVolumemetadata:  name: web-pv2spec :  capacity :    storage: 2Gi  accessModes:    - ReadWriteOnce  persistentVolumeReclaimPolicy: Recycle  storageClassName: nfs  nfs:    path: /nfsdata/web2    server: 192.168.1.21
3.创建所需文件夹
[root@master yaml]# mkdir /nfsdata/web1[root@master yaml]# mkdir /nfsdata/web2
4.执行一下web和web2
[root@master yaml]# kubectl apply -f web.yaml [root@master yaml]# kubectl apply -f web2.yaml 
5.查看一下
[root@master yaml]# kubectl get pv

6.创建web的pvc的yaml文件
[root@master yaml]# vim web-pvc.yaml apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: web-pvcspec:  accessModes:  - ReadWriteOnce  resources:    requests:      storage: 1Gi  storageClassName: nfs

执行一下

[root@master yaml]# kubectl apply -f web-pvc.yaml 

查看一下

[root@master yaml]# kubectl get pvc

系统会自动给pvc一个相近内存的pv,所以选择了1G的那个

7.创建pod的yaml文件
[root@master yaml]# vim web-pod.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: web-podspec:  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:      - image: nginx        name: nginx        volumeMounts:        - name: web-test          mountPath: /usr/share/nginx/html      volumes:      - name: web-test        persistentVolumeClaim:          claimName: web-pvc
执行一下
[root@master yaml]# kubectl apply -f web-pod.yaml 
查看一下
[root@master yaml]# kubectl get pod

8. 访问一下nginx的网页
查看一下nginx的ip
[root@master yaml]# kubectl get pod -o wide

进入容器设置网页内容
root@master yaml]# kubectl exec -it web-pod-8686d9c594-qxhr9 /bin/bashroot@web-pod-8686d9c594-qxhr9:/# cd /usr/share/nginx/html/root@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# lsroot@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# echo 123456 > index.htmlroot@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# exit
访问一下
[root@master yaml]# curl 10.244.2.17

如果两个PV,大小一样,名称一样,访问控制模式不一样,PVC会关联哪一个? (验证PV和PVC 关联的时候,访问模式必须一样)

两个PV,大小一样,名称一样,访问控制模式不一样

<1>创建两个pv
web1
[root@master yaml]# vim web1.yaml apiVersion: v1kind: PersistentVolumemetadata:  name: web-pvspec :  capacity:    storage: 1Gi  accessModes:    - ReadWriteOnce  #能以读-写mount到单个的节点  persistentVolumeReclaimPolicy: Recycle  storageClassName: nfs  nfs:    path: /nfsdata/web1    server: 192.168.1.21
web2
[root@master yaml]# vim web2.yaml apiVersion: v1kind: PersistentVolumemetadata:  name: web-pvspec :  capacity:    storage: 1Gi  accessModes:    - ReadWriteMany        #能以读-写mount到多个的节点  persistentVolumeReclaimPolicy: Recycle  storageClassName: nfs  nfs:    path: /nfsdata/web1    server: 192.168.1.21
创建所需文件
[root@master yaml]# mkdir /nfsdata/web1
执行一下
[root@master yaml]# kubectl apply -f web1.yaml [root@master yaml]# kubectl apply -f web2.yaml 

<2>创建pvc
[root@master yaml]# vim web-pvc.yaml apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: web-pvcspec:  accessModes:  - ReadWriteMany    #能以读-写mount到多个的节点  resources:    requests:      storage: 1Gi  storageClassName: nfs
执行一下
[root@master yaml]# kubectl apply -f web-pvc.yaml 
<3>查看一下
[root@master yaml]# kubectl get pv

[root@master yaml]# kubectl get pvc

现在可以看到pv和pvc关联成功,但是为什么只有一个pv呢?(pv挂载的目录要相同)

那是因为当创建了两个相同名字的pv时它并不会认为这是两个不同的pv,而会把他们当成是同一个pv,后创建的pv会刷新前面创建的pv。然后,当创建了pvc,并且pvc的访问模式和后面创建pv的访问模式一样,他们就会关联成功,反之不成功。(当然这些条件下还需要考虑,pv的内存)

(1)以自己的名称创建一个名称空间。以下所有资源都在此名称空间之下。

<1>编写namespace的yam文件

[root@master yaml]# vim namespace.yaml kind: NamespaceapiVersion: v1metadata:  name: xgp-znb

<2>执行一下

[root@master yaml]# kubectl apply -f namespace.yaml 

<3>查看一下

[root@master yaml]# kubectl get ns

(2)设置rbac权限。

下载所需镜像

docker pull registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner

<1>编写rbac的yam文件

[root@master yaml]# vim rbac-rolebind.yamlkind: NamespaceapiVersion: v1metadata:  name: xgp-znb---apiVersion: v1kind: ServiceAccountmetadata:  name: nfs-provisioner  namespace: xgp-znb---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:  name: nfs-provisioner-runner  namespace: xgp-znbrules:   -  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: ["watch", "create", "update", "patch"]   -  apiGroups: [""]      resources: ["services", "endpoints"]      verbs: ["get","create","list", "watch","update"]   -  apiGroups: ["extensions"]      resources: ["podsecuritypolicies"]      resourceNames: ["nfs-provisioner"]      verbs: ["use"]---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:  name: run-nfs-provisionersubjects:  - kind: ServiceAccount    name: nfs-provisioner    namespace: xgp-znbroleRef:  kind: ClusterRole  name: nfs-provisioner-runner  apiGroup: rbac.authorization.k8s.io

<2>执行一下

[root@master yaml]# kubectl apply -f  rbac-rolebind.yaml 

(3)创建nfs-deployment.yaml

<1>编写deployment的yam文件

[root@master yaml]# vim nfs-deployment.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: nfs-client-provisioner  namespace: xgp-znbspec:  replicas: 1  strategy:    type: Recreate  template:    metadata:      labels:        app: nfs-client-provisioner    spec:      serviceAccount: nfs-provisioner      containers:        - name: nfs-client-provisioner          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner          volumeMounts:            - name: nfs-client-root              mountPath:  /persistentvolumes          env:            - name: PROVISIONER_NAME              value: xgp-znb            - name: NFS_SERVER              value: 192.168.1.21            - name: NFS_PATH              value: /nfsdata      volumes:        - name: nfs-client-root          nfs:            server: 192.168.1.21            path: /nfsdata

<2>执行一下

[root@master yaml]# kubectl apply -f nfs-deployment.yaml

(4)创建storageclass自动创建PV。

<1>编写storageclass的yam文件

[root@master yaml]# vim storageclass.yamlapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:  name: test-scprovisioner: xgp-znb   #通过provisioner字段关联到上述DeployreclaimPolicy: Retain

<2>执行一下

[root@master yaml]# kubectl apply -f storageclass.yaml

(5)创建PVC

<1>编写PVC的yaml文件

[root@master yaml]# vim pvc.yamlapiVersion: v1kind: PersistentVolumeClaimmetadata:  name: test-claim  namespace: xgp-znbspec:  storageClassName: test-sc  accessModes:    - ReadWriteMany  resources:    requests:      storage: 500Mi

<2>执行一下

[root@master yaml]# kubectl apply -f pvc.yaml 

<3>查看一下

[root@master yaml]# kubectl get pvc -n xgp-znb

(6)创建一个Pod, 基于nginx运行一个web服务,使用Deployment资源对象,replicas=3.持久化存储目录为默认主目录

<1>编写deployment的yam文件

[root@master yaml]# vim pod.yaml apiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: web-pod  namespace: xgp-znbspec:  replicas: 3  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:      - image: nginx        name: nginx        volumeMounts:        - name: web-test          mountPath: /usr/share/nginx/html      volumes:      - name: web-test        persistentVolumeClaim:          claimName: test-claim

<2>执行一下

[root@master yaml]# kubectl apply -f pvc.yaml 

<3>查看一下

[root@master yaml]# kubectl get pod -n xgp-znb

(7)访问nginx页面

修改nginx主页

[root@master yaml]# kubectl exec -it web-pod-8cd956cc7-6szjb -n xgp-znb /bin/bash//进入容器之中root@web-pod-8cd956cc7-6szjb:/# echo  xgp-znb > /usr/share/nginx/html/index.html//添加自定义内容主机

访问一下

[root@master yaml]# curl 10.244.2.18

五个可移植性建议

  1. 把你的 pvc,和 其它一系列配置放一起, 比如说deployment,configmap
  2. 不要把你的pv放在其它配置里, 因为用户可能没有权限创建pv
  3. 初始化pvc 模版的时候, 提供一个storageclass
  4. 在你的工具软件中,watch那些没有bound的pvc,并呈现给用户
  5. 集群启动的时候启用DefaultStorageClass, 但是不要指定某一类特定的class, 因为不同provisioner的class,参数很难一致

volumn phase

1. 在PVC中绑定一个PV,可以根据下面几种条件组合选择
  • Access Modes, 按照访问模式选择pv
  • Resources, 按照资源属性选择, 比如说请求存储大小为8个G的pv
  • Selector, 按照pv的label选择
  • Class, 根据StorageClass的class名称选择, 通过annotation指定了Storage Class的名字, 来绑定特定类型的后端存储
2. 关于根据class过滤出pv的说明:所有的 PVC 都可以在不使用 StorageClass 注解的情况下,直接使用某个动态存储。把一个StorageClass 对象标记为 "default" 就可以了。StorageClass 用注解http://storageclass.beta.kubernetes.io/is-default-class 就可以成为缺省存储。有了缺省的 StorageClass,用户创建 PVC 就不用 storage-class 的注解了,1.4 中新加入的DefaultStorageClass 准入控制器会自动把这个标注指向缺省存储类。PVC 指定特定storageClassName,如fast时, 绑定名称为fast的storageClassPVC中指定storageClassName为""时, 绑定no class的pv(pv中无class annotation, 或者其值为"")PVC不指定storageClassName时, DefaultStorageClass admission plugin 开启与否(在apiserver启动时可以指定), 对default class的解析行为是不同的。当DefaultStorageClass admission plugin启用时, 针对没有storageClass annotation的pvc,DefaultStorageClass会分配一个默认的class, 这个默认的class需要用户指定,比如在创建storageclass对象时加入annotation,如 http://storageclass.beta.kubernetes.io/is-default-class: "true" 。如果有多个默认的class, 则pvc会被拒绝创建, 如果用户没有指定默认的class, 则这个DefaultStorageClass admission plugin不会起任何作用。 pvc会找那些no class的pv做绑定。当DefaultStorageClass admission plugin没有启用时, 针对没有storageClass annotation的pvc, 会绑定no class的pv(pv中无class annotation, 或者其值为"")
0