您可以在本地盘上通过VolumeGroup进行磁盘虚拟化,并通过LVM数据卷切分磁盘给应用使用。本文介绍如何使用LVM数据卷。

背景信息

使用HostPath和LocalVolume都可以实现Pod对主机存储空间的访问,但均具有其局限性:
  • Kubernetes没有提供上述本地存储卷的生命周期管理能力,需要管理员手动管理、运维存储卷。
  • 多个Pod共享一个本地存储的时候,需要共享存储目录或者分别使用其子目录,无法做到容量隔离。
  • 多个Pod共享一个本地存储的时候,IOPS、吞吐等指标共享了整个存储空间,无法进行限制。
  • 新建Pod使用本地存储时,不知道各个节点存储空间余量,不能进行合理的存储卷调度。

为此ACK提供了LVM数据卷方案,以解决上述问题。

功能介绍

  • LVM数据卷生命周期管理:卷自动创建、删除、挂载、卸载。
  • LVM数据卷扩容功能。
  • LVM卷的监控能力。
  • LVM卷的IOPS限制。
  • 节点本地存储管理:自动运维VolumeGroup。
  • LVM卷的集群容量感知能力。

注意事项

  • LVM为本地存储类型,不适用于高可用数据场景。
  • VolumeGroup运维、本地存储容量感知为可选项(暂缓提供)。

插件部署

LVM CSI插件分为2个组件:Plugin(负责挂载、卸载LVM卷)和Provisioner(负责创建LVM卷和PV对象)。

apiVersion: storage.k8s.io/v1beta1
kind: CSIDriver
metadata:
  name: localplugin.csi.alibabacloud.com
spec:
  attachRequired: false
  podInfoOnMount: true
---
kind: DaemonSet
apiVersion: apps/v1
metadata:
  name: csi-local-plugin
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: csi-local-plugin
  template:
    metadata:
      labels:
        app: csi-local-plugin
    spec:
      tolerations:
        - operator: Exists
      serviceAccount: admin
      priorityClassName: system-node-critical
      hostNetwork: true
      hostPID: true
      containers:
        - name: driver-registrar
          image: registry.cn-hangzhou.aliyuncs.com/acs/csi-node-driver-registrar:v1.1.0
          imagePullPolicy: Always
          args:
            - "--v=5"
            - "--csi-address=/csi/csi.sock"
            - "--kubelet-registration-path=/var/lib/kubelet/csi-plugins/localplugin.csi.alibabacloud.com/csi.sock"
          env:
            - name: KUBE_NODE_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: spec.nodeName
          volumeMounts:
            - name: plugin-dir
              mountPath: /csi
            - name: registration-dir
              mountPath: /registration

        - name: csi-localplugin
          securityContext:
            privileged: true
            capabilities:
              add: ["SYS_ADMIN"]
            allowPrivilegeEscalation: true
          image: registry.cn-hangzhou.aliyuncs.com/acs/csi-plugin:v1.14.8.41-bce68b74-aliyun
          imagePullPolicy: "Always"
          args :
            - "--endpoint=$(CSI_ENDPOINT)"
            - "--v=5"
            - "--nodeid=$(KUBE_NODE_NAME)"
            - "--driver=localplugin.csi.alibabacloud.com"
          env:
            - name: KUBE_NODE_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: spec.nodeName
            - name: DRIVER_VENDOR
              value: localplugin.csi.alibabacloud.com
            - name: CSI_ENDPOINT
              value: unix://var/lib/kubelet/csi-plugins/localplugin.csi.alibabacloud.com/csi.sock
          volumeMounts:
            - name: pods-mount-dir
              mountPath: /var/lib/kubelet
              mountPropagation: "Bidirectional"
            - mountPath: /dev
              mountPropagation: "HostToContainer"
              name: host-dev
            - mountPath: /var/log/
              name: host-log
      volumes:
        - name: plugin-dir
          hostPath:
            path: /var/lib/kubelet/csi-plugins/localplugin.csi.alibabacloud.com
            type: DirectoryOrCreate
        - name: registration-dir
          hostPath:
            path: /var/lib/kubelet/plugins_registry
            type: DirectoryOrCreate
        - name: pods-mount-dir
          hostPath:
            path: /var/lib/kubelet
            type: Directory
        - name: host-dev
          hostPath:
            path: /dev
        - name: host-log
          hostPath:
            path: /var/log/
  updateStrategy:
    rollingUpdate:
      maxUnavailable: 10%
    type: RollingUpdate

