如果要去创建服务,做数据持久化,需要预先知道可用PV有哪些?
成都创新互联专注于磴口企业网站建设,响应式网站建设,电子商务商城网站建设。磴口网站建设公司,为磴口等地区提供建站服务。全流程按需网站建设,专业设计,全程项目跟踪,成都创新互联专业和态度为您提供的服务
如果为了这个服务去提前创建PV,那么我们还需要知道,这个服务,大概需要多大的空间?
主机 | IP地址 | 服务 |
---|---|---|
master | 192.168.1.21 | k8s |
node01 | 192.168.1.22 | k8s |
node02 | 192.168.1.23 | k8s |
基于[ 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再去引用。
作用:它可以动态的自动的创建所需要的PV
Provisioner(供给方,提供者):及提供了存储资源的存储系统。k8s内建有多重供给方,这些供给方的名字都以“kubernetes.io”为前缀。并且还可以自定义。
Parameters(参数):存储类使用参数描述要关联到的存储卷,注意不同的供给方参数也不同。
ReclaimPlicy: PV的回收策略,可用值有Delete(默认)和Retain
[root@master yaml]# showmount -e
RBAC:rbac是k8s的API的安全策略,是基于用户的访问权限的控制。规定了谁,可以有什么样的权限。
为了给SC资源操作k8s集群的权限。
[root@master yaml]# vim rbac-rolebind.yaml
kind: Namespace
apiVersion: v1
metadata:
name: bdqn-test
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
namespace: bdqn-test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-provisioner-runner
namespace: bdqn-test
rules:
- 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: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: bdqn-test
roleRef:
kind: ClusterRole
name: nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
运行一下
[root@master yaml]# kubectl apply -f rbac-rolebind.yaml
作用:其实它是一个NFS客户端。但它通过K8S的内置的NFS驱动挂载远端的NFS服务器到本地目录;然后将自身作为storage provider,关联storage class。
[root@master yaml]# vim nfs-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nfs-client-provisioner
namespace: bdqn-test
spec:
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
[root@master yaml]# vim test-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: stateful-nfs
namespace: bdqn-test
provisioner: bdqn-test #这里要和第三个nfs-client-provisioner的env环境变量中的value值对应。
reclaimPolicy: Retain #回收策略为:retain,还有一个默认的值为“default”
执行一下
[root@master yaml]# kubectl apply -f test-storageclass.yaml
[root@master yaml]# vim test-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-claim
namespace: bdqn-test
spec:
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
[root@master yaml]# vim test-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: test-pod
namespace: bdqn-test
spec:
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
进入容器修改页面内容
[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-5bcfe6c6ce15
web1
web2
[root@master yaml]# cat /nfsdata/bdqn-test-test-claim-pvc-79ddfcf1-65ae-455f-9e03-5bcfe6c6ce15/test-file
123456
创建一个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
web1
[root@master yaml]# vim web.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: web-pv
spec :
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: v1
kind: PersistentVolume
metadata:
name: web-pv2
spec :
capacity :
storage: 2Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfsdata/web2
server: 192.168.1.21
[root@master yaml]# mkdir /nfsdata/web1
[root@master yaml]# mkdir /nfsdata/web2
[root@master yaml]# kubectl apply -f web.yaml
[root@master yaml]# kubectl apply -f web2.yaml
[root@master yaml]# kubectl get pv
[root@master yaml]# vim web-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: web-pvc
spec:
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的那个
[root@master yaml]# vim web-pod.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web-pod
spec:
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
[root@master yaml]# kubectl get pod -o wide
root@master yaml]# kubectl exec -it web-pod-8686d9c594-qxhr9 /bin/bash
root@web-pod-8686d9c594-qxhr9:/# cd /usr/share/nginx/html/
root@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# ls
root@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# echo 123456 > index.html
root@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# exit
[root@master yaml]# curl 10.244.2.17
[root@master yaml]# vim web1.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: web-pv
spec :
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce #能以读-写mount到单个的节点
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfsdata/web1
server: 192.168.1.21
[root@master yaml]# vim web2.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: web-pv
spec :
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
[root@master yaml]# vim web-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: web-pvc
spec:
accessModes:
- ReadWriteMany #能以读-写mount到多个的节点
resources:
requests:
storage: 1Gi
storageClassName: nfs
[root@master yaml]# kubectl apply -f web-pvc.yaml
[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的内存)
[root@master yaml]# vim namespace.yaml
kind: Namespace
apiVersion: v1
metadata:
name: xgp-znb
[root@master yaml]# kubectl apply -f namespace.yaml
[root@master yaml]# kubectl get ns
下载所需镜像
docker pull registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
[root@master yaml]# vim rbac-rolebind.yaml
kind: Namespace
apiVersion: v1
metadata:
name: xgp-znb
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
namespace: xgp-znb
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-provisioner-runner
namespace: xgp-znb
rules:
- 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: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: xgp-znb
roleRef:
kind: ClusterRole
name: nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
[root@master yaml]# kubectl apply -f rbac-rolebind.yaml
[root@master yaml]# vim nfs-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nfs-client-provisioner
namespace: xgp-znb
spec:
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
[root@master yaml]# kubectl apply -f nfs-deployment.yaml
[root@master yaml]# vim storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: test-sc
provisioner: xgp-znb #通过provisioner字段关联到上述Deploy
reclaimPolicy: Retain
[root@master yaml]# kubectl apply -f storageclass.yaml
[root@master yaml]# vim pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-claim
namespace: xgp-znb
spec:
storageClassName: test-sc
accessModes:
- ReadWriteMany
resources:
requests:
storage: 500Mi
[root@master yaml]# kubectl apply -f pvc.yaml
[root@master yaml]# kubectl get pvc -n xgp-znb
[root@master yaml]# vim pod.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web-pod
namespace: xgp-znb
spec:
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
[root@master yaml]# kubectl apply -f pvc.yaml
[root@master yaml]# kubectl get pod -n xgp-znb
[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
所有的 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, 或者其值为“”)