一、存储类
1、存储类的好处
支持pv的动态创建、用户用到持久性存储时、需要通过创建pvc来绑定配pv此类操作需求动态创建适配的pv会存储管理带来极大的灵活性
二、StorageClass的关键配置参数
1、关键配置参数详解
[root@master chapter7]# kubectl explain StorageClass KIND: StorageClass VERSION: storage.k8s.io/v1 DESCRIPTION: StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned. StorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name. FIELDS: allowVolumeExpansion <boolean> AllowVolumeExpansion shows whether the storage class allow volume expand allowedTopologies <[]Object> Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is only honored by servers that enable the VolumeScheduling feature. apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds metadata <Object> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata mountOptions <[]string> #由当前动态创建的pv的挂载选项列表 Dynamically provisioned PersistentVolumes of this storage class are created with these mountOptions, e.g. ["ro", "soft"]. Not validated - mount of the PVs will simply fail if one is invalid. parameters <map[string]string> #存储类使用参数描述要关联到的存储卷、不过、不同的Provisioner可用的参数各不相同 Parameters holds the parameters for the provisioner that should create volumes of this storage class. provisioner <string> -required- #即提供了存储资源的存储系统,存储类要依赖Provisioner来判定要使用的存储插件以便适配到目标存储系统、kubernetes内核有多中供给方Provisioner、这些供给方的名称都以kubernetes.io为前缀。另外,它还支持用户依据kubernetes规范定义的Provisioner Provisioner indicates the type of the provisioner. reclaimPolicy <string> #为当前存储类动态床架你的pv指定回收策略,可用之Delete和retain;不过那些由管理员手创建的pv的回收策略则取决于他们自身的定义 Dynamically provisioned PersistentVolumes of this storage class are created with this reclaimPolicy. Defaults to Delete. volumeBindingMode <string> #定义如何为pvc完成供给和绑定,默认值为:VolumeScheduling;此选项仅在启用了存储卷调度功能时才能生效 VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is only honored by servers that enable the VolumeScheduling feature.
2、资源清单
[root@master chapter7]# cat glusterfs-storageclass.yaml kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: glusters provisioner: kubernetes.io/glusterfs parameters: resturl: "http://heketi.ilinux.io:8080" restauthenabled: "false" restuser: "ik8s" restuserkey: "ik8s.io"
1、parameters.resturl字段用于指定gluster存储系统的RESTful风格的访问接口
2、本示例中使用的http://heketi.ilinux.io:8080应替换为自己实际环境中的可用地址、gluster存储系统本身并不支持这种访问放手、不过只有再restauthenabled设置为"true"时restuser和restuserkey字段才会启用
二、动态供给pv供给
动态PV供给的启用、需要实现由管理员至少一个存储类,不同的Provisoner的创建方法各有不同、并非所有的存储插件都有Kubernetes内建支持PV动态供给功能
上文中定义glusterfs存储类资源创建完成后、便可以根据使用动态PV供给功能、下面的资源清单定义在pvc-gluserfs-dynamic-0001配置文件它将从glusterfs存储类中申请使用5GB的存储空间
1、配置清单
[root@master chapter7]# cat pvc-gluster-dynamic-0001.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-gluster-dynamic-0001 annotations: volume.beta.kubernetes.io/storage-class: gluster-dynamic spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi
2、创建及查看详细信息
各种存储插件对动态供给方式的支持状况
目前、在PVC的定义中指定使用的存储类资源的方式共有两种:一种是使用spec.StorageClass字段、一种是使用"volume.beta.kubernetes.io/storage-class"字段,不过,建议仅适用一种方式,以免两者设置为不同的值时会出现配置错误、接下来创建定义PVC,并检查其绑定状态
[root@master chapter7]# kubectl apply -f pvc-gluster-dynamic-0001.yaml persistentvolumeclaim/pvc-gluster-dynamic-0001 created [root@master chapter7]# kubectl describe pvc-gluster-dynamic-0001 error: the server doesn't have a resource type "pvc-gluster-dynamic-0001" [root@master chapter7]# kubectl describe pvc pvc-gluster-dynamic-0001 Name: pvc-gluster-dynamic-0001 Namespace: default StorageClass: gluster-dynamic Status: Pending Volume: Labels: <none> Annotations: volume.beta.kubernetes.io/storage-class: gluster-dynamic Finalizers: [kubernetes.io/pvc-protection] Capacity: Access Modes: VolumeMode: Filesystem Mounted By: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning ProvisioningFailed 14s (x3 over 31s) persistentvolume-controller storageclass.storage.k8s.io "gluster-dynamic" not found
任何支持PV动态供给的存储系统都可以在定义为存储类后由PVC动态申请使用、这对于难于预估使用的存储空间大小及存储卷数量的使用场景尤为有用例如由StatefulSet控制管理POD对象时,
存储卷是必备资源,且随着规模变动,存储卷的数量也会随之变动
另外、用户也可以使用云端存储提供的PV动态供给机制,如AWS EBS、AzureDisk、Cinder或GCEPersistentDisk等,将kubernetes部署与Iaas云端时、此种存储方式使用的较多、各类云存储动态供给的具体使用方式请参考相关的使用手册
三、PV和PVC的生命周期
1、架构图
我们可以将PV看作可用的存储资源,PVC则是对存储资源的需求,PV和PVC的相互关系遵循如下图所示
2、资源供给
Kubernetes支持两种资源的供应模式:静态模式(Static)和动态模式(Dynamic)。资源供应的结果就是创建好的PV。
静态模式:集群管理员手工创建许多PV,在定义PV时需要将后端存储的特性进行设置。
动态模式:集群管理员无须手工创建PV,而是通过StorageClass的设置对后端存储进行描述,标记为某种类型。此时要求PVC对存储的类型进行声明,系统将自动完成PV的创建及与PVC的绑定。
PVC可以声明Class为"",说明该PVC禁止使用动态模式。
3、资源绑定
在用户定义好PVC之后,系统将根据PVC对存储资源的请求(存储空间和访问模式)在已存在的PV中选择一个满足PVC要求的PV,一旦找到,就将该PV与用户定义的PVC进行绑定,
用户的应用就可以使用这个PVC了。
如果在系统中没有满足PVC要求的PV,PVC则会无限期处于Pending状态,直到等到系统管理员创建了一个符合其要求的PV。PV一旦绑定到某个PVC上,就会被这个PVC独占,不能再与其他PVC进行绑定了。
在这种情况下,当PVC申请的存储空间比PV的少时,整个PV的空间就都能够为PVC所用,可能会造成资源的浪费。如果资源供应使用的是动态模式,则系统在为PVC找到合适的StorageClass后,将自动创建一个PV并完成与PVC的绑定。
4、资源使用
Pod使用Volume的定义,将PVC挂载到容器内的某个路径进行使用。Volume的类型为persistentVolumeClaim,在后面的示例中再进行详
细说明。在容器应用挂载了一个PVC后,就能被持续独占使用。不过,多个Pod可以挂载同一个PVC,应用程序需要考虑多个实例共同访问一块存储空间的问题。
存储使用(using)
POD资源基于persistentVolumeClaim卷类型的定义、将选择定的PVC关联为存储卷、而后即可为内部的容器所使用、对于支持多种访问模式的存储卷来说、用户需要额外指定要使用的模式
一旦完成将存储卷挂载值POD对象内的容器中,其应用即可使用关联的PV提供的存储空间
PVC保护(partition)
有用户删除了仍处于某pod资源使用中的PVC时,Kubernetes不会立即予以移除、而是推迟到不再被任何pod资源使用后方才执行删除操作处于此种阶段的PVC资源的status字段为"termination"
并且其Finalizers字段中包含"kubernetes.io/pvc-protection"
5、资源释放
当用户对存储资源使用完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为“已释放”,但还不能立刻与其他PVC进行绑定。
通过之前PVC写入的数据可能还被留在存储设备上,只有在清除之后该PV才能再次使用。
6、存储回收
对于PV,管理员可以设定回收策略,用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收,
才能供新的PVC绑定和使用。回收策略详见下节的说明。下面通过两张图分别对在静态资源供应模式和动态资源供应模式下,PV、PVC、StorageClass及Pod使用PVC的原理进行说明。
下图描述了在静态资源供应模式下,通过PV和PVC完成绑定,并供Pod使用的存储管理机制。
下图描述了在动态资源供应模式下,通过StorageClass和PVC完成资源动态绑定(系统自动生成PV),并供Pod使用的存储管理机制
1、留存(Retain)
留存策略意味着在删除PVC之后、kubernetes系统不会自动删除PV,而仅仅是将它置于"释放(releases)状态"、不过,此种状态的PV尚且不能被其他PVC申请所绑定、因为此前的申请生成的数据仍然存在,
需要由管理员手动决定其后续处理方案。这就意味着,如果想要再次使用此类的PV资源、则需要由管理员按下面的步骤手动执行删除操作
删除PV,这折后,此PV的数据依然留存于外部的存储智商 手工清理存储系统上依然留存的数学 手工删除存储系统级的存储卷(例如:RBD存储系统山过的images)以释放空间、以便再次创建、或者直接将其重新创建为PV
2、回收( Recycle)
如果可被底层存储插件支持,资源回收策略会在存储卷商执行数据删除操作并让PV资源再次变为可被Claim.另外、管理元也可以配制一个自定义的回收器POD模板、以便执行自定义的回收操作、不过、此种回收策略行将废弃
3、删除(delete)
对于支持Delete回收策略的存储插件来说、在PVC被删除后会直接移除PV对象、同时移除的还有PV相关的外部存储系统上的存储资产(asset)、支持这种操作的存储系统有AWS EBS、GCE PD、Azure Disk或Cinder。动态创建的PV资源的回收策略屈居于相关存储类上的定义、存储类上相关的默认策略为delete、大多数情况下、管理元都需要按用户期望的处理机制修改此默认策略、以免导致数据费计划内的误删除
四、downwardAPI存储卷
很多时候、应用程序需要给予其所在的环境信息设定运行特性等、这类环境信息包括节点及集群的部分详细属性信息等
Nginx进程根据节点的cpu核心数量自动设定要启动的worker进程数 JVM虚拟机可根据节点内存资源自动个设定其堆内存大小 托管运行于kubernetes的POD对象中的容器化应用偶尔也需要获取其所属pod对象的IP、主机名、标签、注解、UID、请求的CPU及内存资源量及其限额甚至是POD所在的节点名称
容器可通过环境变量或downwardAPI存储卷访问此类信息、不过、标签和注解仅支持通过存储卷暴露给容器
1、环境变量式元数据注入
引用downwardAPI元数据信息的常用方式之一是使用容器的环境变量、它通过在valueFrom字段中嵌套fieldRef或resourceFieldRef字段来引用相应的数据源
不过、通常只有常量类的属性才能够通过环境变量注入到容器中、毕竟、在进程启动完成后无法再向其告知变量值的变动、于是、环境变量也支持中途的更新操作可通过fieldRef字段引用的信息具体如下:
pod.spec.nodeName #节点名称 pod.spec.serviceAccountName #pod对象使用的serviceAccount资源名称 pod.status.hostIP #节点IP地址 pod.status.podIP #pod对象的IP地址 pod.metadata.name #pod对象的名称 pod.metadata.namespace #pod对象隶属的名称空间 pod.metadata.labels #pod对象标签中的指定键的值 pod.metadata.annotations #pod对象注解信息中的指定键的值
资源清单
[root@master chapter7]# cat downwardAPI-env.yaml apiVersion: v1 kind: Pod metadata: name: env-test-pod labels: app: env-test-pod spec: containers: - name: env-test-container image: busybox command: [ "/bin/sh", "-c", "env" ] resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" env: - name: MY_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: MY_POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: MY_APP_LABEL valueFrom: fieldRef: fieldPath: metadata.labels['app'] - name: MY_CPU_LIMIT valueFrom: resourceFieldRef: resource: limits.cpu - name: MY_MEM_REQUEST valueFrom: resourceFieldRef: resource: requests.memory divisor: 1Mi restartPolicy: Never
此POD对象创建完成后、向控制台打印所有的环境变量即可终止运行、它仅用于测试通过环境变量注入信息到容器的使用效果
运行查看环境变量
[root@master chapter7]# kubectl create -f downwardAPI-env.yaml pod/env-test-pod created [root@master chapter7]# kubectl get pods -l app=env-test-pod NAME READY STATUS RESTARTS AGE env-test-pod 0/1 ContainerCreating 0 23s [root@master chapter7]# kubectl get pods -l app=env-test-pod NAME READY STATUS RESTARTS AGE env-test-pod 0/1 Completed 0 30s
而后即可通过控制台日志获取注入的环境变量
[root@master chapter7]# kubectl logs env-test-pod |grep "^MY_" MY_POD_NAMESPACE=default MY_CPU_LIMIT=1 MY_APP_LABEL=env-test-pod MY_MEM_REQUEST=32 MY_POD_NAME=env-test-pod
未为容器定义资源请求及资源限制时、downwardAPI引用的值即默认为节点的可分配CPU及内存资源量
2、存储卷式元数据注入
资源清单
[root@master chapter7]# cat downwardAPI-vol.yaml kind: Pod apiVersion: v1 metadata: labels: zone: east-china cluster: downward-api-test-cluster1 rack: rack-101 app: dapi-vol-pod name: dapi-vol-pod annotations: annotation1: "test-value-1" annotation2: "test-value-2" spec: containers: - name: volume-test-container image: busybox command: ["sh", "-c", "sleep 864000"] resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" volumeMounts: - name: podinfo mountPath: /etc/podinfo readOnly: false volumes: - name: podinfo downwardAPI: defaultMode: 420 items: - fieldRef: fieldPath: metadata.name path: pod_name - fieldRef: fieldPath: metadata.namespace path: pod_namespace - fieldRef: fieldPath: metadata.labels path: pod_labels - fieldRef: fieldPath: metadata.annotations path: pod_annotations - resourceFieldRef: containerName: volume-test-container resource: limits.cpu path: "cpu_limit" - resourceFieldRef: containerName: volume-test-container resource: requests.memory divisor: "1Mi" path: "mem_request"
运行查看
[root@master chapter7]# kubectl apply -f downwardAPI-vol.yaml pod/dapi-vol-pod created [root@master chapter7]# kubectl get pods -l app=dapi-vol-pod NAME READY STATUS RESTARTS AGE dapi-vol-pod 1/1 Running 0 3m38s
接下来即可测试访问上述的映射文件,例如查看pod对象的标签列表
[root@master chapter7]# kubectl exec dapi-vol-pod -- cat /etc/podinfo/pod_labels app="dapi-vol-pod" rack="rack-101" zone="east-china" [root@master chapter7]# kubectl label pods dapi-vol-pod env="test" pod/dapi-vol-pod labeled
而后再次查看容器内的pod_labels文件的内容、由如下的命令结果可知新的标签已经能够通过相关的文件获取到:
[root@master chapter7]# kubectl exec dapi-vol-pod -- cat /etc/podinfo/pod_labels app="dapi-vol-pod" cluster="downward-api-test-cluster1" env="test" rack="rack-101" zone="east-china"