1.Local Persistent Volume

Local Persistent Volume是Kubernetes在v1.10推出的功能(后面简称local pv),用于解决用户使用host-path映射本地目录时存在的以下问题:

  • 提供一种使用本地存储的PV,使没有存储系统的K8S集群可以正常部署那些使用PVC的应用(比如一些开源的Helm Chart)
  • 解决host-path在使用过程中的调度问题,即re-schedule的情况下,local pv保证pod依然能再次调度到相同的节点

通过以下步骤使用local pv:

  • 创建Storage Class
1
2
3
4
5
6
7
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
# WaitForFirstConsumer表示k8s调度时,会考虑pod和pv/pvc之间的约束关系,保证pod运行在local pv所在节点。
volumeBindingMode: WaitForFirstConsumer

虽然local pv不支持动态provisioner,但依然需要创建一个StorageClass,并且指定volumeBindingMode为WaitForFirstConsumer。

  • 创建PV
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  # Filesystem/Block
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  # Retain/Recycle/Delete 
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    # 指定读写目录
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - node1

上述定义中,nodeAffinity则限制了pv所在的节点,定义时要保证key/values的唯一。

local pv支持向文件挂载块设备,可以将dev等直接挂载到pod中,kubelet在mount前自动格式化块设备

  • 创建PVC,Kubernetes会自动binding满足条件的PVC/PV,存在多个候选的PV时Kubernetes优先绑定capacity.storage最小的。

使用local pv时,需要手工创建volume path并且定义pv,社区出现了一些external-provisioner来简化这些操作。

比较典型的包括:

1.local-static-provisioner

local-static-provisioner是kubernetes官方维护的项目,帮助用户在使用local pv时"自动"创建pv。 使用local-static-provisioner时,用户无需手工定义/安装pv,只需在discovering directory目录中进行mount操作(mount目录或者设备均可),local-static-provisioner会自动为每个挂载点创建pv。

local-static-provisioner项目在 helm/provisioner 目录下提供了helm chart,用户可以快速部署。

local-static-provisioner 回收PV的逻辑:如果配置回收策略为Delete,用户删除PV时,其状态为Released。此时数据目录下的内容会被删除,PV重新变为Available状态。

假如用户在每个节点上需要的pv是固定的,那么可以通过initContainer中配置初始化脚本来完成初始化:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
initContainers:
  - name: "init-pv"
    securityContext:
      privileged: true
    image: { { .Values.database.internal.image.repository } }:{{ .Values.database.internal.image.tag }}
    imagePullPolicy: { { .Values.imagePullPolicy } }
    command: [ "mount" ]
    # 创建 /mnt/fask-disks/pv1 作为 pv 目录
    args: [ "--bind", "/mnt/fask-disks/pv1","/mnt/fask-disks/pv1" ]
    volumeMounts:
      - name: discovering-directory
        # local-static-provisioner的discovering目录
        mountPath: /mnt/fask-disks
        # 通过该配置将mount传播回host和其他容器
        mountPropagation: Bidirectional

2.local-path-provisioner

local-path-provisioner 是Rancher集成在K3S中的一个小工具,用于在kubernetes节点中自动创建local PV。 local-path-provisioner相比local-static-provisioner做到了完全自动化,当用户创建对应PVC时会自动在该目录下创建子目录作为PV Volume,无需用户干预。

local-path-provisioner通过监听K8S中的PVC请求,在指定节点创建Helper Pod。Helper Pod挂载对应节点的目录,创建子目录作为Volume或者删除对应Volume中的数据。 当Helper Pod正常结束时,local-path-provisioner的控制器将创建/删除PV。

local-path-provisioner 提供以下能力:

  • 自动创建/删除PV的数据目录
  • 指定数据目录(PS:PV中的数据实际存放在对应的子目录,子目录的名称是随机的)
  • 指定Helper Pod的脚本(setup/teardown)

附录:XFS QUOTA

上述方案中,都不支持对Local PV进行容量限制。

用户可以通过XFS QUOTA在系统盘上创建对应的目录限制。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 挂载/dev/sdb,并且打开prjquota功能
mount -o prjquota /dev/sdb /data

# 查看挂载点的quota能力是否开启
xfs_quota -x -c "state"

# 创建/data/1GB,在该目录上进心存储空间的限制
mkdir /data/1GB

# 创建project对应的id为333,目录为/data/1GB
xfs_quota -x -c "project -s -p /data/1GB 333"

# 限制目录的存储空间为1024m
xfs_quota -x -c "limit -p bhard=1024m 333" /data

# 打印/data挂载点下的所有quota
xfs_quota -x -c "report -pbh" /data

# 测试写入2GB数据
dd if=/dev/zero of=/data/1GB/test bs=1M count=2048

# 查看挂载点上quota空间的使用情况
xfs_quota -x -c "quota  -p 333" /data

# 清理quota,PS: 清理命令有点问题???
xfs_quota -x -c "disable -pv" /data
xfs_quota -x -c "remove  -pv" /data
xfs_quota -x -c "enable  -pv" /data

参考:https://www.ichenfu.com/2017/02/20/xfs-per-directory-quota/

参考