{"msg":"操作成功","code":200,"data":{"createBy":"admin","createTime":"2021-11-19 17:54:30","updateBy":"admin","updateTime":"2021-11-19 17:54:30","remark":null,"id":73,"articleTitle":"Kubernetes（十一）StorageClass动态存储供应","articleUrl":"k8s_storageclass","articleThumbnail":"https://www.asumimoe.com/imgfiles/20220906/f93daad129a04b8db74eed70cd45263b.png","articleFlag":"1","draftStatus":"1","reprintStatement":"0","articleSummary":"Kubernetes集群管理员通过提供不同的存储类，可以满足用户不同的服务质量级别、备份策略和任意策略要求的存储需求。动态存储卷供应使用StorageClass进行实现，其允许存储卷按需被创建。","articleContent":"## StorageClass存储类\n\nKubernetes集群管理员通过提供不同的存储类，可以满足用户不同的服务质量级别、备份策略和任意策略要求的存储需求。动态存储卷供应使用StorageClass进行实现，其允许存储卷按需被创建。如果没有动态存储供应，Kubernetes集群的管理员将不得不通过手工的方式类创建新的存储卷。通过动态存储卷，Kubernetes将能够按照用户的需要，自动创建其需要的存储。\n\n基于StorageClass的动态存储供应整体过程如下：\n\n1）集群管理员预先创建存储类（StorageClass）；\n\n2）用户创建使用存储类的持久化存储声明(PVC：PersistentVolumeClaim)；\n\n3）存储持久化声明通知系统，它需要一个持久化存储(PV: PersistentVolume)；\n\n4）系统读取存储类的信息；\n\n5）系统基于存储类的信息，在后台自动创建PVC需要的PV；\n\n6）用户创建一个使用PVC的Pod；\n\n7）Pod中的应用通过PVC进行数据的持久化；\n\n8）而PVC使用PV进行数据的最终持久化处理。\n\n## 定义存储类\n\n每一个存储类都包含provisioner、parameters和reclaimPolicy这三个参数域，当一个属于某个类的PersistentVolume需要被动态提供时，将会使用上述的参数域。\n\n存储类对象的名称非常重要，用户通过名称类请求特定的存储类。管理员创建存储类对象时，会设置类的名称和其它的参数，存储类的对象一旦被创建，将不能被更新。管理员能够为PVC指定一个默认的存储类。\n\n```yaml\nkind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: standard\n# 指定存储类的供应者\nprovisioner: kubernetes.io/aws-ebs\nparameters:\n  type: gp2\n# 指定回收策略\nreclaimPolicy: Retain\nmountOptions:\n  - debug\n```\n\n### 供应者\n\n| **存储卷**           | **内置供应者** | **配置例子**                                                 |\n| -------------------- | -------------- | ------------------------------------------------------------ |\n| AWSElasticBlockStore | ✓              | [AWS](https://kubernetes.io/docs/concepts/storage/storage-classes/#aws) |\n| AzureFile            | ✓              | [Azure File](https://kubernetes.io/docs/concepts/storage/storage-classes/#azure-file) |\n| AzureDisk            | ✓              | [Azure Disk](https://kubernetes.io/docs/concepts/storage/storage-classes/#azure-disk) |\n| CephFS               | –              | –                                                            |\n| Cinder               | ✓              | [OpenStack Cinder](https://kubernetes.io/docs/concepts/storage/storage-classes/#openstack-cinder) |\n| FC                   | –              | –                                                            |\n| FlexVolume           | –              | –                                                            |\n| Flocker              | ✓              | –                                                            |\n| GCEPersistentDisk    | ✓              | [GCE](https://kubernetes.io/docs/concepts/storage/storage-classes/#gce) |\n| Glusterfs            | ✓              | [Glusterfs](https://kubernetes.io/docs/concepts/storage/storage-classes/#glusterfs) |\n| iSCSI                | –              | –                                                            |\n| PhotonPersistentDisk | ✓              | –                                                            |\n| Quobyte              | ✓              | [Quobyte](https://kubernetes.io/docs/concepts/storage/storage-classes/#quobyte) |\n| NFS                  | –              | –                                                            |\n| RBD                  | ✓              | [Ceph RBD](https://kubernetes.io/docs/concepts/storage/storage-classes/#ceph-rbd) |\n| VsphereVolume        | ✓              | [vSphere](https://kubernetes.io/docs/concepts/storage/storage-classes/#vsphere) |\n| PortworxVolume       | ✓              | [Portworx Volume](https://kubernetes.io/docs/concepts/storage/storage-classes/#portworx-volume) |\n| ScaleIO              | ✓              | [ScaleIO](https://kubernetes.io/docs/concepts/storage/storage-classes/#scaleio) |\n| StorageOS            | ✓              | [StorageOS](https://kubernetes.io/docs/concepts/storage/storage-classes/#storageos) |\n| Local                | –              | [Local](https://kubernetes.io/docs/concepts/storage/storage-classes/#local) |\n\nKubernetes的存储类并不局限于表中的“interneal”供应者，“interneal”供应者的名称带有“kubernetes.io”前缀；也可以允许和指定外部的供应者，外部供应者通过独立的程序进行实现。外部供应者的作者对代码在何处生存、如何供应、如何运行、使用什么卷插件（包括Flex）等有充分的判断权，`kubernetes-incubator/external-storage`仓库中存在编写外部提供者的类库。例如，NFS不是内部的供应者，但也是可以使用。在`kubernetes-incubator/external-storage`仓库中以列表的形式展示了一些外部的供应者，一些第三方供应商也提供了他们自己的外部供应者。\n\n### 提供者的参数\n\n存储类存在很多描述存储卷的参数，依赖不同的提供者可能有不同的参数。例如，对于type参数，它的值可能为io1。当一个参数被省略，则使用默认的值。\n\n### 回收策略\n\n通过存储类创建的持久化存储卷通过`reclaimPolicy`参数来指定，它的值可以是Delete或者Retain，默认为Delete。对于通过手工创建的，并使用存储类进行管理的持久化存储卷，将使用任何在创建时指定的存储卷。\n\n### 挂接选项\n\n通过存储类动态创建的持久化存储卷，会存在一个通过`mountOptions`参数指定的挂接选择。如果存储卷插件不支持指定的挂接选项，这提供存储供应就会失败，在存储类或者PV中都不会对挂接选项进行验证，因此需要在设置时进行确认。\n\n## 使用存储类\n\n动态存储卷供应基于StorageClass的API对象的来实现，集群管理员能够按需定义StorageClass对象，每一个StorageClass对象能够指定一个存储卷插件（即供应者）。集群管理员能够在一个集群中定义各种存储卷供应，用户不需要了解存储的细节和复杂性，就能够选择符合自己要求的存储。\n\n### 启用动态供应\n\n为了启用动态供应，集群管理员需要预先为用户创建一个或者多个存储类对象。存储类对象定义了使用哪个供应者，以及供应者相关的参数。下面是存储类的一个示例，它创建一个名称为slow的存储类，使用gce供应者：\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: slow\nprovisioner: kubernetes.io/gce-pd\nparameters:\n  type: pd-standard\n```\n\n下面创建了一个名为“fast”的存储类，其提供类似固态磁盘的存储卷磁盘：\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: fast\nprovisioner: kubernetes.io/gce-pd\nparameters:\n  type: pd-ssd\n```\n\n### 使用动态供应\n\n用户通过在PersistentVolumeClaim中包含一个存储类，来请求动态供应存储。在Kubernetes  v1.6之前的版本，通过volume.beta.kubernetes.io/storage-class注释类请求动态供应存储；在v1.6版本之后，用户应该使用PersistentVolumeClaim对象的storageClassName参数来请求动态存储。\n\n下面是请求fast存储类的持久化存储卷声明的YAML配置文件示例：\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: claim1\nspec:\n  accessModes:\n    - ReadWriteOnce\n# 指定所使用的存储类，此存储类将会自动创建符合要求的PV\n storageClassName: fast\n resources:\n    requests:\n      storage: 30Gi\n```\n\n此声明将使用类似于固态存储磁盘，当持久化存储卷声明被删除后，存储卷也将会被销毁。\n\n### 默认行为\n\n如果Kubernetes的集群中没有指定存储类，集群管理员可以通过执行下面的设置，启用默认的存储类：\n\n- 标记一个默认的StorageClass对象；\n- 确定API server中DefaultStorage接入控制器已被启用\n\n管理员能够通过添加storageclass.kubernetes.io/is-default-class注释，标记一个特定的StorageClass作为默认的存储类。在集群中，如果存在一个默认的StorageClass，系统将能够在不指定storageClassName 的情况下创建一个PersistentVolume，DefaultStorageClass接入控制器会自动将storageClassName指向默认的存储类。注意：在一个集群中，最多只能有一个默认的存储类，如果没有默认的存储类，那么如果在PersistentVolumeClaim中没有显示指定storageClassName，则将无法创建PersistentVolume。\n\n## NFS存储类示例\n\n### 部署nfs-provisioner\n\n为nfs-provisioner实例选择存储状态和数据的存储卷，并将存储卷挂接到容器的/export 命令。\n\n```yaml\n...\n volumeMounts:\n    - name: export-volume\n      mountPath: /export\nvolumes:\n  - name: export-volume\n    hostPath:\n      path: /tmp/nfs-provisioner\n...\n```\n\n为StorageClass选择一个供应者名称，并在`deploy/kubernetes/deployment.yaml`进行设置。\n\n```yaml\nargs:\n  - \"-provisioner=example.com/nfs\"\n...\n```\n\n完整的deployment.yaml文件内容如下：\n\n```yaml\nkind: Service\napiVersion: v1\nmetadata:\n  name: nfs-provisioner\n  labels:\n    app: nfs-provisioner\nspec:\n  ports:\n    - name: nfs\n      port: 2049\n    - name: mountd\n      port: 20048\n    - name: rpcbind\n      port: 111\n    - name: rpcbind-udp\n      port: 111\n      protocol: UDP\n  selector:\n    app: nfs-provisioner\n---\n\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: nfs-provisioner\nspec:\n  replicas: 1\n  strategy:\n    type: Recreate\n  template:\n    metadata:\n      labels:\n        app: nfs-provisioner\n    spec:\n      containers:\n        - name: nfs-provisioner\n          image: quay.io/kubernetes_incubator/nfs-provisioner:v1.0.8\n          ports:\n            - name: nfs\n              containerPort: 2049\n            - name: mountd\n              containerPort: 20048\n            - name: rpcbind\n              containerPort: 111\n            - name: rpcbind-udp\n              containerPort: 111\n              protocol: UDP\n          securityContext:\n            capabilities:\n              add:\n                - DAC_READ_SEARCH\n                - SYS_RESOURCE\n          args:\n            # 定义提供者的名称，存储类通过此名称指定提供者\n            - \"-provisioner=nfs-provisioner\"\n          env:\n            - name: POD_IP\n              valueFrom:\n                fieldRef:\n                  fieldPath: status.podIP\n            - name: SERVICE_NAME\n              value: nfs-provisioner\n            - name: POD_NAMESPACE\n              valueFrom:\n                fieldRef:\n                  fieldPath: metadata.namespace\n          imagePullPolicy: \"IfNotPresent\"\n          volumeMounts:\n            - name: export-volume\n              mountPath: /export\n      volumes:\n        - name: export-volume\n          hostPath:\n            path: /srv\n```\n\n在设置好`deploy/kubernetes/deployment.yaml`文件后，通过kubectl create命令在Kubernetes集群中部署nfs-provisioner。\n\n```shell\n$ kubectl create -f {path}/deployment.yaml\n```\n\n### 创建StorageClass\n\n下面是example-nfs的StorageClass配置文件，此配置文件定义了一个名称为nfs-storageclass的存储类，此存储类的提供者为nfs-provisioner。\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: nfs-storageclass\n  provisioner: nfs-provisioner\n```\n\n通过kubectl create -f命令使用上面的配置文件创建：\n\n```shell\n$ kubectl create -f deploy/kubernetes/class.yaml\nstorageclass “example-nfs” created\n```\n\n在存储类被正确创建后，就可以创建PersistenetVolumeClaim来请求StorageClass，而StorageClass将会为PersistenetVolumeClaim自动创建一个可用PersistentVolume。\n\n### 创建PersistenetVolumeClaim\n\nPersistenetVolumeClaim是对PersistenetVolume的声明，即PersistenetVolume为存储的提供者，而PersistenetVolumeClaim为存储的消费者。下面是PersistentVolumeClaim的YAML配置文件，此配置文件通过*spec.storageClassName*字段指定所使用的存储储类。\n\n在此配置文件中，使用*nfs-storageclass*存储类为PersistenetVolumeClaim创建PersistenetVolume，所要求的PersistenetVolume存储空间大小为1Mi，可以被多个容器进行读取和写入操作。\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: nfs-pvc\nspec:\n  accessModes:\n  - ReadWriteMany\n  storageClassName： nfs-storageclass\n  resources:\n    requests:\n      storage: 1Mi\n```\n\n通过kubectl create命令创建上述的持久化存储卷声明：\n\n```shell\n$ kubectl create -f {path}/claim.yaml\n```\n\n###  创建使用PersistenVolumeClaim的部署\n\n 在这里定义名为busybox-deployment的部署YAML配置文件，使用的镜像为busybox。基于busybox镜像的容器需要对**/mnt**目录下的数据进行持久化，在YAML文件指定使用名称为nfs的PersistenVolumeClaim对容器的数据进行持久化。\n\n```yaml\n# This mounts the nfs volume claim into /mnt and continuously\n# overwrites /mnt/index.html with the time and hostname of the pod. \napiVersion: v1\nkind: Deployment\nmetadata:  \n  name: busybox-deployment\nspec:  \n  replicas: 2  \n  selector:    \n    name: busybox-deployment\n  template:    \n    metadata:      \n      labels:        \n        name: busybox-deployment    \n    spec:      \n      containers:      \n      - image: busybox        \n        command:          \n        - sh          \n        - -c          \n        - 'while true; do date > /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'        \n        imagePullPolicy: IfNotPresent        \n        name: busybox        \n        volumeMounts:          \n        # name must match the volume name below          \n        - name: nfs            \n          mountPath: \"/mnt\"     \n     # \n     volumes:      \n     - name: nfs        \n       persistentVolumeClaim:          \n         claimName: nfs-pvc\n```\n\n通过kubectl create创建busy-deployment部署：\n\n```shell\n$ kubectl create -f {path}/nfs-busybox-deployment.yaml\n```\n\n转载自：[https://www.kubernetes.org.cn/4078.html](https://www.kubernetes.org.cn/4078.html)","categoryId":10,"viewCount":1324,"categoryName":"Kubernetes","author":"球接子","authorAvatar":null,"tagIds":[16],"tagNames":["Kubernetes"]}}