Volumn和PV的关系
Volumn卷
属于 Pod 内部共享资源存储,生命周期和 Pod 相同,与 Container 无关,即使 Pod 上的容 器停止或者重启,Volume 不会受到影响,但是如果 Pod 终止,那么这个 Volume 的生命周 期也将结束。
存储的基本组件
在 k8s 中 对 于 存 储 的 资 源 抽 象 了 两 个 概 念 , 分 别 是 PersistentVolume(PV)和PersistentVolumeClaim(PVC)。
PV 是集群中的资源
PVC 是对这些资源的请求
PV 和 PVC 都只是抽象的概念,在 k8s 中是通过插件的方式提供具体的存储实现。
目前包含 有 NFS、ceph、iSCSI 和云提供商指定的存储系统
管理存储是管理计算的一个明显问题。
该 PersistentVolume 子系统为用户和管理员提供 了一个 API,用于抽象如何根据消费方式提供存储的详细信息。
为此,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim
PV/PVC/StorageClass
PersistentVolume(持久化卷):
是对底层的共享存储的一种抽象,PV 由管理员 进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、 NFS 等,都是通过插件机制完成与共享存储的对接
PersistentVolumeClaim(PVC):
是由用户进行存储的请求。 它类似于 pod。 Pod 消耗 节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请 求特定的大小和访问模式(例如,可以一次读/写或多次只读)。
StorageClass :
为管理员提供了一种描述他们提供的存储的“类”的方法。
不同的类可能映 射到服务质量级别,或备份策略,或者由群集管理员确定的任意策略。
Kubernetes 本身对于什么类别代表是不言而喻的。 这个概念有时在其他存储系统中称为“配置文件”。
PV 是运维人员来创建的,开发操作 PVC,可是大规模集群中可能会有很多 PV,如果这 些 PV 都需要运维手动来处理这也是一件很繁琐的事情,所以就有了动态供给概念.
也就是 Dynamic Provisioning,动态供给的关键就是 StorageClass,它的作用就是创建 PV 模板。
创 建 StorageClass 里面需要定义 PV 属性比如存储类型、大小等;另外创建这种 PV 需要用到 存储插件。最终效果是,用户提交PVC,里面指定存储类型,如果符合我们定义的StorageClass, 则会为其自动创建 PV 并进行绑定
PVC 和 PV 是一一对应
PV 和 PVC 中的 spec 关键字段要匹配,比如存储(storage)大小。
PV 和 PVC 中的 storageClassName 字段必须一致。
四个概念的关系
Kubernetes 中 存 储 中 有 四 个 重 要 的 概 念 : Volume 、 PersistentVolume ( PV )、 PersistentVolumeClaim(PVC)、StorageClass。
声明周期
PV 是群集中的资源。PVC 是对这些资源的请求,并且还充当对资源的检查。
PV 和 PVC 之间的相互作用遵循以下生命周期:
Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling
供应准备 Provisioning
通过集群外的存储系统或者云平台来提供存储持久化支持
- 静态提供 Static:集群管理员创建多个 PV。 它们携带可供集群用户使用的真实存储的详 细信息。 它们存在于 Kubernetes API 中,可用于消费
- 动态提供 Dynamic:当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时, 集群可能会尝试为 PVC 动态配置卷。 此配置基于 StorageClasses:PVC 必须请求一个类, 并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用 动态配置。
绑定 Binding
用户创建 pvc 并指定需要的资源和访问模式。在找到可用 pv 之前,pvc 会 保持未绑定状态。
使用 Using
用户可在 pod 中像 volume 一样使用 pvc。
释放 Releasing
用户删除 pvc 来回收存储资源,pv 将变成“released”状态。由于还保留着 之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他 pvc 使 用。
回收Recycling
pv可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。
- 保留策略:允许人工处理保留的数据。
- 删除策略:将删除 pv 和外部关联的存储资源,需要插件支持。
- 回收策略:将执行清除操作,之后可以被新的 pvc 使用,需要插件支持。 注:目前只有 NFS 和 HostPath 类型卷支持回收策略,AWS EBS,GCE PD,Azure Disk 和 Cinder 支持删除(Delete)策略
PV 类型
- GCEPersistentDisk
- AWSElasticBlockStore
- AzureFile AzureDisk
- FC (Fibre Channel)
- Flexvolume
- NFS
- iSCSI
- RBD (Ceph Block Device)
- CephFS
- Cinder (OpenStack block storage)
- Glusterfs
- VsphereVolume
- Quobyte Volumes
- StorageOS
PV 卷阶段状态
- Available – 资源尚未被 claim 使用
- Bound – 卷已经被绑定到 claim 了
- Released – claim 被删除,卷处于释放状态,但未被集群回收。
- Failed – 卷自动回收失败
k8s存储架构图
Kubernetes 卷插件实现方法
In Tree
Kubernetes 卷插件目前是“in-tree”,意味着它们与核心 kubernetes 二进制文件链接,编译, 构建和一起发布。
有不利于核心代码的发布,增加了工作量,并且卷插件的权限太高等缺点 需要将后端存储的代码逻辑放到 K8S 的代码中运行。逻辑代码可能会引起与 K8S 其他部件 之间的相互影响
Out-of-tree Provisioner-FlexVolume
现有的 Flex Volume 插件需要访问节点和主机的根文件系统才能部署第三方驱动程序文件, 并且对主机的依赖性强.
调用一个主机的可执行程序包的方式执行存储卷的挂载使用。
解决了 In-Tree 方式的强耦合, 不过命令行调用的方式,在主机安全性、部署依赖的容器化、与 K8S 服务之间的相互扩展性 等方面存在不足Flexvolume 运行在 host 空间,不能使用 rbac授权机制访问Kubernetes API, 导致其功能极大的受限 Storage providers support this type and develop Driver
Out-of-tree Provisioner -CSI
容器存储接口(CSI)是由来自各个 CO 的社区成员(包括 Kubernetes,Mesos,Cloud Foundry 和 Docker)之间的合作产生的规范。
此接口的目标是为 CO 建立标准化机制,以将任意存 储系统暴露给其容器化工作负载。
CSI 标准使 K8S 和存储提供者之间将彻底解耦,将存储的所有的部件作为容器形式运行在 K8S 上。 CO Container Orchestrer Storage providers support this type and develop Driver
NFS实现存储
创建一个 NFS 服务器作为 K8s 的存储系统, nfs 默认不支持动态存储。
使用了第三方的 NFS 插件 实现 flexvolume and CSI 方式使用存 储。
NFS服务建立
- 安装nfs-server
yum install nfs-utils rpcbind -y systemctl enable rpcbind nfs-server systemctl start rpcbind nfs-server systemctl status rpcbind nfs-server
- 创建共享目录
mkdir /nfs-server
- 配置共享目录
vi /etc/exports # 编辑或创建/etc/exports文件 /nfs-server *(rw,sync,no_root_squash # 配置nfs-server
- 对/etc/exports 增加或修改的部分进行挂载和卸载
exportfs -a
注意: exportfs 命令,参考 https://wker.com/linux-command/exportfs.html
Client 安装NFS服务
Note: 在每一个节点都需要安装NFS服务
yum install nfs-utils rpcbind -y systemctl enable rpcbind nfs-server systemctl start rpcbind nfs-server systemctl status rpcbind nfs-server
测试共享卷是否可用
showmount -e 192.168.56.5 # nfs server 的ip mount -t nfs 192.168.56.5:/nfs-server /home # bind 共享卷 umount /home # unbind 共享卷
NFS共享存储实践
静态供应
- 创建PV
pv1.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: pv0001 spec: capacity: storage: 5Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Recycle nfs: path: "/nfs-server" server: 192.168.10.201
- 创建PVC
pvc1.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi
- 创建Pod
pod1.yaml
kind: Pod apiVersion: v1 metadata: name: nfs-test spec: containers: - name: my-busybox image: busybox volumeMounts: - mountPath: "/data" name: sample-volume command: ["sleep", "1000000"] imagePullPolicy: IfNotPresent volumes: - name: sample-volume persistentVolumeClaim: claimName: nfs-pvc
- 测试
进入 pod容器中,在/data目录创建一个test.txt文件
查看nfs-server 是否包含共享了test.txt文件
NFS CSI类型动态供应
NFS CSI Driver 是 K8s 官方提供的 CSI 示例程序,只实现了 CSI 的最简功能 Controller 由 CSI Plugin+csi-provisioner+livenessprobe 组成 node-server 由 CSI Plugin+liveness-probe+node-driver-registrar 组成
安装CSI组件
rbac-csi.yaml 文件配置
---apiVersionv1 kindServiceAccount metadata namecsi-nfs-controller-sa namespacekube-system ---kindClusterRole apiVersionrbac.authorization.k8s.io/v1 metadata namenfs-external-provisioner-role rulesapiGroups"" 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"get""list""watch""create""update""patch"apiGroups"storage.k8s.io" resources"csinodes" verbs"get""list""watch"apiGroups"" resources"nodes" verbs"get""list""watch"apiGroups"coordination.k8s.io" resources"leases" verbs"get""list""watch""create""update""patch"apiGroups"" resources"secrets" verbs"get"---kindClusterRoleBinding apiVersionrbac.authorization.k8s.io/v1 metadata namenfs-csi-provisioner-binding subjectskindServiceAccount namecsi-nfs-controller-sa namespacekube-system roleRef kindClusterRole namenfs-external-provisioner-role apiGrouprbac.authorization.k8s.io
csi-nfs-driverinfo.yaml 文件配置
---apiVersionstorage.k8s.io/v1 kindCSIDriver metadata namenfs.csi.k8s.io spec attachRequiredfalse volumeLifecycleModesPersistent Ephemeral
csi-nfs-node.yaml 文件配置
---# This YAML file contains driver-registrar & csi driver nodeplugin API objects# that are necessary to run CSI nodeplugin for nfskindDaemonSet apiVersionapps/v1 metadata namecsi-nfs-node namespacekube-system spec updateStrategy rollingUpdate maxUnavailable1 typeRollingUpdate selector matchLabels appcsi-nfs-node template metadata labels appcsi-nfs-node spec hostNetworktrue # original nfs connection would be broken without hostNetwork setting dnsPolicyClusterFirstWithHostNet nodeSelector kubernetes.io/oslinux tolerationsoperator"Exists" containersnameliveness-probe imageregistry.cn-hangzhou.aliyuncs.com/liuyik8s/livenessprobev2.5.0 args--csi-address=/csi/csi.sock --probe-timeout=3s --health-port=29653 --v=2 volumeMountsnamesocket-dir mountPath/csi resources limits memory100Mi requests cpu10m memory20Mi namenode-driver-registrar imageregistry.cn-hangzhou.aliyuncs.com/liuyik8s/csi-node-driver-registrarv2.4.0 args--v=2 --csi-address=/csi/csi.sock --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) livenessProbe exec command/csi-node-driver-registrar --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) --mode=kubelet-registration-probe initialDelaySeconds30 timeoutSeconds15 envnameDRIVER_REG_SOCK_PATH value/var/lib/kubelet/plugins/csi-nfsplugin/csi.sock nameKUBE_NODE_NAME valueFrom fieldRef fieldPathspec.nodeName volumeMountsnamesocket-dir mountPath/csi nameregistration-dir mountPath/registration resources limits memory100Mi requests cpu10m memory20Mi namenfs securityContext privilegedtrue capabilities add"SYS_ADMIN" allowPrivilegeEscalationtrue imagemcr.microsoft.com/k8s/csi/nfs-csiv3.1.0 args"-v=5""--nodeid=$(NODE_ID)""--endpoint=$(CSI_ENDPOINT)" envnameNODE_ID valueFrom fieldRef fieldPathspec.nodeName nameCSI_ENDPOINT valueunix///csi/csi.sock portscontainerPort29653 namehealthz protocolTCP livenessProbe failureThreshold5 httpGet path/healthz porthealthz initialDelaySeconds30 timeoutSeconds10 periodSeconds30 imagePullPolicy"IfNotPresent" volumeMountsnamesocket-dir mountPath/csi namepods-mount-dir mountPath/var/lib/kubelet/pods mountPropagation"Bidirectional" resources limits memory300Mi requests cpu10m memory20Mi volumesnamesocket-dir hostPath path/var/lib/kubelet/plugins/csi-nfsplugin typeDirectoryOrCreate namepods-mount-dir hostPath path/var/lib/kubelet/pods typeDirectory hostPath path/var/lib/kubelet/plugins_registry typeDirectory nameregistration-dir
csi-nfs-controller.yaml 文件配置
---kindDeployment apiVersionapps/v1 metadata namecsi-nfs-controller namespacekube-system spec replicas2 selector matchLabels appcsi-nfs-controller template metadata labels appcsi-nfs-controller spec hostNetworktrue # controller also needs to mount nfs to create dir dnsPolicyClusterFirstWithHostNet serviceAccountNamecsi-nfs-controller-sa nodeSelector kubernetes.io/oslinux # add "kubernetes.io/role: master" to run controller on master node priorityClassNamesystem-cluster-critical tolerationskey"node-role.kubernetes.io/master" operator"Exists" effect"NoSchedule"key"node-role.kubernetes.io/controlplane" operator"Exists" effect"NoSchedule" containersnamecsi-provisioner imageregistry.cn-hangzhou.aliyuncs.com/liuyik8s/csi-provisionerv2.2.2 args"-v=2""--csi-address=$(ADDRESS)""--leader-election" envnameADDRESS value/csi/csi.sock volumeMountsmountPath/csi namesocket-dir resources limits memory400Mi requests cpu10m memory20Mi nameliveness-probe imageregistry.cn-hangzhou.aliyuncs.com/liuyik8s/livenessprobev2.5.0 args--csi-address=/csi/csi.sock --probe-timeout=3s --health-port=29652 --v=2 volumeMountsnamesocket-dir mountPath/csi resources limits memory100Mi requests cpu10m memory20Mi namenfs imagemcr.microsoft.com/k8s/csi/nfs-csiv3.1.0 securityContext privilegedtrue capabilities add"SYS_ADMIN" allowPrivilegeEscalationtrue imagePullPolicyIfNotPresent args"-v=5""--nodeid=$(NODE_ID)""--endpoint=$(CSI_ENDPOINT)" envnameNODE_ID valueFrom fieldRef fieldPathspec.nodeName nameCSI_ENDPOINT valueunix///csi/csi.sock portscontainerPort29652 namehealthz protocolTCP livenessProbe failureThreshold5 httpGet path/healthz porthealthz initialDelaySeconds30 timeoutSeconds10 periodSeconds30 volumeMountsnamepods-mount-dir mountPath/var/lib/kubelet/pods mountPropagation"Bidirectional"mountPath/csi namesocket-dir resources limits memory200Mi requests cpu10m memory20Mi volumesnamepods-mount-dir hostPath path/var/lib/kubelet/pods typeDirectory namesocket-dir emptyDir
storageclass-nfs.yaml 文件配置
---apiVersionstorage.k8s.io/v1 kindStorageClass metadata namenfs-csi provisionernfs.csi.k8s.io parameters server192.168.56.5 #修改为自己的nfs的服务器地址 share/nfs-server #修改为nfs的目录reclaimPolicyRetain # only retain is supported,目前这个回收策略只支持RetainvolumeBindingModeImmediate mountOptionshard nfsvers=4.1
安装CSI
kubectl apply -f rbac-csi.yaml kubectl apply -f csi-nfs-driverinfo.yaml kubectl apply -f csi-nfs-node.yaml kubectl apply -f csi-nfs-controller.yaml kubectl apply -f storageclass-nfs.yaml
官网连接更新参考:
https://artifacthub.io/packages/helm/keyporttech/csi-driver-nfs/0.1.4https://github.com/kubernetes-csi/csi-driver-nfs/blob/master/deploy/example/README.md
CSI动态供应存储创建 PVC/POD
Deployment 无状态使用
pod-pvc-csi.yaml 文件配置
apiVersionv1 kindPersistentVolumeClaim metadata namenfs2 # annotations:# hitachi.io/note: "pvc-sample"spec accessModesReadWriteOnce resources requests storage5Gi storageClassNamenfs-csi # 指定className,动态创建pv---kindPod apiVersionv1 metadata namenfs-test-csi spec containersnamemy-busybox imagebusybox volumeMountsmountPath"/data" namesample-volume command"sleep""1000000" imagePullPolicyIfNotPresent volumesnamesample-volume persistentVolumeClaim claimNamenfs2
安装 pod-pvc-csi.yaml
kubectl apply -f pod-pvc-csi.yaml
查看pvc
查看storageClassName
测试
进入 nfs-test-csi 容器中,创建 test-csi.txt
查看nfs-server的共享卷
Statefulset 有状态使用
apiVersionv1 kindService metadata namenginx labels appnginx spec portsport80 nameweb clusterIPNone selector appnginx ---apiVersionapps/v1 kindStatefulSet metadata nameweb spec serviceName"nginx" replicas3 selector matchLabels appnginx volumeClaimTemplatesmetadata nametest annotations volume.beta.kubernetes.io/storage-class"nfs-csi" spec accessModes"ReadWriteOnce" resources requests storage2Gi #---- template metadata labels appnginx spec containersnamenginx imagenginx1.9 portscontainerPort80 nameweb volumeMountsnametest readOnlyfalse mountPath"/usr/share/nginx/html"















