上一节我们讨论了 Kubernetes 通过PVC指定StorageClass对象提供 Dynamic Provisioning 机制动态的创建 PV 对象。虽然也引入了yaml文件示例子讲解,但是我还是觉得需要通过一节实战课程来动手操作加深理解。
以下示意图是动态存储的完整过程:

我们这节的动手实践,利用NFS动态提供Kubernetes存储卷。
创建NFS服务
服务端
安装 rpcbind 和 nfs-utils
yum -y install rpcbindyum -y install nfs-utils创建共享文件夹 mkdir opt/share设置共享目录访问的权限 vi etc/exports// /opt/share 共享目录// 172.16.212.0/24 可访问d的ip// rw可读写,sync同步,no_root_squash:root远程用户使用时不降权/opt/share 172.16.212.0/24(insecure,rw,async,no_root_squas)开启rcband和nfs服务并设置开机启动
systemctl start rpcbindsystemctl start nfssystemctl enable rpcbindsystemctl enable nfs
Kubernetes 集群创建授权管理
在 Kubernetes 中 ServiceAccount 是给 Pod 内的进程用来访问资源授权用的,我们可以理解为 Pod 内的进程需要访问 NFS Client Provisioner 需要有授权认证。使用 ServiceAccount 的流程如下:
创建 ServiceAccount 对象
apiVersion: v1kind: ServiceAccountmetadata:name: nfs-client-provisionernamespace: default
创建 Role 对象
kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: leader-locking-nfs-client-provisionernamespace: defaultrules:- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "list", "watch", "create", "update", "patch"]
创建RoleBinding对象绑定 ServiceAccount 和 Role
kind: RoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:name: leader-locking-nfs-client-provisionersubjects:- kind: ServiceAccountname: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: defaultroleRef:kind: Rolename: leader-locking-nfs-client-provisionerapiGroup: rbac.authorization.k8s.io
绑定Role和 ServiceAccount 后我们可以看到生成了对应的secret 对象:
kubectl get secretNAME TYPE DATA AGEnfs-client-provisioner-token-44jgf kubernetes.io/service-account-token 3 40skubectl describe secret nfs-client-provisioner-token-44jgfName: nfs-client-provisioner-token-44jgfNamespace: defaultLabels: <none>Annotations: kubernetes.io/service-account.name: nfs-client-provisionerkubernetes.io/service-account.uid: 19f19d11-2839-4157-890f-d60975b32090Type: kubernetes.io/service-account-tokenData====ca.crt: 1066 bytesnamespace: 7 bytestoken: xxxxxxxxxxxxxxxxxxxx
同样的,如果希望不仅仅只是当前 Namespace 空间下的资源可以使用该NFS Client Provisioner ,还可以创建 ClusterRole 同 ServiceAccount 绑定:
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: nfs-client-provisioner-runnerrules:- 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: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:name: run-nfs-client-provisionersubjects:- kind: ServiceAccountname: nfs-client-provisionernamespace: defaultroleRef:kind: ClusterRolename: nfs-client-provisioner-runnerapiGroup: rbac.authorization.k8s.io
可以看到 Role 对象需要指定 Namespace,而 ClusterRole不需要。
创建StorageClass对象
apiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: demo-nfs-storageprovisioner: demo-nfs-storageparameters:archiveOnDelete: "false"
注意 provisioner的值,在创建 provisioner时需要指定该值。
创建 NFS Provisioner
apiVersion: apps/v1kind: Deploymentmetadata:name: nfs-client-provisionerlabels:app: nfs-client-provisionernamespace: defaultnamespace: defaultspec:replicas: 1selector:matchLabels:app: nfs-client-provisionerstrategy:type: Recreateselector:matchLabels:app: nfs-client-provisionertemplate:metadata:labels:app: nfs-client-provisionerspec:serviceAccountName: nfs-client-provisionercontainers:- name: nfs-client-provisionerimage: quay.io/external_storage/nfs-client-provisioner:latestvolumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: demo-nfs-storage- name: NFS_SERVERvalue: 172.16.212.25- name: NFS_PATHvalue: /opt/sharevolumes:- name: nfs-client-rootnfs:server: 172.16.212.25path: /opt/share
注意看 env的 PROVISIONER_NAME 与StorageClass的 provisioner字段一致。
到这里搭建 StorageClass + NFS远程存储的过程就完成了,我们可以创建一个PVC来验证 Dynamic Provisioning:
kind: PersistentVolumeClaimapiVersion: v1metadata:name: test-claimannotations:volume.beta.kubernetes.io/storage-class: "demo-nfs-storage"spec:accessModes:- ReadWriteManyresources:requests:storage: 1Mi
可以看到该 PVC对象指定了使用StorageClass对象完成 Dynamic Provisioning 过程,当使用 kubectl apply 命令创建完成PVC后,我们可以查看下 PVC的状态:
kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEtest-claim Bound pvc-dd5d8bb7-c457-4bbd-9dca-dd4e92172edd 1Mi RWX demo-nfs-storage 36s
可以看到该PVC已经是绑定状态了,我们再来看看与其绑定的PV详细信息:
kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEpvc-dd5d8bb7-c457-4bbd-9dca-dd4e92172edd 1Mi RWX Delete Bound default/test-claim demo-nfs-storage 38skubectl describe pv pvc-dd5d8bb7-c457-4bbd-9dca-dd4e92172eddName: pvc-dd5d8bb7-c457-4bbd-9dca-dd4e92172eddLabels: <none>Annotations: pv.kubernetes.io/provisioned-by: nfs-storageFinalizers: [kubernetes.io/pv-protection]StorageClass: demo-nfs-storageStatus: BoundClaim: default/test-claimReclaim Policy: DeleteAccess Modes: RWXVolumeMode: FilesystemCapacity: 1MiNode Affinity: <none>Message:Source:Type: NFS (an NFS mount that lasts the lifetime of a pod)Server: 172.16.212.25Path: opt/share/default-test-claim-pvc-dd5d8bb7-c457-4bbd-9dca-dd4e92172eddReadOnly: falseEvents: <none>
可以看到该PV的存储目为 172.16.212.25 NFS服务的 /opt/share/default-test-claim-pvc-dd5d8bb7-c457-4bbd-9dca-dd4e92172edd 路径。
我们在NFS服务下可以看到该路径是存在的:
ls /opt/share/default-test-claim-pvc-dd5d8bb7-c457-4bbd-9dca-dd4e92172edd
以上是验证 StorageClass 动态存储机制完整的过程。
本系列回顾:
Kubernetes系列3 一 docker隔离与限制的原理
Kubernetes系列10 一 容器编排之StatefulSet
Kubernetes系列11 一 容器编排之DaemonSet
Kubernetes系列12 一 Job 与 CronJob
Kubernetes系列13 一 持久化存储 PV、PVC、StorageClass




