Local Path: k8s 本地路径 volume

发布时间: 更新时间: 总字数:2576 阅读时间:6m 作者: IP上海 分享 网址

Local Path Provisioner 为 Kubernetes 用户提供了一种利用各个节点上本地存储的方法。根据用户配置,Local Path Provisioner 会在节点上自动创建基于 hostPathlocal 的持久卷(Persistent Volume)。

介绍

Local Path Provisioner 利用了 Kubernetes 的本地持久卷特性,但提供了一个比 Kubernetes 内置 local 卷特性更简单的解决方案。

优点

缺点

  • 目前不支持卷容量限制,容量限制现在会被忽略

安装部署

要求 Kubernetes v1.12+。

安装时,目录 /opt/local-path-provisioner 将在所有节点上用作供应路径(即存储持久卷数据的路径)。默认情况下,它将安装在 local-path-storage 命名空间中。

  • 稳定版

    kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.32/deploy/local-path-storage.yaml
    
  • 开发版

    kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
    

或者,使用 kustomize 进行部署。

  • 稳定版

    kustomize build "github.com/rancher/local-path-provisioner/deploy?ref=v0.0.32" | kubectl apply -f -
    
  • 开发版

    kustomize build "github.com/rancher/local-path-provisioner/deploy?ref=master" | kubectl apply -f -
    

安装后,您应该会看到类似下面的输出:

$ kubectl -n local-path-storage get pod
NAME                                     READY     STATUS    RESTARTS   AGE
local-path-provisioner-d744ccf98-xfcbk   1/1       Running   0          7m

使用以下命令检查日志:

kubectl -n local-path-storage logs -f -l app=local-path-provisioner

使用方法

创建一个使用 hostPath 后端的持久卷(Persistent Volume)和一个使用它的 Pod:

  • pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: local-path-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 128Mi
  • pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: volume-test
    image: nginx:stable-alpine
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: volv
      mountPath: /data
    ports:
    - containerPort: 80
  volumes:
  - name: volv
    persistentVolumeClaim:
      claimName: local-path-pvc
  • 应用
kubectl create -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/examples/pvc/pvc.yaml
kubectl create -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/examples/pod/pod.yaml

或者,使用 kustomize 来部署它们。

kustomize build "github.com/rancher/local-path-provisioner/examples/pod?ref=master" | kubectl apply -f -

您应该能看到 PV 已经被创建:

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                    STORAGECLASS   REASON    AGE
pvc-bc3117d9-c6d3-11e8-b36d-7a42907dda78   2Gi        RWO            Delete           Bound     default/local-path-pvc   local-path               4s

PVC 已经被绑定:

$ kubectl get pvc
NAME             STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
local-path-pvc   Bound     pvc-bc3117d9-c6d3-11e8-b36d-7a42907dda78   2Gi        RWO            local-path     16s

并且 Pod 开始运行:

$ kubectl get pod
NAME          READY     STATUS    RESTARTS   AGE
volume-test   1/1       Running   0          3s

向 Pod 中写入一些内容:

kubectl exec volume-test -- sh -c "echo local-path-test > /data/test"

现在使用以下命令删除 Pod:

kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/examples/pod/pod.yaml

确认 Pod 已被删除后,重新创建它:

kubectl create -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/examples/pod/pod.yaml

检查卷中的内容:

$ kubectl exec volume-test -- sh -c "cat /data/test"
local-path-test

删除 Pod 和 PVC:

kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/examples/pod/pod.yaml
kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/examples/pvc/pvc.yaml

或者,使用 kustomize 来删除它们。

kustomize build "github.com/rancher/local-path-provisioner/examples/pod?ref=master" | kubectl delete -f -

存储在节点上的卷内容将被自动清理。您可以查看 local-path-provisioner-xxx 的日志了解详情。

现在已经验证按预期工作。

相关配置

自定义 ConfigMap

相关配置包括一个 config.json 文件、一个 Pod 模板 helperPod.yaml 以及两个 bash 脚本 setupteardown,它们存储在一个 ConfigMap 中,例如:

kind: ConfigMap
apiVersion: v1
metadata:
  name: local-path-config
  namespace: local-path-storage
