数据卷扩容
使用云盘存储卷,往往在服务初始化的时候申请了一个适当容量的云盘,但是随着数据的增长,数据盘的容量不能满足需求,需要扩容。
传统应用的扩容场景中,往往是先手动停掉应用,再对数据盘进行备份,然后执行扩容操作,最后重新启动应用。
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,并保持数据的完整性;