Kuberentes集群添加腾讯云CBS为默认存储

前言

目前公司已经将有状态服务部署在 Kubernetes 集群中,所以对存储能力的需求也越来越强烈。由于我们使用的是灵雀云的产品,部署在腾讯云上所以这里我们使用腾讯云的 CBS 做存储,腾讯自己有自己的开源 CSI 插件来对接 CBS

kubernetes-csi-tencentcloud

kubernetes-csi-tencentcloud 是腾讯云 Cloud Block Storage 服务的一个满足 CSI 标准实现的插件。这个插件可以让你在 Kubernetes 上使用 Cloud Block Storage。

特性

  • Static Provisioning - 为一个已有的CBS盘创建PV,并在容器中使用PVC来使用它
  • Dynamic Provisioning - 在容器需要使用时,根据PVC去创建CBS盘
    • specify zone - 指定要在哪个zone创建CBS盘
      • allowedTopologies - topology key是topology.com.tencent.cloud.csi.cbs/zone.
      • diskZone in StorageClass.parameters - diskZone中配置的zone优先级最高. 之后才是allowedTopologies中的zone
    • Topology-Aware - pod被调度完以后,在相应node所在zone创建CBS盘. 如果同时diskZone已配置,优先diskZone
  • Volume Snapshot - 磁盘快照
  • Volume Resizing - 磁盘扩容
  • Volume Attach Limit - 单节点最大能attach的CBS盘数量.(每个节点最大可attach 20块CBS盘)

在 Kubernetes 上安装

注意:
在讲述前置要求之前,对于各组件设置参数启动项有些要注意的地方:

  • 有些feature gates在GA以后的版本不能再被显式设置,否则可能导致报错。实际上这些feature gates在beta版本开始则无需添加。下表整理了涉及到feature gates的beta版本的表格,在给kubelet、master/controllermanager、scheduler设置启动参数时,可以基于此来做取舍.(举例:KubeletPluginsWatcher在1.12及以上版本则无须添加)
特性 默认值 阶段 起始 直到
VolumeSnapshotDataSource true Beta 1.17 -
CSINodeInfo true Beta 1.14 1.16
CSIDriverRegistry true Beta 1.14 1.17
KubeletPluginsWatcher true Beta 1.12 1.12
VolumeScheduling true Beta 1.10 1.12
ExpandCSIVolumes true Beta 1.16 -

前置要求:

  • Kubernetes v1.13.x及以上
  • kube-apiserver 和 kubelet 的 --allow-privileged flag 都要设置为 true (针对 v1.15.x 及以上版本, kubelet 默认设置 --allow-privileged 为 true,如果仍然显式设置,则会报错 )
  • 所有节点的 kubelet 需要添加的启动项为: --feature-gates=VolumeSnapshotDataSource=true,CSINodeInfo=true,CSIDriverRegistry=true,KubeletPluginsWatcher=true
  • apiserver/controller-manager: --feature-gates=VolumeSnapshotDataSource=true,CSINodeInfo=true,CSIDriverRegistry=true
  • scheduler: --feature-gates=VolumeSnapshotDataSource=true,CSINodeInfo=true,CSIDriverRegistry=true,VolumeScheduling=true

Clone 仓库

注: kubernetes-csi-tencentcloud中包括 CBS CSI, CFS CSI 与 COSFS CSI。这里我就只用CBS块存储了。其他两个也用过,感觉用起来还是不太适合。

1
git clone https://github.com/TencentCloud/kubernetes-csi-tencentcloud.git

使用腾讯云 API Credential 创建 kubernetes secret:

注: 如果是自建集群,必须创建;而如果是TKE集群环境,可以不创建该secret,driver中默认会根据TKE_QCSRole获取临时秘钥。

