Local Path Provisioner 为 Kubernetes 用户提供了一种利用各个节点上本地存储的方法。根据用户配置,Local Path Provisioner 会在节点上自动创建基于 hostPath
或 local
的持久卷(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
进行部署。
安装后,您应该会看到类似下面的输出:
$ 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:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-path-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 128Mi
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 脚本 setup
和 teardown
,它们存储在一个 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
是用户可以自定义在每个节点上存储数据位置的地方。
- 如果某个节点未在
nodePathMap
中列出,而 Kubernetes 要在该节点上创建卷,则会使用 DEFAULT_PATH_FOR_NON_LISTED_NODES
中指定的路径进行供应。
- 如果某个节点在
nodePathMap
中列出,则会使用 paths
中指定的路径进行供应。
- 如果某个节点被列出,但其
paths
设置为 []
,则 local path 将拒绝在该节点上供应卷。
- 如果指定了多个路径,则在供应时会随机选择一个路径。
sharedFileSystemPath
允许 local path 使用一个同时挂载在所有节点上的文件系统。在这种情况下,支持所有访问模式:ReadWriteOnce
、ReadOnlyMany
和 ReadWriteMany
。
storageClassConfigs
是一个从存储类(storage class)名称到包含 nodePathMap
或 sharedFilesystemPath
对象的映射,如上所述。
此外,可以在 StorageClass 定义中使用 volumeBindingMode: Immediate
。
请注意,nodePathMap
、sharedFileSystemPath
和 storageClassConfigs
是互斥的。如果使用了 sharedFileSystemPath
或 storageClassConfigs
,则 nodePathMap
必须设置为空数组 []
。
setupCommand
和 teardownCommand
允许您指定 helperPod 中二进制文件的路径,这些文件将分别在创建或删除 PVC 时被调用。如果您出于安全原因需要使用 distroless 镜像,这会很有用。请参阅 examples/distroless 目录中的示例。二进制文件可以接受以下参数:
参数 |
描述 |
-p |
应该被创建或移除的卷目录。 |
-m |
PersistentVolume 的模式(Block 或 Filesystem )。 |
-s |
请求的卷大小(以字节为单位)。 |
-a |
操作类型,可以是 create 或 delete 。 |
setupCommand
和 teardownCommand
的优先级高于 ConfigMap 中的 setup
和 teardown
脚本。
config.json
必须是有效的 JSON 文件。
- 路径必须以
/
开头,即为绝对路径。
- 禁止使用根目录(
/
)。
- 单个节点不允许有重复的路径。
- 不允许有重复的节点。
setup
和 teardown
脚本以及 helperPod.yaml
模板
setup
脚本在创建卷之前运行,用于在节点上准备卷目录。
teardown
脚本在删除卷之后运行,用于清理节点上的卷目录。
helperPod.yaml
模板用于创建一个运行 setup
或 teardown
脚本的辅助 Pod (helper Pod)。
这些脚本通过环境变量接收输入:
环境变量 |
描述 |
VOL_DIR |
应该被创建或移除的卷目录。 |
VOL_MODE |
PersistentVolume 的模式(Block 或 Filesystem )。 |
VOL_SIZE_BYTES |
请求的卷大小(以字节为单位)。 |
重载
local path provisioner 支持自动配置重载。用户可以使用 kubectl apply
或 kubectl 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