Kubernetes对有状态或者对数据须要持久化的应用,不只须要将容器内的目录挂载到宿主机的目录或者empDir临时存储卷,并且须要更加可靠的存储来保存应用产生的重要数据,以便于容器应用重建之后,仍然可使用以前的数据。为了可以屏蔽底层存储实现的细节,让用户方便使用,同时能让管理员方便管理,kubernetes从v1.0版本就引入了persistentVolume和persistentVolumeCliam两个资源对象来实现对存储的管理。
persistentVolume(PV)是对底层网络共享存储的抽象,将共享存储定义为一种“资源”,好比节点也是一种容器应用能够消费的资源。PV由管理员进行建立和配置,它与共享存储的具体实现直接相关,例如:GlusterFS、iSCSI、RBD或者GEC/AWS公有云提供的共享存储,经过插件式的机制完成与共享存储的对接,以供应用访问和使用。 persistentVolumeCliam(PVC)则是用户对于存储资源的一个“申请”。就像Pod“消费”node的资源同样,PVC会“消费”PV资源。PVC能够申请特定的存储空间和访问模式。
使用PVC“申请”到必定的存储空间仍然不足以知足应用对于存储设备的各类需求。一般应用程序都会对存储设备的特性和性能有不一样的要求。包括读写速度、并发性能、数据冗余等更高的要求,kubernetes从v1.4开始引入了一个新的资源对象storageClass,用于标记存储资源的特性和性能。到v1.6版本时,storageClass和动态资源应用机制获得了完善,实现了存储卷的按需建立。
那么下面小编将对PV、PVC、storageClass和动态资源供应等共享存储管理机制进行详细说明。html
PV做为存储资源,主要包括存储能力、访问模式、存储类型、回收策略、后端存储类型等关键信息的设置。如下面配置为例:node
apiVersion: v1 kind: PersistentVolume metadata: name: pv1 spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: slow nfs: path: /tmp server: 172.17.0.2
上面这个例子就建立了一个5G空间,访问模式为ReadWriteOnce,存储类型为”slow”(这里须要要求系统已经建立了名为slow的storageClass 资源对象),回收策略为“recycle”,而且后端存储类型为nfs(并设置了NFS server的IP和路径)
Kubernetes支持的PV的类型以下:
GCEPersistentDisk #GEC公有云提供的PersistentDisk
AWSElasticBlockStore #AWS公有云提供的ElasticBlockStore
AzureFile #Azure公有云提供的File
AzureDisk #AzureDisk提供的Disk
FC (Fibre Channel)
Flexvolume
Flocker
NFS #网络文件系统
iSCSI
RBD (Ceph Block Device) #Ceph存储块
CephFS
Cinder (OpenStack block storage) #openStack Cinder块存储
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath #宿主机目录,仅用于单机测试
Portworx Volumes
ScaleIO Volumes
StorageOSjson
① 存储能力(capacity)
描述存储设备具有的能力,目前仅支持对存储空间的设置(storage:xxx)后端
② 访问模式(Access Modes)
对PV进行访问模式的设置,用于描述用户应用对存储资源的访问权限。访问模式以下:
ReadWriteOnce:读写权限,而且只能被单个node挂载
ReadOnlyMany:只读权限,能够被多个node挂载
ReadWriteMany:读写权限,能够被多个node挂载
注意:PV能够可能支持多种访问模式,但PV在挂载时只能使用一种访问模式,多种访问模式不能同时生效。
对于不一样类型的PV有不一样的访问模式,在PV的定义时须要与他们匹配:centos
③ 存储类别(class)
PV能够设定其存储的类别,经过storageClassName参数指定一个storageClass资源对象的名称。具备特定“类别”的PV只能与请求了该“类别”的PVC进行绑定。未设定“类别”的PV则只能与不请求任何“类别”的PVC进行绑定。storageClass资源对象会在后面的动态资源供应中大展神威。api
④ 回收策略(Reclaim Policy)
目前支持如下三种回收策略:
保留(Retain):保留数据,须要手工处理
回收空间(Recycle):简单清除文件的操做(例如执行rm -rf /xx/*)
删除(Delete):与PV相连的后端存储完成volume的删除操做(如AWS EBS、GCE PD、Azure Disk、OpenStack Cinder等设备的内部volume清理)
注意:目前只有NFS和hostPath支持“Recycle”,AWS EBS、GCE PD、Azure Disk、OpenStack Cinder支持“Delete”。安全
某个PV在生命周期中,可能处于如下4个节点之一:
Available:可用状态,还与某个PVC绑定
Bound:已经与某个PVC绑定
Released:绑定的PVC已经删除,资源已经释放,但没有被集群回收
Failed:自动资源回收失败bash
在将一个PV挂载到一个node上时,根据后端存储的特色,可能须要设置额外的挂载参数,目前能够经过在PV的定义中,设置一个名为“volume.beta.kubernetes.io/mount/options”的annotation来实现。下面小编经过一个gcePersistentDisk设置挂载参数为例:网络
apiVersion: "v1" kind: PersistentVolume metadata: name: gce-disk-1 annotations: volume.beta.kubernetes.io/mount/options: discard sepc: capacity: storage: 10Gi accessModes: - ReadWriteOnce gcePersistentDisk: fsType: ext4 pdName: gce-disk-1
上面咱们了解了PV的定义,这里咱们就使用它,这时就须要PVC了。PVC做为用户对存储资源的需求申请,主要包括存储空间申请、访问模式。PV选择条件和存储类别等信息的设置。
接下来小编也是经过一个例子,向你们介绍若是定义PVC去使用PV:架构
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: myclaim sepc: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi storageClassName: slow selector: matchLabels: release: "stable" matchExpressions: - {key: environment, operator: In, values: [dev]}
申请8G空间,访问模式为“ReadWriteOnce”、PV选择条件包括标签为“release=stable”而且包含条件为“environment in dev”的标签,存储类别为slow(系统中已经存在)。
其中对PVC的关键配置详细介绍:
资源请求(resources):仅支持存储空间大小请求
资源请求(resources):仅支持存储空间大小请求
PV的选择条件:经过label selector去筛选可使用的PV,系统将根据标签找到合适获得PV,而且将PV与PVC绑定
存储类别:PVC在定义时能够设定须要的后端存储的类别,以下降对后端存储特性的依赖。只有设置了该class的PV才能被系统筛选出来,而且与该PVC绑定
这里针对PVC是否设置class需求,小编进行详细的说明一下:
这里分为两种状况:
系统启用了defaultStorageClass
若是启用了defaultStorageClass可是,系统中不存在默认的storageClass,那么等效于不启用defaultStorageClass的状况
若是启用了defaultStorageClass而且系统中有默认的storageClass,则系统自动的为PVC建立一个PV(使用默认的defaultStorageClass),并将它们绑定
系统未启用defaultStorageClass
若是设置了storageClass为“”或者没有设置storageClass字段,那么只能选择未设定storageclass的PV与之进行匹配和绑定
设置默认的storageClass的方法是,在storageClass上定义一个annotation“storageclass.kubernetes.io/is-default-class=true”,可是不能给多个storageClass都设置annotation,若是这样的话因为不惟一,系统没法为PVC建立相应的PV。
使用PV与PVC绑定的注意项:
PV和PVC都受namespace的 限制,只有相同namespace中的PV和PVC才能绑定,并只有相同namespace下pod才能挂载PVC。
当在PVC定义中同时设置了selector和storageClassName,只有两者同时知足条件才能将PV和PVC绑定。
PV能够看作可用的存储资源,PVC则是对存储资源的请求,PV和PVC的相互关系以下图所示:
接下来由图咱们逐一介绍:
Kubernetes支持两种资源供应模式:静态模式和动态模式。资源供应的结果就是建立好的PV。
静态模式:集群管理员手工建立许多PV,在定义PV时须要将后端存储的特性进行设置。
动态模式:集群管理员无须手动建立PV,而是经过storageClass的设置对后端存储进行描述,标记为某种“类型”。此时要求PVC对存储的类型进行声明,系统将自动完成PV的建立于PVC的绑定。
在用户定义好PVC以后,系统将根据PVC对存储资源的请求在已经存在的PV中选择一个知足PVC要求的PV,一旦找到,就将该PV与用户定义的PVC进行绑定,而后用户的应用就可使用这个PVC。若是系统中没有知足PVC要求的PV,PVC则会无限期的处于pending状态,直到等待系统管理员建立了一个符合其要求的PV。PV一旦绑定到某个PVC上,就被这个PVC独占,不能与其余的PVC进行绑定了。这样的话容易形成资源的浪费,若是使用的是动态模式,则系统在为PVC找到合适的storageClass后将自动建立一个PV并完成与PVC的绑定。
Pod使用volume的定义,将PVC挂载到容器内的某个路径进行使用。Volume的类型为“persistentVolumeClaim”,在后面的示例中再进行详细的说明。在容器应用挂载了一个PVC以后,就能被持续独占使用。不过,多个pod能够挂载同一个PVC。
当用户对存储资源使用完毕以后,用户能够删除PVC,与该PVC绑定的PV将会被标价为“已释放”,但还不能马上与其余PVC进行绑定。经过以前PVC写入的数据可能还留在存储设备上,只有在清除以后该PV才能再次使用。
对于PV,管理员能够设置回收策略,用于设置与之绑定的PVC释放资源以后,对于遗留数据如何处理。只有PV的存储空间完成回收,才能供新的PVC绑定和使用。
最后小编经过两幅图,来介绍一下静态资源供应模式和动态资源供应模式的原理,为下面一节内容作铺垫:
静态模式下的PV和PVC原理
动态模式下storageClass、PV、PVC原理
StorageClass做为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节,一方面减轻用户对于存储资源细节的关注,另外一方面也减轻了管理员手工管理PV的工做,由系统自动完成PV的建立和绑定,实现了动态的资源供应。
对于StorageClass的定义主要包括:名称、后端存储的提供者和后端存储的相关参数配置。StorageClass一旦被建立出来,将没法修改。如须要修改,只能删除原先建立的StorageClass从新构建。下面是一个定义StorageClass的例子:
kind: storageClass apiVersion: storage.k8s.io/v1 metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2
上面的例子就定义了一个名为“standard”,提供者为“aws-ebs”,其参数为gp2的StorageClass。
其中定义StorageClass中有两个重点参数:
provisioner(提供者):描述存储资源的提供者,也能够看作是后端存储驱动。目前provisioner都是以“Kubernetes.io/”为开头
parameters(参数):后端资源提供者的参数设置,不一样的provisioner包括不一样的参数设置
①AWS EBS存储卷
kind: storageClass apiVersion: storage.k8s.io/v1 metadata: name: slow provisioner: kubernetes.io/aws-ebs parameters: type: io1 zone: us-east-1d iopsPerGB: "10"
参数说明:
type:可选有:io一、gp二、sc一、st1,默认是gp2
zone:AWS zone名称
iopPerGB:仅用于io1类型的volume,意为每秒每G的I/O操做数量
encrypted:是否加密
kmsKeyId:加密时的Amazon Resource Name
② GCE PD存储卷
kind: storageClass apiVersion: storage.k8s.io/v1 metadata: name: slow provisioner: kubernetes.io/gce-pd parameters: type: pd-standard zone: us-centrall-a
参数说明:
type:可选项有:pd-standard、pd-ssd,默认是pd-standard
zone:GCE zone名称
③ GlusterFS存储卷
apiVersion: storage.k8s.io/v1 kind: storageClass metadata: name: slow provisioner: kubernetes.io/glusterfs parameters: resturl: "http://127.0.0.1:8081" clusterid: 44ad5as1fd5ae1fde1fwe1d5we1d5 restauthenabled: "true" restuser: "admin" secreNamespace: "default" secreName: "heketi-sercret" gidMin: "40000" gidMax: "50000" volumetype: "replicate:3"
参数说明:
resturl:Gluster REST服务(Heketi)URL地址,用于自动完成GlusterFSvolume的设置
restauthenabled:访问Gluster REST服务启用安全机制
restuser:访问Gluster REST服务的用户名
secretNamespace和secretName:保存访问Gluster REST服务密码的Secret的资源对象名
clustered:GlusterFS 的cluster ID
gidMin和gidMax:storageClass的GID的范围,用于动态建立资源供应时PV设置的GID
volumetype:GlusterFS的volume类型设置,例如:replicate:3表示replicate类型3个副本
④ OpenStack Cinder存储卷
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: gold provisioner: kubernetes.io/cinder parameters: type: fast availability: nova
参数说明:
type:cinder的volumetype,默认为空
availability:availability zone ,默认为空
要在系统中设置一个默认的storageClass,首先须要启动名为“DefaultStorageClass”的admission controller,即在kube-apiserver的命令参数中的--admission-control中增长:DefaultStorageClass
例:--admission-control=“xxx,xxx,xxx, DefaultStorageClass”
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: gold annotations: storageclass.beta.kubernetes.io/is-default-class="true" provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd
而后建立这个storageClass,此时咱们在经过命令可查看:
[::root]kubelet get sc -n=xxx
注意:默认的storageClass只能设置一个,不然系统会由于多个default引发冲突,而不知道筛选哪个为默认的,最终致使默认的storageClass不生效。
这个案例从定义storageClass、建立storageFS和Heketi服务、用户申请PVC到建立Pod使用存储资源,对storageClass和动态资源分配进行详细说明,进一步分析kubernetes的存储机制。
这里的案例是参考至:
https://www.cnblogs.com/xiaoqshuo/p/10096682.html 和《kubernetes权威指南》
GlusterFS是Scale-Out存储解决方案Gluster的核心,它是一个开源的分布式文件系统,具备强大的横向扩展能力,经过扩展可以支持数PB存储容量和处理数千客户端。GlusterFS借助TCP/IP或InfiniBand RDMA网络将物理分布的存储资源汇集在一块儿,使用单一全局命名空间来管理数据。GlusterFS基于可堆叠的用户空间设计,可为各类不一样的数据负载提供优异的性能。
GlusterFS支持运行在任何标准IP网络上标准应用程序的标准客户端,用户能够在全局统一的命名空间中使用NFS/CIFS等标准协议来访问应用数据。GlusterFS使得用户可摆脱原有的独立、高成本的封闭存储系统,可以利用普通廉价的存储设备来部署可集中管理、横向扩展、虚拟化的存储池,存储容量可扩展至TB/PB级。
GlusterFS以原始数据格式(如EXT三、EXT四、XFS、ZFS)储存数据,并实现多种数据自动修复机制。
架构图:
这里只是带你们了解一下GlusterFS,便于理解后面PVC挂载的内容,无需过多深刻。
Heketi服务是一个提供REST ful API管理GlusterFS卷框架,并可以在kubernetes、openstack等云平台上实现动态存储资源供应,支持GlusterFS多集群管理,便于管理员对GlusterFS进行操做,以下图简单介绍了Heketi服务的做用:
① 在各个计划用于GlusterFS的node上安装GlusterFS客户端
#yum install glusterfs glusterfs-fuse -y
② 在master的kube-apiserver服务和待启动GlusterFS的各个node上的kubelet服务的启动参数中入:--allow-privileged=true
③ 载入指定的个别模块
modprobe dm_snapshot modprobe dm_mirror modprobe dm_thin_pool
④ 为要部署GlusterFS的node打上标签,为了将GlusterFS容器定向部署到安装了GlusterFS的node上
[root@k8s-master01 ~]# kubectl label node k8s-node-1 storagenode=glusterfs node/k8s-node-1 labeled [root@k8s-master01 ~]# kubectl label node k8s-node-2 storagenode=glusterfs node/k8s-node-2 labeled [root@k8s-master01 ~]# kubectl label node k8s-node-3 storagenode=glusterfs node/k8s-node-3 labeled
⑤ 建立GlusterFS管理服务容器集群
#glusterfs-daemonset.yaml:
kind: DaemonSet apiVersion: extensions/v1beta1 metadata: name: glusterfs labels: glusterfs: daemonset annotations: description: GlusterFS DaemonSet tags: glusterfs spec: template: metadata: name: glusterfs labels: glusterfs-node: pod spec: nodeSelector: storagenode: glusterfs hostNetwork: true containers: - image: gluster/gluster-centos:latest name: glusterfs volumeMounts: - name: glusterfs-heketi mountPath: "/var/lib/heketi" - name: glusterfs-run mountPath: "/run" - name: glusterfs-lvm mountPath: "/run/lvm" - name: glusterfs-etc mountPath: "/etc/glusterfs" - name: glusterfs-log mountPath: "/var/log/glusterfs" - name: glusterfs-config mountPath: "/var/lib/glusterd" - name: glusterfs-dev mountPath: "/dev" - name: glusterfs-misc mountPath: "/var/lib/misc/glusterfsd" - name: glusterfs-cgroup mountPath: "/sys/fs/cgroup" readOnly: true - name: glusterfs-ssl mountPath: "/etc/ssl" readOnly: true securityContext: capabilities: {} privileged: true readinessProbe: timeoutSeconds: 3 initialDelaySeconds: 60 exec: command: - "/bin/bash" - "-c" - systemctl status glusterd.service livenessProbe: timeoutSeconds: 3 initialDelaySeconds: 60 exec: command: - "/bin/bash" - "-c" - systemctl status glusterd.service volumes: - name: glusterfs-heketi hostPath: path: "/var/lib/heketi" - name: glusterfs-run - name: glusterfs-lvm hostPath: path: "/run/lvm" - name: glusterfs-etc hostPath: path: "/etc/glusterfs" - name: glusterfs-log hostPath: path: "/var/log/glusterfs" - name: glusterfs-config hostPath: path: "/var/lib/glusterd" - name: glusterfs-dev hostPath: path: "/dev" - name: glusterfs-misc hostPath: path: "/var/lib/misc/glusterfsd" - name: glusterfs-cgroup hostPath: path: "/sys/fs/cgroup" - name: glusterfs-ssl hostPath: path: "/etc/ssl"
#kubelet create -f glusterfs-daemonset.yaml #建立 #kubectl get pods #查看 NAME READY STATUS RESTARTS AGE glusterfs-fvxh7 1/1 Running 0 47m glusterfs-jjw7b 1/1 Running 0 47m glusterfs-td875 1/1 Running 0 47m
⑥建立Heketi服务
在部署Heketi以前,须要为他建立一个ServiceAccount对象:
#heketi-service-account.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: heketi-service-account
#kubelet create -f heketi-service-account.yaml
#heketi-deployment-svc.yaml
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: deploy-heketi labels: glusterfs: heketi-deployment deploy-heketi: heketi-deployment annotations: description: Defines how to deploy Heketi spec: relicas: 1 template: metadata: name: deploy-heketi labels: glusterfs: heketi-pod spec: ServiceAccountName: heketi-service-account containers: - image: heketi/heketi:dev name: deploy-heketi env: - name: HEKETI_EXECUTOR value: kubernetes - name: HEKETI_FSTAB value: "/var/lib/heketi/fstab" - name: HEKETI_SNAPSHOT_LIMIT value: "14" - name: HEKETI_KUBE_GLUSTER_DAEONSET value: "y" ports: - containerPort: 8080 volumeMounts: - name: db mountPath: "/var/lib/heketi" readinessProbe: timeoutSeconds: 3 initialDelaySeconds: 3 httpGet: path: "/hello" port: 8080 livenessProbe: timeoutSeconds: 3 initialDelaySeconds: 30 httpGet: path: "/hello" port: 8080 volumes: - name: db hostPath: path: "/heketi-data" --- kind: Service apiVersion: v1 metadata: name: deploy-heketi labels: glusterfs: heketi-service deploy-heketi: support annotations: description: Exposes Heketi Service spec: selector: name: deploy-heketi ports: - name: deploy-heketi port: 8080 targetPort: 8080
#kubelete create -f heketi-deployment-svc.yaml
⑦ 为Heketi设置GlusterFS集群
在Heketi能管理GlusterFS集群以前,须要为其设置GlusterFS集群信息。可使用json配置文件传入,而且Heketi要求一个GlusterFS集群至少有3各节点。
#topology.json
{ "clusters": [ { "nodes": [ { "node": { "hostnames": { "manage": [ "k8s-node-1" ], "storage": [ "192.168.2.100" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdb" } ] }, { "node": { "hostnames": { "manage": [ "k8s-node-2" ], "storage": [ "192.168.2.101" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdc" } ] }, { "node": { "hostnames": { "manage": [ "k8s-node-3" ], "storage": [ "192.168.2.102" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdb" } ] } ] } ] }
而后进入Heketi的容器中,执行:
#export HEKETI_CLI_SERVER=http://localhost:8080 #heketi-cli topology load –json= topology.json
完成以上操做,Heketi就完成了GlusterFS集群的建立,同时在GlusterFS集群的各个节点上的/dev/sdb盘上成功建立了PV和VG。
注意:/dev/sdb必定要是未建立文件系统的裸设备。
#查看GFS信息
[root@k8s-node-1 kubernetes]# heketi-cli topology info
集群建立成功以后,固然咱们要试试,storageClass的功能能不能用啊:
① 定义storageClass
#storageclass-gluster-heketi.yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gluster-heketi provisioner: kubernetes-io/glusterfs parameters: resturl: "http://172.17.2.2:8080" restauthenabled: "false"
② 定义PVC
#pvc-gluster-heketi.yaml(使用动态资源供应模式)
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc-gluster-heketi spec: storageClassName: gluster-heketi accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
#能够经过命令查看pv,和自动建立的PVC
#kubelet get pvc #kubelet get pv
③ 使用pod挂载PVC
#pod-use-pvc.yaml
apiVersion: v1 kind: Pod metadata: name: pod-use-pvc spec: containers: - name: pod-use-pvc image: busybox command: - sleep - "3600" volumeMounts: - name: gluster-volume mountPath: "/pv-data" readOnly: false volumes: - name: gluster-volume persistentVolumeClaim: claimName: pvc-gluster-heketi
#kubelet create -f pod-use-pvc.yaml #建立这个pod
而后进入容器:
#kubelet exec -it pod-use-pvc /bin/sh
在其中的/pv-data 目录建立文件,而后验证文件在GlusterFS集群中是否生效!
文章内容参考至《kubernetes权威指南》