1、存储类介绍
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进行数据的最终持久化处理。
2、定义存储类
每一个存储类都包含provisioner、parameters和reclaimPolicy这三个参数域,当一个属于某个类的PersistentVolume需要被动态提供时,将会使用上述的参数域。
存储类对象的名称非常重要,用户通过名称类请求特定的存储类。管理员创建存储类对象时,会设置类的名称和其它的参数,存储类的对象一旦被创建,将不能被更新。管理员能够为PVC指定一个默认的存储类。
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: standard # 指定存储类的供应者 provisioner: kubernetes.io/aws-ebs parameters: type: gp2 # 指定回收策略 reclaimPolicy: Retain mountOptions: - debug
2.1 供应者
存储类有一个供应者的参数域,此参数域决定PV使用什么存储卷插件。参数必需进行设置:
存储卷 | 内置供应者 | 配置例子 |
AWSElasticBlockStore | ✓ | AWS |
AzureFile | ✓ | Azure File |
AzureDisk | ✓ | Azure Disk |
CephFS | – | – |
Cinder | ✓ | OpenStack Cinder |
FC | – | – |
FlexVolume | – | – |
Flocker | ✓ | – |
GCEPersistentDisk | ✓ | GCE |
Glusterfs | ✓ | Glusterfs |
iSCSI | – | – |
PhotonPersistentDisk | ✓ | – |
Quobyte | ✓ | Quobyte |
NFS | – | – |
RBD | ✓ | Ceph RBD |
VsphereVolume | ✓ | vSphere |
PortworxVolume | ✓ | Portworx Volume |
ScaleIO | ✓ | ScaleIO |
StorageOS | ✓ | StorageOS |
Local | – | Local |
Kubernetes的存储类并不局限于表中的“interneal”供应者,“interneal”供应者的名称带有“kubernetes.io”前缀;也可以允许和指定外部的供应者,外部供应者通过独立的程序进行实现。外部供应者的作者对代码在何处生存、如何供应、如何运行、使用什么卷插件(包括Flex)等有充分的判断权,kubernetes-incubator/external-storage仓库中存在编写外部提供者的类库。例如,NFS不是内部的供应者,但也是可以使用。在kubernetes-incubator/external-storage仓库中以列表的形式展示了一些外部的供应者,一些第三方供应商也提供了他们自己的外部供应者。
2.2 提供者的参数
存储类存在很多描述存储卷的参数,依赖不同的提供者可能有不同的参数。例如,对于type参数,它的值可能为io1。当一个参数被省略,则使用默认的值。
2.3 回收策略
通过存储类创建的持久化存储卷通过reclaimPolicy参数来指定,它的值可以是Delete或者Retain,默认为Delete。对于通过手工创建的,并使用存储类进行管理的持久化存储卷,将使用任何在创建时指定的存储卷。
2.4 挂接选项
通过存储类动态创建的持久化存储卷,会存在一个通过mountOptions参数指定的挂接选择。如果存储卷插件不支持指定的挂接选项,这提供存储供应就会失败,在存储类或者PV中都不会对挂接选项进行验证,因此需要在设置时进行确认。
3、使用存储类
动态存储卷供应基于StorageClass的API对象的来实现,集群管理员能够按需定义StorageClass对象,每一个StorageClass对象能够指定一个存储卷插件(即供应者)。集群管理员能够在一个集群中定义各种存储卷供应,用户不需要了解存储的细节和复杂性,就能够选择符合自己要求的存储。
3.1 启用动态供应
为了启用动态供应,集群管理员需要预先为用户创建一个或者多个存储类对象。存储类对象定义了使用哪个供应者,以及供应者相关的参数。下面是存储类的一个示例,它创建一个名称为slow的存储类,使用gce供应者:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow provisioner: kubernetes.io/gce-pd parameters: type: pd-standard
下面创建了一个名为“fast”的存储类,其提供类似固态磁盘的存储卷磁盘:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd
3.2 使用动态供应
用户通过在PersistentVolumeClaim中包含一个存储类,来请求动态供应存储。在Kubernetes v1.6之前的版本,通过volume.beta.kubernetes.io/storage-class注释类请求动态供应存储;在v1.6版本之后,用户应该使用PersistentVolumeClaim对象的storageClassName参数来请求动态存储。
下面是请求fast存储类的持久化存储卷声明的YAML配置文件示例:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: claim1 spec: accessModes: - ReadWriteOnce # 指定所使用的存储类,此存储类将会自动创建符合要求的PV storageClassName: fast resources: requests: storage: 30Gi
此声明将使用类似于固态存储磁盘,当持久化存储卷声明被删除后,存储卷也将会被销毁。
3.3 默认行为
如果Kubernetes的集群中没有指定存储类,集群管理员可以通过执行下面的设置,启用默认的存储类:
- 标记一个默认的StorageClass对象;
- 确定API server中DefaultStorage接入控制器已被启用
管理员能够通过添加storageclass.kubernetes.io/is-default-class注释,标记一个特定的StorageClass作为默认的存储类。在集群中,如果存在一个默认的StorageClass,系统将能够在不指定storageClassName 的情况下创建一个PersistentVolume,DefaultStorageClass接入控制器会自动将storageClassName指向默认的存储类。注意:在一个集群中,最多只能有一个默认的存储类,如果没有默认的存储类,那么如果在PersistentVolumeClaim中没有显示指定storageClassName,则将无法创建PersistentVolume。
4、NFS存储类示例
4.1 部署nfs-provisioner
为nfs-provisioner实例选择存储状态和数据的存储卷,并将存储卷挂接到容器的/export 命令。
... volumeMounts: - name: export-volume mountPath: /export volumes: - name: export-volume hostPath: path: /tmp/nfs-provisioner ...
为StorageClass选择一个供应者名称,并在deploy/kubernetes/deployment.yaml进行设置。
args: - "-provisioner=example.com/nfs" ...
完整的deployment.yaml文件内容如下:
kind: Service apiVersion: v1 metadata: name: nfs-provisioner labels: app: nfs-provisioner spec: ports: - name: nfs port: 2049 - name: mountd port: 20048 - name: rpcbind port: 111 - name: rpcbind-udp port: 111 protocol: UDP selector: app: nfs-provisioner --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nfs-provisioner spec: replicas: 1 strategy: type: Recreate template: metadata: labels: app: nfs-provisioner spec: containers: - name: nfs-provisioner image: quay.io/kubernetes_incubator/nfs-provisioner:v1.0.8 ports: - name: nfs containerPort: 2049 - name: mountd containerPort: 20048 - name: rpcbind containerPort: 111 - name: rpcbind-udp containerPort: 111 protocol: UDP securityContext: capabilities: add: - DAC_READ_SEARCH - SYS_RESOURCE args: # 定义提供者的名称,存储类通过此名称指定提供者 - "-provisioner=nfs-provisioner" env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: SERVICE_NAME value: nfs-provisioner - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace imagePullPolicy: "IfNotPresent" volumeMounts: - name: export-volume mountPath: /export volumes: - name: export-volume hostPath: path: /srv
在设置好deploy/kubernetes/deployment.yaml文件后,通过kubectl create命令在Kubernetes集群中部署nfs-provisioner。
$ kubectl create -f {path}/deployment.yaml
4.2 创建StorageClass
下面是example-nfs的StorageClass配置文件,此配置文件定义了一个名称为nfs-storageclass的存储类,此存储类的提供者为nfs-provisioner。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-storageclass provisioner: nfs-provisioner
通过kubectl create -f命令使用上面的配置文件创建:
$ kubectl create -f deploy/kubernetes/class.yaml
storageclass “example-nfs” created
在存储类被正确创建后,就可以创建PersistenetVolumeClaim来请求StorageClass,而StorageClass将会为PersistenetVolumeClaim自动创建一个可用PersistentVolume。
4.3 创建PersistenetVolumeClaim
PersistenetVolumeClaim是对PersistenetVolume的声明,即PersistenetVolume为存储的提供者,而PersistenetVolumeClaim为存储的消费者。下面是PersistentVolumeClaim的YAML配置文件,此配置文件通过spec.storageClassName字段指定所使用的存储储类。
在此配置文件中,使用nfs-storageclass存储类为PersistenetVolumeClaim创建PersistenetVolume,所要求的PersistenetVolume存储空间大小为1Mi,可以被多个容器进行读取和写入操作。
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteMany storageClassName: nfs-storageclass resources: requests: storage: 1Mi
通过kubectl create命令创建上述的持久化存储卷声明:
$ kubectl create -f {path}/claim.yaml
4.4 创建使用PersistenVolumeClaim的部署
在这里定义名为busybox-deployment的部署YAML配置文件,使用的镜像为busybox。基于busybox镜像的容器需要对/mnt目录下的数据进行持久化,在YAML文件指定使用名称为nfs的PersistenVolumeClaim对容器的数据进行持久化。
# This mounts the nfs volume claim into /mnt and continuously # overwrites /mnt/index.html with the time and hostname of the pod. apiVersion: v1 kind: Deployment metadata: name: busybox-deployment spec: replicas: 2 selector: name: busybox-deployment template: metadata: labels: name: busybox-deployment spec: containers: - image: busybox command: - sh - -c - 'while true; do date > /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done' imagePullPolicy: IfNotPresent name: busybox volumeMounts: # name must match the volume name below - name: nfs mountPath: "/mnt" # volumes: - name: nfs persistentVolumeClaim: claimName: nfs-pvc
通过kubectl create创建busy-deployment部署:
$ kubectl create -f {path}/nfs-busybox-deployment.yaml
参考资料
作者简介:
季向远,北京神舟航天软件技术有限公司产品经理。本文版权归原作者所有。