数据卷扩容
使用云盘存储卷, 往往在服务初始化的时候申请了一个适当容量的云盘, 但是随着数据的增长, 数据盘的容量不能满足需求, 需要扩容.
传统应用的扩容场景中, 往往是先手动停掉应用, 再对数据盘进行备份, 然后执行扩容操作, 最后重新启动应用.
Kubernetes 本身是一个自动化调度, 编排系统, 实现了对数据卷的生命周期管理. 最新版本中已经提供对数据卷扩容的功能; 下面是一些介绍:
https://kubernetes.io/blog/2018/08/02/dynamically-expand-volume-with-csi-and-kubernetes/
数据卷扩容目前支持以下类型:
- gcePersistentDisk
- awsElasticBlockStore
- OpenStack Cinder
- glusterfs
- rbd
- csi
CSI 数据卷扩容目前属于 Alpha 阶段(1.14), 需要开启 Feature Gates 才可以使用;
ExpandCSIVolumes=true
注: 数据卷扩容只支持通过 storageclass 创建的动态 pv, 静态 pv 不能实现扩容;
实现原理
Resizer 架构上分为 controller 部分 和 node 部分, 实现过程也分 2 个阶段:
阶段 1:Controller 部分实现云盘扩容
这个阶段由 csi-resizer 实现完成, 在 controller 中通过云盘 API 调用实现扩容.
下面逻辑决定是否扩容:
resizer watch pvc, 判断 pvc 是否需要 resize:
比较 pvc 现在和之前的值, 当 pvc 值变大时;
比较 pvc 和 volume 的值, 当 pvc 值大于 pv 值时;
扩容是通过 resizeVolume 函数实现的, 过程:
对需要扩容的 pvc, 配置 pvc 状态为 resizing;
调用 csi-plugin 中 ControllerExpandVolume 函数, 调用云盘 API 实现云盘扩容;
更新 pv 对象的 size,size 变成扩容后大小;
如果需要文件系统扩容, 更新 pvc 状态为: FileSystemResizePending, 等待 node 部分进行文件系统扩容;
此时 pvc 的 conditions 字段变为:
- conditions:
- - lastProbeTime: null
- lastTransitionTime: "2019-07-23T12:44:34Z"
- message: Waiting for user to (re-)start a pod to finish file system resize of volume on node.
- status: "True"
- type: FileSystemResizePending
阶段 2:Node 部分实现文件系统扩容
kubelet 一直 watch pvc, 执行逻辑如下:
云盘 attach 后, 执行 MountDevice; 编辑 pv 为已挂载: MarkDeviceAsMounted;
然后调用 resizeFileSystem 函数 (通过 RequiresFSResize() 方法判断是否进行文件系统扩容)
调用 CSI 的 NodeExpand 接口, 进而调用 CSI Plugin 的 NodeExpandVolume, 实现文件系统扩容;
更新 pvc 的 size 大小, 并更新 pvc 的 FileSystemResizePending 状态;
ACK 中云盘扩容实践
为了确保数据的一致性, 在执行扩容操作前, 请对云盘进行打快照保护;
1. 依赖准备
申请 1.14 版本阿里云 Kubernetes 集群;
kubelet 中配置 feature gates:--feature-gates=ExpandCSIVolumes=true
安装部署 csi-plugin, 模板: https://github.com/AliyunContainerService/csi-plugin/tree/master/deploy/ack
csi-plugin 需要更新到最新版本, 支持 NodeExpandVolume;
2. resizer 插件部署:
resizer 插件部署为 statefulset 应用, 默认跑在 master 上; 配置优先级, 保证 pod 可以优先启动;
resizer 和 csi-plugin 通过 socket 通信, 只负责 phase1 的云盘扩容工作;
- kind: Service
- apiVersion: v1
- metadata:
- name: csi-resizer
- namespace: kube-system
- labels:
- App: csi-resizer
- spec:
- selector:
- App: csi-resizer
- ports:
- - name: dummy
- port: 12345
- ---
- kind: StatefulSet
- apiVersion: apps/v1beta1
- metadata:
- name: csi-resizer
- namespace: kube-system
- spec:
- serviceName: "csi-resizer"
- template:
- metadata:
- labels:
- App: csi-resizer
- spec:
- tolerations:
- - operator: "Exists"
- nodeSelector:
- node-role.kubernetes.io/master: ""
- priorityClassName: system-node-critical
- serviceAccount: admin
- hostNetwork: true
- containers:
- - name: csi-resizer
- image: registry.cn-hangzhou.aliyuncs.com/acs/csi-resizer:v0.1.0
- args:
- - "--v=5"
- - "--csi-address=$(ADDRESS)"
- - "--leader-election"
- env:
- - name: ADDRESS
- value: /socketDir/csi.sock
- imagePullPolicy: "Always"
- volumeMounts:
- - name: socket-dir
- mountPath: /socketDir/
- - name: csi-diskplugin
- securityContext:
- privileged: true
- capabilities:
- add: ["SYS_ADMIN"]
- allowPrivilegeEscalation: true
- image: registry.cn-hangzhou.aliyuncs.com/plugins/csi-plugin:v1.13.2-f21f9ba2
- imagePullPolicy: "Always"
- args:
- - "--endpoint=$(CSI_ENDPOINT)"
- - "--v=5"
- - "--driver=diskplugin.csi.alibabacloud.com"
- env:
- - name: CSI_ENDPOINT
- value: unix://socketDir/csi.sock
- - name: ACCESS_KEY_ID
- value: ""
- - name: ACCESS_KEY_SECRET
- value: ""
- volumeMounts:
- - mountPath: /var/log/
- name: host-log
- - mountPath: /socketDir/
- name: socket-dir
- - name: etc
- mountPath: /host/etc
- volumes:
- - name: socket-dir
- emptyDir: {}
- - name: host-log
- hostPath:
- path: /var/log/
- - name: etc
- hostPath:
- path: /etc
- updateStrategy:
- type: RollingUpdate
3. 创建云盘应用
创建 storageclass,allowVolumeExpansion 配置为 true;
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: alicloud-disk-expand
- provisioner: diskplugin.csi.alibabacloud.com
- parameters:
- type: cloud_efficiency
- reclaimPolicy: Retain
- allowVolumeExpansion: true
创建 pvc, 云盘大小为 20G, 动态生成 pv:
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: pvc-disk
- spec:
- accessModes:
- - ReadWriteOnce
- resources:
- requests:
- storage: 20Gi
- storageClassName: alicloud-disk-expand
- # kubectl get pvc
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- pvc-disk Bound pvc-4bf230a9-adc6-11e9-ae51-00163e105050 20Gi RWO alicloud-disk-expand 8s
- # kubectl get pv
- NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
- pvc-4bf230a9-adc6-11e9-ae51-00163e105050 20Gi RWO Retain Bound default/pvc-disk alicloud-disk-expand 3s
创建应用, 挂载上面的云盘卷:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: dynamic-create
- labels:
- App: nginx
- spec:
- selector:
- matchLabels:
- App: nginx
- template:
- metadata:
- labels:
- App: nginx
- spec:
- containers:
- - name: nginx
- image: nginx:1.7.9
- ports:
- - containerPort: 80
- volumeMounts:
- - name: disk-pvc
- mountPath: "/data"
- volumes:
- - name: disk-pvc
- persistentVolumeClaim:
- claimName: pvc-disk
云盘块设备为:/dev/vdd, 大小 20G, 挂载容器内 / data 目录;
- # kubectl exec dynamic-create-857bd875b5-6rmzn df | grep data
- /dev/vdd 20511312 45080 20449848 1% /data
- # kubectl exec dynamic-create-857bd875b5-6rmzn ls /data
- lost+found
创建测试数据:
- # kubectl exec dynamic-create-857bd875b5-6rmzn touch /data/test
- # kubectl exec dynamic-create-857bd875b5-6rmzn ls /data
- lost+found test
4. 执行云盘扩容
更新 pvc 大小, 会驱动 resizer 调用云盘 API 进行扩容, 控制台可以检查云盘已经变成了 30G, 且 pv 的 size 也更新到 30G;
更新 pvc 的 size:
- # kubectl patch pvc pvc-disk -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}'
- # kubectl get pvc
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- pvc-disk Bound pvc-4bf230a9-adc6-11e9-ae51-00163e105050 20Gi RWO alicloud-disk-expand 7m57s
- # kubectl get pv
- NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
- pvc-4bf230a9-adc6-11e9-ae51-00163e105050 30Gi RWO Retain Bound default/pvc-disk alicloud-disk-expand 8m22s
此时 pod 内文件系统还是 20G:
- # kubectl exec dynamic-create-857bd875b5-6rmzn df | grep data
- /dev/vdd 20511312 45080 20449848 1% /data
上面更新了云盘存储的大小, 但是文件系统并没有更新, 即扩容空间在 pod 中还不能使用.
重启 pod, 触发调用 nodeExpand 方法进行文件系统扩容:
- # kubectl delete pod dynamic-create-857bd875b5-6rmzn
- pod "dynamic-create-857bd875b5-6rmzn" deleted
- # kubectl get pvc
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- pvc-disk Bound pvc-4bf230a9-adc6-11e9-ae51-00163e105050 30Gi RWO alicloud-disk-expand 18m
- # kubectl get pv
- NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
- pvc-4bf230a9-adc6-11e9-ae51-00163e105050 30Gi RWO Retain Bound default/pvc-disk alicloud-disk-expand 18m
- # kubectl get pod
- NAME READY STATUS RESTARTS AGE
- dynamic-create-857bd875b5-9fmcs 1/1 Running 0 62s
- # kubectl exec dynamic-create-857bd875b5-9fmcs df | grep data
- /dev/vdc 30832548 45036 30771128 1% /data
- # kubectl exec dynamic-create-857bd875b5-9fmcs ls /data
- lost+found test
pvc 的大小更新为 30G, 且 pod 中文件系统的大小也扩容到 30G, 并保持数据的完整性;
CSI 开发交流群
2.PNG
来源: http://www.jianshu.com/p/00dc43639bde