存储类
本文描述了 Kubernetes 中 StorageClass 的概念。 建议先熟悉卷和持久卷的概念。
介绍
StorageClass 为管理员提供了描述存储 "类" 的方法。 不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。 Kubernetes 本身并不清楚各种类代表的什么。这个类的概念在其他存储系统中有时被称为 "配置文件"。
StorageClass 资源
每个 StorageClass 都包含 provisioner
、parameters
和 reclaimPolicy
字段,
这些字段会在 StorageClass 需要动态分配 PersistentVolume 时会使用到。
StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。
管理员可以为没有申请绑定到特定 StorageClass 的 PVC 指定一个默认的存储类: 更多详情请参阅 PersistentVolumeClaim 章节。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
- debug
volumeBindingMode: Immediate
存储制备器
每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。 该字段必须指定。
卷插件 | 内置制备器 | 配置例子 |
---|---|---|
AWSElasticBlockStore | ✓ | AWS EBS |
AzureFile | ✓ | Azure File |
AzureDisk | ✓ | Azure Disk |
CephFS | - | - |
Cinder | ✓ | OpenStack Cinder |
FC | - | - |
FlexVolume | - | - |
GCEPersistentDisk | ✓ | GCE PD |
Glusterfs | ✓ | Glusterfs |
iSCSI | - | - |
NFS | - | NFS |
RBD | ✓ | Ceph RBD |
VsphereVolume | ✓ | vSphere |
PortworxVolume | ✓ | Portworx Volume |
Local | - | Local |
你不限于指定此处列出的 "内置" 制备器(其名称前缀为 "kubernetes.io" 并打包在 Kubernetes 中)。 你还可以运行和指定外部制备器,这些独立的程序遵循由 Kubernetes 定义的规范。 外部供应商的作者完全可以自由决定他们的代码保存于何处、打包方式、运行方式、使用的插件(包括 Flex)等。 代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一个用于为外部制备器编写功能实现的类库。你可以访问代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 了解外部驱动列表。
例如,NFS 没有内部制备器,但可以使用外部制备器。 也有第三方存储供应商提供自己的外部制备器。
回收策略
由 StorageClass 动态创建的 PersistentVolume 会在类的 reclaimPolicy
字段中指定回收策略,可以是
Delete
或者 Retain
。如果 StorageClass 对象被创建时没有指定 reclaimPolicy
,它将默认为 Delete
。
通过 StorageClass 手动创建并管理的 PersistentVolume 会使用它们被创建时指定的回收策略。
允许卷扩展
Kubernetes v1.11 [beta]
PersistentVolume 可以配置为可扩展。将此功能设置为 true
时,允许用户通过编辑相应的 PVC 对象来调整卷大小。
当下层 StorageClass 的 allowVolumeExpansion
字段设置为 true 时,以下类型的卷支持卷扩展。
卷类型 | Kubernetes 版本要求 |
---|---|
gcePersistentDisk | 1.11 |
awsElasticBlockStore | 1.11 |
Cinder | 1.11 |
glusterfs | 1.11 |
rbd | 1.11 |
Azure File | 1.11 |
Azure Disk | 1.11 |
Portworx | 1.11 |
FlexVolume | 1.13 |
CSI | 1.14 (alpha), 1.16 (beta) |
挂载选项
由 StorageClass 动态创建的 PersistentVolume 将使用类中 mountOptions
字段指定的挂载选项。
如果卷插件不支持挂载选项,却指定了挂载选项,则制备操作会失败。 挂载选项在 StorageClass 和 PV 上都不会做验证,如果其中一个挂载选项无效,那么这个 PV 挂载操作就会失败。
卷绑定模式
volumeBindingMode
字段控制了卷绑定和动态制备应该发生在什么时候。
默认情况下,Immediate
模式表示一旦创建了 PersistentVolumeClaim 也就完成了卷绑定和动态制备。
对于由于拓扑限制而非集群所有节点可达的存储后端,PersistentVolume
会在不知道 Pod 调度要求的情况下绑定或者制备。
集群管理员可以通过指定 WaitForFirstConsumer
模式来解决此问题。
该模式将延迟 PersistentVolume 的绑定和制备,直到使用该 PersistentVolumeClaim 的 Pod 被创建。
PersistentVolume 会根据 Pod 调度约束指定的拓扑来选择或制备。
这些包括但不限于资源需求、
节点筛选器、
Pod 亲和性和互斥性、
以及污点和容忍度。
以下插件支持动态制备的 WaitForFirstConsumer
模式:
以下插件支持预创建绑定 PersistentVolume 的 WaitForFirstConsumer
模式:
- 上述全部
- Local
Kubernetes v1.17 [stable]
动态制备和预先创建的 PV 也支持 CSI 卷, 但是你需要查看特定 CSI 驱动的文档以查看其支持的拓扑键名和例子。
如果你选择使用 WaitForFirstConsumer
,请不要在 Pod 规约中使用 nodeName
来指定节点亲和性。
如果在这种情况下使用 nodeName
,Pod 将会绕过调度程序,PVC 将停留在 pending
状态。
相反,在这种情况下,你可以使用节点选择器作为主机名,如下所示
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
nodeSelector:
kubernetes.io/hostname: kube-01
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
允许的拓扑结构
当集群操作人员使用了 WaitForFirstConsumer
的卷绑定模式,
在大部分情况下就没有必要将制备限制为特定的拓扑结构。
然而,如果还有需要的话,可以使用 allowedTopologies
。
这个例子描述了如何将制备卷的拓扑限制在特定的区域,
在使用时应该根据插件支持情况替换 zone
和 zones
参数。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-standard
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
- key: failure-domain.beta.kubernetes.io/zone
values:
- us-central-1a
- us-central-1b
参数
Storage Classes 的参数描述了存储类的卷。取决于制备器,可以接受不同的参数。 例如,参数 type 的值 io1 和参数 iopsPerGB 特定于 EBS PV。 当参数被省略时,会使用默认值。
一个 StorageClass 最多可以定义 512 个参数。这些参数对象的总长度不能超过 256 KiB, 包括参数的键和值。
AWS EBS
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
iopsPerGB: "10"
fsType: ext4
type
:io1
,gp2
,sc1
,st1
。详细信息参见 AWS 文档。默认值:gp2
。zone
(弃用):AWS 区域。如果没有指定zone
和zones
, 通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。zone
和zones
参数不能同时使用。zones
(弃用):以逗号分隔的 AWS 区域列表。 如果没有指定zone
和zones
,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。zone
和zones
参数不能同时使用。iopsPerGB
:只适用于io1
卷。每 GiB 每秒 I/O 操作。 AWS 卷插件将其与请求卷的大小相乘以计算 IOPS 的容量, 并将其限制在 20000 IOPS(AWS 支持的最高值,请参阅 AWS 文档。 这里需要输入一个字符串,即"10"
,而不是10
。fsType
:受 Kubernetes 支持的文件类型。默认值:"ext4"
。encrypted
:指定 EBS 卷是否应该被加密。合法值为"true"
或者"false"
。 这里需要输入字符串,即"true"
, 而非true
。kmsKeyId
:可选。加密卷时使用密钥的完整 Amazon 资源名称。 如果没有提供,但encrypted
值为 true,AWS 生成一个密钥。关于有效的 ARN 值,请参阅 AWS 文档。
zone
和 zones
已被弃用并被 允许的拓扑结构 取代。
GCE PD
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-standard
fstype: ext4
replication-type: none
type
:pd-standard
或者pd-ssd
。默认:pd-standard
zone
(弃用):GCE 区域。如果没有指定zone
和zones
, 通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。zone
和zones
参数不能同时使用。zones
(弃用):逗号分隔的 GCE 区域列表。如果没有指定zone
和zones
, 通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配。zone
和zones
参数不能同时使用。fstype
:ext4
或xfs
。 默认:ext4
。宿主机操作系统必须支持所定义的文件系统类型。replication-type
:none
或者regional-pd
。默认值:none
。
如果 replication-type
设置为 none
,会制备一个常规(当前区域内的)持久化磁盘。
如果 replication-type
设置为 regional-pd
,
会制备一个区域性持久化磁盘(Regional Persistent Disk)。
强烈建议设置 volumeBindingMode: WaitForFirstConsumer
,这样设置后,
当你创建一个 Pod,它使用的 PersistentVolumeClaim 使用了这个 StorageClass,
区域性持久化磁盘会在两个区域里制备。 其中一个区域是 Pod 所在区域。
另一个区域是会在集群管理的区域中任意选择。磁盘区域可以通过 allowedTopologies
加以限制。
Glusterfs
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/glusterfs
parameters:
resturl: "http://127.0.0.1:8081"
clusterid: "630372ccdc720a92c681fb928f27b53f"
restauthenabled: "true"
restuser: "admin"
secretNamespace: "default"
secretName: "heketi-secret"
gidMin: "40000"
gidMax: "50000"
volumetype: "replicate:3"
resturl
:制备 gluster 卷的需求的 Gluster REST 服务/Heketi 服务 url。 通用格式应该是IPaddress:Port
,这是 GlusterFS 动态制备器的必需参数。 如果 Heketi 服务在 OpenShift/kubernetes 中安装并暴露为可路由服务,则可以使用类似于http://heketi-storage-project.cloudapps.mystorage.com
的格式,其中 fqdn 是可解析的 heketi 服务网址。restauthenabled
:Gluster REST 服务身份验证布尔值,用于启用对 REST 服务器的身份验证。 如果此值为 'true',则必须填写restuser
和restuserkey
或secretNamespace
+secretName
。 此选项已弃用,当在指定restuser
、restuserkey
、secretName
或secretNamespace
时,身份验证被启用。restuser
:在 Gluster 可信池中有权创建卷的 Gluster REST服务/Heketi 用户。restuserkey
:Gluster REST 服务/Heketi 用户的密码将被用于对 REST 服务器进行身份验证。 此参数已弃用,取而代之的是secretNamespace
+secretName
。
-
secretNamespace
,secretName
:Secret 实例的标识,包含与 Gluster REST 服务交互时使用的用户密码。 这些参数是可选的,secretNamespace
和secretName
都省略时使用空密码。 所提供的 Secret 必须将类型设置为 "kubernetes.io/glusterfs",例如以这种方式创建:kubectl create secret generic heketi-secret \ --type="kubernetes.io/glusterfs" --from-literal=key='opensesame' \ --namespace=default
Secret 的例子可以在 glusterfs-provisioning-secret.yaml 中找到。
clusterid
:630372ccdc720a92c681fb928f27b53f
是集群的 ID,当制备卷时, Heketi 将会使用这个文件。它也可以是一个 clusterid 列表,例如:"8452344e2becec931ece4e33c4674e4e,42982310de6c63381718ccfa6d8cf397"
。这个是可选参数。gidMin
,gidMax
:StorageClass GID 范围的最小值和最大值。 在此范围(gidMin-gidMax)内的唯一值(GID)将用于动态制备卷。这些是可选的值。 如果不指定,所制备的卷为一个 2000-2147483647 之间的值,这是 gidMin 和 gidMax 的默认值。
-
volumetype
:卷的类型及其参数可以用这个可选值进行配置。如果未声明卷类型,则由制备器决定卷的类型。 例如:- 'Replica volume':
volumetype: replicate:3
其中 '3' 是 replica 数量。 - 'Disperse/EC volume':
volumetype: disperse:4:2
其中 '4' 是数据,'2' 是冗余数量。 - 'Distribute volume':
volumetype: none
有关可用的卷类型和管理选项, 请参阅管理指南。
更多相关的参考信息, 请参阅如何配置 Heketi。
当动态制备持久卷时,Gluster 插件自动创建名为
gluster-dynamic-<claimname>
的端点和无头服务。在 PVC 被删除时动态端点和无头服务会自动被删除。 - 'Replica volume':
NFS
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: example-nfs
provisioner: example.com/external-nfs
parameters:
server: nfs-server.example.com
path: /share
readOnly: "false"
server
:NFS 服务器的主机名或 IP 地址。path
:NFS 服务器导出的路径。readOnly
:是否将存储挂载为只读的标志(默认为 false)。
Kubernetes 不包含内部 NFS 驱动。你需要使用外部驱动为 NFS 创建 StorageClass。 这里有些例子:
OpenStack Cinder
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gold
provisioner: kubernetes.io/cinder
parameters:
availability: nova
availability
:可用区域。如果没有指定,通常卷会在 Kubernetes 集群节点所在的活动区域中轮转调度。
Kubernetes 1.11 [deprecated]
OpenStack 的内部驱动已经被弃用。请使用 OpenStack 的外部云驱动。
vSphere
vSphere 存储类有两种制备器
树内制备器已经被 弃用。 更多关于 CSI 制备器的详情,请参阅 Kubernetes vSphere CSI 驱动 和 vSphereVolume CSI 迁移。
CSI 制备器
vSphere CSI StorageClass 制备器在 Tanzu Kubernetes 集群下运行。示例请参阅 vSphere CSI 仓库。
vCP 制备器
以下示例使用 VMware Cloud Provider (vCP) StorageClass 调度器。
-
使用用户指定的磁盘格式创建一个 StorageClass。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/vsphere-volume parameters: diskformat: zeroedthick
diskformat
:thin
,zeroedthick
和eagerzeroedthick
。默认值:"thin"
。
-
在用户指定的数据存储上创建磁盘格式的 StorageClass。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/vsphere-volume parameters: diskformat: zeroedthick datastore: VSANDatastore
datastore
:用户也可以在 StorageClass 中指定数据存储。 卷将在 storage class 中指定的数据存储上创建,在这种情况下是VSANDatastore
。 该字段是可选的。 如果未指定数据存储,则将在用于初始化 vSphere Cloud Provider 的 vSphere 配置文件中指定的数据存储上创建该卷。
-
Kubernetes 中的存储策略管理
-
使用现有的 vCenter SPBM 策略
vSphere 用于存储管理的最重要特性之一是基于策略的管理。 基于存储策略的管理(SPBM)是一个存储策略框架,提供单一的统一控制平面的跨越广泛的数据服务和存储解决方案。 SPBM 使得 vSphere 管理员能够克服先期的存储配置挑战,如容量规划、差异化服务等级和管理容量空间。
SPBM 策略可以在 StorageClass 中使用
storagePolicyName
参数声明。
-
Kubernetes 内的 Virtual SAN 策略支持
Vsphere Infrastructure(VI)管理员将能够在动态卷配置期间指定自定义 Virtual SAN 存储功能。你现在可以在动态制备卷期间以存储能力的形式定义存储需求,例如性能和可用性。 存储能力需求会转换为 Virtual SAN 策略,之后当持久卷(虚拟磁盘)被创建时, 会将其推送到 Virtual SAN 层。虚拟磁盘分布在 Virtual SAN 数据存储中以满足要求。
你可以参考基于存储策略的动态制备卷管理, 进一步了解有关持久卷管理的存储策略的详细信息。
-
有几个 vSphere 例子供你在 Kubernetes for vSphere 中尝试进行持久卷管理。
Ceph RBD
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/rbd
parameters:
monitors: 10.16.153.105:6789
adminId: kube
adminSecretName: ceph-secret
adminSecretNamespace: kube-system
pool: kube
userId: kube
userSecretName: ceph-secret-user
userSecretNamespace: default
fsType: ext4
imageFormat: "2"
imageFeatures: "layering"
monitors
:Ceph monitor,逗号分隔。该参数是必需的。adminId
:Ceph 客户端 ID,用于在池 ceph 池中创建映像。默认是 "admin"。adminSecret
:adminId
的 Secret 名称。该参数是必需的。 提供的 secret 必须有值为 "kubernetes.io/rbd" 的 type 参数。adminSecretNamespace
:adminSecret
的命名空间。默认是 "default"。pool
: Ceph RBD 池. 默认是 "rbd"。userId
:Ceph 客户端 ID,用于映射 RBD 镜像。默认与adminId
相同。
-
userSecretName
:用于映射 RBD 镜像的userId
的 Ceph Secret 的名字。 它必须与 PVC 存在于相同的 namespace 中。该参数是必需的。 提供的 secret 必须具有值为 "kubernetes.io/rbd" 的 type 参数,例如以这样的方式创建:kubectl create secret generic ceph-secret --type="kubernetes.io/rbd" \ --from-literal=key='QVFEQ1pMdFhPUnQrSmhBQUFYaERWNHJsZ3BsMmNjcDR6RFZST0E9PQ==' \ --namespace=kube-system
userSecretNamespace
:userSecretName
的命名空间。fsType
:Kubernetes 支持的 fsType。默认:"ext4"
。imageFormat
:Ceph RBD 镜像格式,"1" 或者 "2"。默认值是 "1"。imageFeatures
:这个参数是可选的,只能在你将imageFormat
设置为 "2" 才使用。 目前支持的功能只是layering
。默认是 "",没有功能打开。
Azure 磁盘
Azure Unmanaged Disk Storage Class(非托管磁盘存储类)
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: slow
provisioner: kubernetes.io/azure-disk
parameters:
skuName: Standard_LRS
location: eastus
storageAccount: azure_storage_account_name
skuName
:Azure 存储帐户 Sku 层。默认为空。location
:Azure 存储帐户位置。默认为空。storageAccount
:Azure 存储帐户名称。 如果提供存储帐户,它必须位于与集群相同的资源组中,并且location
是被忽略的。如果未提供存储帐户,则会在与集群相同的资源组中创建新的存储帐户。
Azure 磁盘 Storage Class(从 v1.7.2 开始)
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: slow
provisioner: kubernetes.io/azure-disk
parameters:
storageaccounttype: Standard_LRS
kind: managed
storageaccounttype
:Azure 存储帐户 Sku 层。默认为空。kind
:可能的值是shared
、dedicated
和managed
(默认)。 当kind
的值是shared
时,所有非托管磁盘都在集群的同一个资源组中的几个共享存储帐户中创建。 当kind
的值是dedicated
时,将为在集群的同一个资源组中新的非托管磁盘创建新的专用存储帐户。resourceGroup
: 指定要创建 Azure 磁盘所属的资源组。必须是已存在的资源组名称。 若未指定资源组,磁盘会默认放入与当前 Kubernetes 集群相同的资源组中。
- Premium VM 可以同时添加 Standard_LRS 和 Premium_LRS 磁盘,而 Standard 虚拟机只能添加 Standard_LRS 磁盘。
- 托管虚拟机只能连接托管磁盘,非托管虚拟机只能连接非托管磁盘。
Azure 文件
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: azurefile
provisioner: kubernetes.io/azure-file
parameters:
skuName: Standard_LRS
location: eastus
storageAccount: azure_storage_account_name
skuName
:Azure 存储帐户 Sku 层。默认为空。location
:Azure 存储帐户位置。默认为空。storageAccount
:Azure 存储帐户名称。默认为空。 如果不提供存储帐户,会搜索所有与资源相关的存储帐户,以找到一个匹配skuName
和location
的账号。 如果提供存储帐户,它必须存在于与集群相同的资源组中,skuName
和location
会被忽略。secretNamespace
:包含 Azure 存储帐户名称和密钥的密钥的名字空间。 默认值与 Pod 相同。secretName
:包含 Azure 存储帐户名称和密钥的密钥的名称。 默认值为azure-storage-account-<accountName>-secret
readOnly
:指示是否将存储安装为只读的标志。默认为 false,表示"读/写"挂载。 该设置也会影响VolumeMounts中的ReadOnly
设置。
在存储制备期间,为挂载凭证创建一个名为 secretName
的 Secret。如果集群同时启用了
RBAC
和控制器角色,
为 system:controller:persistent-volume-binder
的 clusterrole 添加
Secret
资源的 create
权限。
在多租户上下文中,强烈建议显式设置 secretNamespace
的值,否则其他用户可能会读取存储帐户凭据。
Portworx 卷
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: portworx-io-priority-high
provisioner: kubernetes.io/portworx-volume
parameters:
repl: "1"
snap_interval: "70"
priority_io: "high"
fs
:选择的文件系统:none/xfs/ext4
(默认:ext4
)。block_size
:以 Kbytes 为单位的块大小(默认值:32
)。repl
:同步副本数量,以复制因子1..3
(默认值:1
)的形式提供。 这里需要填写字符串,即,"1"
而不是1
。io_priority
:决定是否从更高性能或者较低优先级存储创建卷high/medium/low
(默认值:low
)。snap_interval
:触发快照的时钟/时间间隔(分钟)。 快照是基于与先前快照的增量变化,0 是禁用快照(默认:0
)。 这里需要填写字符串,即,是"70"
而不是70
。aggregation_level
:指定卷分配到的块数量,0 表示一个非聚合卷(默认:0
)。 这里需要填写字符串,即,是"0"
而不是0
。ephemeral
:指定卷在卸载后进行清理还是持久化。emptyDir
的使用场景可以将这个值设置为 true,persistent volumes
的使用场景可以将这个值设置为 false (例如 Cassandra 这样的数据库)true/false
(默认为false
)。这里需要填写字符串,即, 是"true"
而不是true
。
本地
Kubernetes v1.14 [stable]
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
本地卷还不支持动态制备,然而还是需要创建 StorageClass 以延迟卷绑定,
直到完成 Pod 的调度。这是由 WaitForFirstConsumer
卷绑定模式指定的。
延迟卷绑定使得调度器在为 PersistentVolumeClaim 选择一个合适的 PersistentVolume 时能考虑到所有 Pod 的调度限制。