1
2
3
4
5
6
7
8
9
10
11
#  参考示例 deploy/kubernetes/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: cbs-csi-api-key
namespace: kube-system
data:
# 需要注意的是,secret 的 value 需要进行 base64 编码
# echo -n "<SECRET_ID>" | base64
TENCENTCLOUD_CBS_API_SECRET_ID: "<SECRET_ID>"
TENCENTCLOUD_CBS_API_SECRET_KEY: "<SECRET_KEY>"

创建rbac

创建attacher,provisioner,plugin需要的rbac:

1
2
kubectl apply -f  deploy/cbs/kubernetes/csi-controller-rbac.yaml
kubectl apply -f deploy/cbs/kubernetes/csi-node-rbac.yaml

创建controller,node和plugin

Kubernetes v1.18.x及以上版本创建controller plugin和node plugin

1
2
3
kubectl apply -f  deploy/cbs/kubernetes/csi-controller-new.yaml
kubectl apply -f deploy/cbs/kubernetes/csi-node-new.yaml
kubectl apply -f deploy/cbs/kubernetes/snapshot-crd.yaml

Kubernetes v1.18.x以下版本创建controller plugin和node plugin

1
2
3
kubectl apply -f  deploy/cbs/kubernetes/csi-controller-old.yaml
kubectl apply -f deploy/cbs/kubernetes/csi-node-old.yaml
kubectl apply -f deploy/cbs/kubernetes/snapshot-crd.yaml

组件说明

CBS-CSI 组件在集群内部署后,包含以下组件:

  • DaemonSet:每个 Node 提供一个 DaemonSet,简称为 NodePlugin。由 CBS-CSI Driver 和 node-driver-registrar 两个容器组成,负责向节点注册 Driver,并提供挂载能力。
  • StatefulSet 和 Deployment:简称为 Controller。由 Driver 和多个 Sidecar(external-provisioner、external-attacher、external-resizer、external-snapshotter、snapshot-controller)一起构成,提供创删卷、attach、detach、扩容、快照等能力。

简单测试验证

1
2
3
4
5
6
# 创建storageclass
kubectl apply -f deploy/examples/storageclass-basic.yaml
# 创建pvc
kubectl apply -f deploy/examples/pvc.yaml
# 创建申请pvc的pod
kubectl apply -f deploy/examples/app.yaml

StorageClass 支持的参数

Note:可以参考示例

  • 如果您集群中的节点存在多个可用区,那么您可以开启cbs存储卷的拓扑感知调度,需要在storageclass中添加volumeBindingMode: WaitForFirstConsumer,如deploy/examples/storageclass-topology.yaml,否则可能会出现cbs存储卷因跨可用区而挂载失败。
  • diskType: 代表要创建的 cbs 盘的类型;值为 CLOUD_PREMIUM 代表创建高性能云盘,值为 CLOUD_SSD 代表创建 ssd 云盘,值为 CLOUD_HSSD 代表创建增强型SSD云盘,
  • diskChargeType: 代表云盘的付费类型;值为 PREPAID 代表预付费,值为 POSTPAID_BY_HOUR 代表按量付费,需要注意的是,当值为 PREPAID 的时候需要指定额外的参数
  • diskChargeTypePrepaidPeriod:代表购买云盘的时长,当付费类型为 PREPAID 时需要指定,可选的值包括 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 24, 36,单位为月
  • diskChargePrepaidRenewFlag: 代表云盘的自动续费策略,当付费类型为 PREPAID 时需要指定,值为NOTIFY_AND_AUTO_RENEW 代表通知过期且自动续费,值为 NOTIFY_AND_MANUAL_RENEW 代表通知过期不自动续费,值为 DISABLE_NOTIFY_AND_MANUAL_RENEW 代表不通知过期不自动续费
  • encrypt: 代表云盘是否加密,当指定此参数时,唯一可选的值为 ENCRYPT
  • disktags: 可以给云盘加tag。形式如 a:b,c:d
  • throughputperformance: 对hssd/tssd盘,如果需要达到最大性能,可以填入额外性能。具体取值参见https://cloud.tencent.com/document/product/362/51896
  • cdcid: 独占集群ID