data:
  config.json: |-
        {
                "nodePathMap":[
                {
                        "node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
                        "paths":["/opt/local-path-provisioner"]
                },
                {
                        "node":"yasker-lp-dev1",
                        "paths":["/opt/local-path-provisioner", "/data1"]
                },
                {
                        "node":"yasker-lp-dev3",
                        "paths":[]
                }
                ]
        }
  setup: |-
        #!/bin/sh
        set -eu
        mkdir -m 0777 -p "$VOL_DIR"
  teardown: |-
        #!/bin/sh
        set -eu
        rm -rf "$VOL_DIR"
  helperPod.yaml: |-
        apiVersion: v1
        kind: Pod
        metadata:
          name: helper-pod
        spec:
          priorityClassName: system-node-critical
          tolerations:
            - key: node.kubernetes.io/disk-pressure
              operator: Exists
              effect: NoSchedule
          containers:
          - name: helper-pod
            image: busybox

helperPod 被允许在经历磁盘压力(disk pressure)状况的节点上运行,尽管可能存在资源限制。当它在此类节点上运行时,它可以执行特定的清理任务,释放 PVC 中的空间,并解决磁盘压力问题。

config.json

nodePathMap 是用户可以自定义在每个节点上存储数据位置的地方。

  1. 如果某个节点未在 nodePathMap 中列出,而 Kubernetes 要在该节点上创建卷,则会使用 DEFAULT_PATH_FOR_NON_LISTED_NODES 中指定的路径进行供应。
  2. 如果某个节点在 nodePathMap 中列出,则会使用 paths 中指定的路径进行供应。
    1. 如果某个节点被列出,但其 paths 设置为 [],则 local path 将拒绝在该节点上供应卷。
    2. 如果指定了多个路径,则在供应时会随机选择一个路径。

sharedFileSystemPath 允许 local path 使用一个同时挂载在所有节点上的文件系统。在这种情况下,支持所有访问模式:ReadWriteOnceReadOnlyManyReadWriteMany

storageClassConfigs 是一个从存储类(storage class)名称到包含 nodePathMapsharedFilesystemPath 对象的映射,如上所述。

此外,可以在 StorageClass 定义中使用 volumeBindingMode: Immediate

请注意,nodePathMapsharedFileSystemPathstorageClassConfigs 是互斥的。如果使用了 sharedFileSystemPathstorageClassConfigs,则 nodePathMap 必须设置为空数组 []

setupCommandteardownCommand 允许您指定 helperPod 中二进制文件的路径,这些文件将分别在创建或删除 PVC 时被调用。如果您出于安全原因需要使用 distroless 镜像,这会很有用。请参阅 examples/distroless 目录中的示例。二进制文件可以接受以下参数:

参数 描述
-p 应该被创建或移除的卷目录。
-m PersistentVolume 的模式(BlockFilesystem)。
-s 请求的卷大小(以字节为单位)。
-a 操作类型,可以是 createdelete

setupCommandteardownCommand 的优先级高于 ConfigMap 中的 setupteardown 脚本。

  • 配置必须遵守以下规则:
  1. config.json 必须是有效的 JSON 文件。
  2. 路径必须以 / 开头,即为绝对路径。
  3. 禁止使用根目录(/)。
  4. 单个节点不允许有重复的路径。
  5. 不允许有重复的节点。

setupteardown 脚本以及 helperPod.yaml 模板

  • setup 脚本在创建卷之前运行,用于在节点上准备卷目录。
  • teardown 脚本在删除卷之后运行,用于清理节点上的卷目录。
  • helperPod.yaml 模板用于创建一个运行 setupteardown 脚本的辅助 Pod (helper Pod)。

这些脚本通过环境变量接收输入:

环境变量 描述
VOL_DIR 应该被创建或移除的卷目录。
VOL_MODE PersistentVolume 的模式(BlockFilesystem)。
VOL_SIZE_BYTES 请求的卷大小(以字节为单位)。

重载