kind: Deployment
apiVersion: apps/v1
metadata:
  name: csi-local-provisioner
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: csi-local-provisioner
  replicas: 2
  template:
    metadata:
      labels:
        app: csi-local-provisioner
    spec:
      tolerations:
      - operator: "Exists"
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: node-role.kubernetes.io/master
                operator: Exists
      priorityClassName: system-node-critical
      serviceAccount: admin
      hostNetwork: true
      containers:
        - name: external-local-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/acs/csi-provisioner:v1.6.0-b6f763a43-ack
          args:
            - "--csi-address=$(ADDRESS)"
            - "--feature-gates=Topology=True"
            - "--volume-name-prefix=lvm"
            - "--strict-topology=true"
            - "--timeout=150s"
            - "--extra-create-metadata=true"
            - "--enable-leader-election=true"
            - "--leader-election-type=leases"
            - "--retry-interval-start=500ms"
            - "--v=5"
          env:
            - name: ADDRESS
              value: /socketDir/csi.sock
          imagePullPolicy: "Always"
          volumeMounts:
            - name: socket-dir
              mountPath: /socketDir
        - name: external-local-resizer
          image: registry.cn-hangzhou.aliyuncs.com/acs/csi-resizer:v0.3.0
          args:
            - "--v=5"
            - "--csi-address=$(ADDRESS)"
            - "--leader-election"
          env:
            - name: ADDRESS
              value: /socketDir/csi.sock
          imagePullPolicy: "Always"
          volumeMounts:
            - name: socket-dir
              mountPath: /socketDir/
      volumes:
        - name: socket-dir
          hostPath:
            path: /var/lib/kubelet/csi-plugins/localplugin.csi.alibabacloud.com
            type: DirectoryOrCreate

使用LVM数据卷示例