不同类型云盘的大小限制

云盘大小仅支持 10 的倍数(如: 100, 110, 120)

  • 高性能云硬盘提供最小 10 GB 到最大 32000 GB 的规格选择。
  • SSD云硬盘提供最小 20 GB 到最大 32000 GB 的规格选择,单块 SSD 云硬盘最高可提供 26000 随机读写IOPS、260MB/s吞吐量的存储性能。
  • 增强型SSD云硬盘提供最小 20 GB 到最大 32000 GB 的规格选择,单盘最高可提供 100000 随机读写IOPS、1000MB/s吞吐量的存储性能。

通过 CBS-CSI 避免云硬盘跨可用区挂载

操作场景

云硬盘不支持跨可用区挂载到节点,在跨可用区的集群环境中,推荐通过 CBS-CSI 拓扑感知特性来避免跨可用区挂载问题。

实现原理

拓扑感知调度需要多个 Kubernetes 组件配合完成,包括 Scheduler、PV controller、external-provisioner。具体流程如下:

  1. PV controller 观察 PVC 对象,检查 Storageclass 的 VolumeBindingMode 是否为 WaitForFirstConsumer,如是,则不会立即处理该 PVC 的创建事件,等待 Scheduler 处理。
  2. Scheduler 调度 Pod 后,会将 nodeName 以 annotation 的方式加入到 PVC 对象上 volume.kubernetes.io/selected-node: 10.0.0.72
  3. PV controller 获取到 PVC 对象的更新事件后,将开始处理 annotation(volume.kubernetes.io/selected-node),根据 nodeName 获取 Node 对象,传入到 external-provisioner 中。
  4. external-provisioner 根据传过来的 Node 对象的 label 获取可用区(failure-domain.beta.kubernetes.io/zone)后在对应可用区创建 PV,达到和 Pod 相同可用区的效果,避免云硬盘和 Node 在不同可用区而无法挂载问题。

前提条件

  • 已安装1.14或以上版本的 TKE 集群
  • 已将 CBS-CSI 或 In-Tree 组件更新为最新版本。

操作步骤

使用以下 YAML,在 Storageclass 中设置 volumeBindingMode 为 WaitForFirstConsumer。示例如下:

1
2
3
4
5
6
7
8
kind: StorageClass
metadata:
name: cbs-topo
parameters:
type: cbs
provisioner: com.tencent.cloud.csi.cbs
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

CBS-CSI 和 In-Tree 组件均支持该操作。

在线扩容云硬盘

操作场景

TKE 支持在线扩容 PV、对应的云硬盘及文件系统,即不需要重启 Pod 即可完成扩容。为确保文件系统的稳定性,建议在云硬盘文件系统处于未挂载状态时进行操作。

前提条件

操作步骤

创建允许扩容的 StorageClass

使用以下 YAML 创建允许扩容的 StorageClass,在 Storageclass 中设置 allowVolumeExpansiontrue。示例如下:

1
2
3
4
5
6
7
8
9
10
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: cbs-csi-expand
parameters:
diskType: CLOUD_PREMIUM
provisioner: com.tencent.cloud.csi.cbs
reclaimPolicy: Delete
volumeBindingMode: Immediate

在线扩容

提供以下两种扩容方式:

扩容方式 说明
重启 Pod 的情况下在线扩容 待扩容的云硬盘文件系统未被挂载,能够避免扩容出错以及方式2存在的问题。推荐使用该方式进行扩容
不重启 Pod 的情况下在线扩容 在节点上挂载着待扩容的云硬盘文件系统,如果存在 I/O 进程,将可能出现文件系统扩容错误。

重启Pod情况下在线扩容

1.执行以下命令,确认扩容前 PV 和文件系统状态。示例如下,PV 和文件系统大小均为30G:

1
2
3
4
5
6
7
$ kubectl exec ivantestweb-0 df /usr/share/nginx/html
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/vdd 30832548 44992 30771172 1% /usr/share/nginx/html

$ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 30Gi RWO Delete Bound default/www1-ivantestweb-0 cbs-csi 20h

2.执行以下命令,为 PV 对象打上一个非法 zone 标签,旨在下一步重启 Pod 后,使 Pod 无法调度到某个节点上。示例如下:

1
$ kubectl label pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c failure-domain.beta.kubernetes.io/zone=nozone

3.执行以下命令重启 Pod,重启后由于 Pod 对应的 PV 的标签表明的是非法 zone,Pod 将处于 Pending 状态。示例如下:

1
2
3
4
5
6
7
8
9
10
11
$ kubectl delete pod ivantestweb-0

$ kubectl get pod ivantestweb-0
NAME READY STATUS RESTARTS AGE
ivantestweb-0 0/1 Pending 0 25s

$ kubectl describe pod ivantestweb-0
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 40s (x3 over 2m3s) default-scheduler 0/1 nodes are available: 1 node(s) had no available volume zone.

4.执行以下命令,修改 PVC 对象中的容量,将容量扩容至40G。示例如下:

1
kubectl patch pvc www1-ivantestweb-0 -p '{"spec":{"resources":{"requests":{"storage":"40Gi"}}}}'

注意:扩容后的PVC对象容量的大小必须为10的倍数,不同云硬盘类型所支持的存储容量规格可参考说明 创建云硬盘

5.执行以下命令,去除 PV 对象之前打上的标签, 标签去除之后 Pod 即可调度成功。示例如下:

1
2
$ kubectl label pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c failure-domain.beta.kubernetes.io/zone-
persistentvolume/pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c labeled

6.执行以下命令,可以查看到 Pod 状态为 Running、对应的 PV 和文件系统扩容成功,从30G扩容到40G。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ kubectl get pod ivantestweb-0
NAME READY STATUS RESTARTS AGE
ivantestweb-0 1/1 Running 0 17m

$ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 40Gi RWO Delete Bound default/www1-ivantestweb-0 cbs-csi 20h

$ kubectl get pvc www1-ivantestweb-0
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www1-ivantestweb-0 Bound pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 40Gi RWO cbs-csi 20h

$ kubectl exec ivantestweb-0 df /usr/share/nginx/html
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/vdd 41153760 49032 41088344 1% /usr/share/nginx/html

不重启Pod情况下在线扩容

1.执行以下命令,确认扩容前 PV 和文件系统状态。示例如下,PV 和文件系统大小均为20G:

1
2
3
4
5
6
7
$ kubectl exec ivantestweb-0 df /usr/share/nginx/html
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/vdd 20511312 45036 20449892 1% /usr/share/nginx/html

$ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 20Gi RWO Delete Bound default/www1-ivantestweb-0 cbs-csi 20h

2.执行以下命令,修改 PVC 对象中的容量,将容量扩容至30G。示例如下:

1
$ kubectl patch pvc www1-ivantestweb-0 -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}'

扩容后的PVC对象容量的大小必须为10的倍数,不同硬盘类型所支持的存储容量规格可参考说明 创建云硬盘

3.执行以下命令,可以查看到 PV 和文件系统已扩容至30G。示例如下:

1
2
3
4
5
6
7
$ kubectl exec ivantestweb-0 df /usr/share/nginx/html
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/vdd 30832548 44992 30771172 1% /usr/share/nginx/html

$ kubectl get pv pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-e193201e-6f6d-48cf-b96d-ccc09225cf9c 30Gi RWO Delete Bound default/www1-ivantestweb-0 cbs-csi 20h

Kuberentes集群添加腾讯云CBS为默认存储
https://system51.github.io/2022/05/10/kubernetes-csi-tencentcloud/
作者
Mr.Ye
发布于
2022年5月10日
许可协议