local path provisioner 支持自动配置重载。用户可以使用 kubectl applykubectl edit 配合 ConfigMap local-path-config 来更改配置。从用户更新 ConfigMap 到 local path provisioner 采纳新配置之间会有一个延迟。为了使对 helper pod manifest 的更新也能生效,必须将以下环境变量添加到 local path provisioner 容器中。否则,用于 helper pod 的 manifest 将与 local path provisioner 上次重启/部署时 ConfigMap 中的内容保持一致。

- name: CONFIG_MOUNT_PATH
  value: /etc/config/

当 local path provisioner 检测到配置更改时,它将尝试加载新配置。用户可以在日志中观察到这一点:

time=“2018-10-03T05:56:13Z” level=debug msg=“Applied config: {“nodePathMap”:[{“node”:“DEFAULT_PATH_FOR_NON_LISTED_NODES”,“paths”:["/opt/local-path-provisioner”]},{“node”:“yasker-lp-dev1”,“paths”:["/opt","/data1"]},{“node”:“yasker-lp-dev3”}]}"

如果重载失败,local path provisioner 将记录错误,并在此期间继续使用上一个有效的配置进行供应

time="2018-10-03T05:19:25Z" level=error msg="failed to load the new config file: fail to load config file /etc/config/config.json: invalid character '\#' looking for beginning of object key string"
time="2018-10-03T05:20:10Z" level=error msg="failed to load the new config file: config canonicalization failed: path must start with / for path opt on node yasker-lp-dev1"
time="2018-10-03T05:23:35Z" level=error msg="failed to load the new config file: config canonicalization failed: duplicate path /data1 on node yasker-lp-dev1
time="2018-10-03T06:39:28Z" level=error msg="failed to load the new config file: config canonicalization failed: duplicate node yasker-lp-dev3"

卷类型

要指定您希望 local path provisioner 创建的卷类型,请添加以下任一注解:

  • PVC:

    annotations:
      volumeType: <local or hostPath>
    
  • StorageClass:

    annotations:
      defaultVolumeType: <local or hostPath>
    

需要注意几点:StorageClass 上的注解将应用于所有使用它的卷,但如果 PVC 上也提供了注解,则 PVC 上的注解会覆盖 StorageClass 上的注解。如果两个注解都没有提供,则默认为 hostPath

存储类 (Storage classes)

如果在 nodePathMap 中为一个节点指定了多个 paths,路径是随机选择的。要让 local path provisioner 选择特定的路径,请使用一个定义了 nodePath 参数的 storageClass。请注意,此路径应已在 nodePathMap 中定义。

默认情况下,卷子目录使用模板 {{ .PVName }}_{{ .PVC.Namespace }}_{{ .PVC.Name }} 进行命名,这使得目录名对每个 PV 实例都是唯一的。可以使用 pathPattern 参数更改此模板,该参数被解释为一个 go 模板。模板可以通过 PVName 变量访问 PV 名称,并通过 PVC 变量访问 PVC 的元数据对象,包括其标签和注解。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ssd-local-path
provisioner: rancher.io/local-path
parameters:
  nodePath: /data/ssd
  pathPattern: "{{ .PVC.Namespace }}/{{ .PVC.Name }}"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

在这里,当使用 ssd-local-path 存储类时,local path provisioner 将使用 /data/ssd 路径,并在其下为每个命名空间和 PVC 创建一个子目录。

卸载

在卸载之前,请确保由该 local path provisioner 创建的 PV 已经被删除。使用 kubectl get pv 并确认没有 StorageClass 为 local-path 的 PV 存在。

要卸载,请执行:

  • 稳定版

    kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.32/deploy/local-path-storage.yaml
    
  • 开发版

    kubectl delete -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
    

调试

为开发者提供了一个集群外的调试环境

git clone https://github.com/rancher/local-path-provisioner.git
cd local-path-provisioner
go build
kubectl apply -f debug/config.yaml
./local-path-provisioner --debug start --service-account-name=default

示例

使用方法

清理

kubectl delete -f debug/config.yaml

参考

  1. https://github.com/rancher/local-path-provisioner
本文总阅读量 次 本站总访问量 次 本站总访客数
Home Archives Categories Tags Statistics