使用CSI-Provisioner自动创建PV,有以下特点:
  • StorageClass中需要指定VolumeGroup名字。
  • 如果期望创建的PV在某个节点,需要给PVC添加Label:volume.kubernetes.io/selected-node: nodeName
  1. 使用以下模板创建StorageClass。
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
        name: csi-local
    provisioner: localplugin.csi.alibabacloud.com
    parameters:
        volumeType: LVM
        vgName: volumegroup1
        fsType: ext4
        lvmType: "striping"
    reclaimPolicy: Delete
    volumeBindingMode: WaitForFirstConsumer
    allowVolumeExpansion: true
    参数 描述
    volumeType 表示本地存储类型为LVM(后续将支持其他类型本地存储)。
    vgName 必选,VolumeGroup的名字。
    lvmType 生成的LVM类型,支持linear(线性)、striping(条带化)。
    fsType 格式文件系统类型。
  2. 使用以下模板创建PVC。
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: lvm-pvc
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 2Gi
      storageClassName: csi-local
  3. 使用以下模板创建应用。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deployment-lvm
      labels:
        app: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.7.9
            volumeMounts:
              - name: lvm-pvc
                mountPath: "/data"
          volumes:
            - name: lvm-pvc
              persistentVolumeClaim:
                claimName: lvm-pvc
  4. 查看应用状态。
    执行以下命令查看Pod信息。
    kubectl get pod
    返回结果如下:
    NAME                             READY   STATUS    RESTARTS   AGE
    deployment-lvm-9f798687c-mqfht   1/1     Running   0          9s
    执行以下命令查看PVC信息。
    kubectl get pvc
    返回结果如下:
    NAME      STATUS   VOLUME                                      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    lvm-pvc   Bound    disk-afacf7a9-3d1a-45da-b443-24f8fb3599c1   2Gi        RWO            csi-local      16s
    执行以下命令查看PV信息。
    kubectl get pv
    返回结果如下:
    NAME                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
    disk-afacf7a9-3d1a-45da-b443-24f8fb3599c1   2Gi        RWO            Delete           Bound    default/lvm-pvc   csi-local               12s
    执行以下命令查看Pod挂载详情。
    kubectl exec -ti deployment-lvm-9f798687c-mqfht sh df /data
    返回结果如下:
    Filesystem                                                              1K-blocks  Used Available Use% Mounted on
    /dev/mapper/volumegroup1-disk--afacf7a9--3d1a--45da--b443--24f8fb3599c1   1998672  6144   1976144   1% /data
    执行以下命令列出/data下的目录。
    ls /data
    返回结果如下:
    lost+found
    执行以下命令在/data下新增test目录并查看。
    touch /data/test
    ls /data
    返回结果如下:
    lost+found  test
    执行以下命令退出登录。
    exit
    执行以下命令删除Pod重建。
    kubectl delete pod deployment-lvm-9f798687c-mqfht
    返回结果如下:
    pod "deployment-lvm-9f798687c-mqfht" deleted
    执行以下命令查看Pod信息。
    kubectl get pod
    返回结果如下:
    NAME                             READY   STATUS    RESTARTS   AGE
    deployment-lvm-9f798687c-jsdnk   1/1     Running   0          2m19s
    执行以下命令查看Pod挂载详情。
    kubectl exec deployment-lvm-9f798687c-jsdnk ls /data
    返回结果如下:
    lost+found  
    test
  5. 扩容LVM卷。
    执行以下命令查看PVC信息。
    kubectl get pvc
    返回结果如下:
    NAME      STATUS   VOLUME                                      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    lvm-pvc   Bound    disk-afacf7a9-3d1a-45da-b443-24f8fb3599c1   2Gi        RWO            csi-local      6m50s
    执行以下命令将PVC扩容到4 G。
    kubectl patch pvc lvm-pvc -p '{"spec":{"resources":{"requests":{"storage":"4Gi"}}}}'
    返回结果如下:
    persistentvolumeclaim/lvm-pvc patched
    执行以下命令查看PVC信息。
    kubectl get pvc
    返回结果如下:
    NAME      STATUS   VOLUME                                      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    lvm-pvc   Bound    disk-afacf7a9-3d1a-45da-b443-24f8fb3599c1   4Gi        RWO            csi-local      7m26s
    执行以下命令查看LVM卷扩容到4 G。
    kubectl exec deployment-lvm-9f798687c-jsdnk df /data
    返回结果如下:
    Filesystem                                                              1K-blocks  Used Available Use% Mounted on
    /dev/mapper/volumegroup1-disk--afacf7a9--3d1a--45da--b443--24f8fb3599c1   4062912  8184   4038344   1% /data
  6. 执行以下命令监控LVM卷。
    curl -s localhost:10255/metrics | grep lvm-pvc
    返回结果如下:
    kubelet_volume_stats_available_bytes{namespace="default",persistentvolumeclaim="lvm-pvc"} 1.917165568e+09
    kubelet_volume_stats_capacity_bytes{namespace="default",persistentvolumeclaim="lvm-pvc"} 1.939816448e+09
    kubelet_volume_stats_inodes{namespace="default",persistentvolumeclaim="lvm-pvc"} 122400
    kubelet_volume_stats_inodes_free{namespace="default",persistentvolumeclaim="lvm-pvc"} 122389
    kubelet_volume_stats_inodes_used{namespace="default",persistentvolumeclaim="lvm-pvc"} 11
    kubelet_volume_stats_used_bytes{namespace="default",persistentvolumeclaim="lvm-pvc"} 5.873664e+06

    可以将上述监控数据接入Promethus并在前端展示。详情请参见开源Prometheus监控