Self-hosted service
rancher/local-path-provisioner avatar
rancher/local-path-provisioner

Local Path Provisioner: dynamic local storage for Kubernetes without the manual PV dance

Dynamically provisioning persistent local storage with Kubernetes

2,940 stars531 forksGoApache-2.0

At a glance

What is it?
Rancher's Local Path Provisioner turns a directory on each node into a StorageClass that can provision hostPath or local volumes on demand. It is a small, single-purpose controller, and the README is explicit about what it will not do.
Who is it for?
Use Local Path Provisioner when you want a StorageClass that provisions hostPath or local volumes on demand and you can live without capacity enforcement. Do not use it when you need replicated storage, multi-node ReadWriteMany semantics, or a hard per-volume size limit; the README states capacity limits are ignored, and the examples/pvc-with-rwop-access-mode directory exists precisely because ReadWriteOncePod is a separate opt-in.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Local Path Provisioner solves, and for whom

Kubernetes has a built-in local persistent volume feature, and the README points at the upstream blog post for it. The problem is that the built-in path requires you to pre-create PersistentVolumes by hand, matching node names and paths yourself. The README says the Kubernetes Local Volume provisioner cannot do dynamic provisioning for local volumes. Local Path Provisioner exists to close that gap: a PersistentVolumeClaim gets bound, and the controller creates the PersistentVolume for you.

The audience is narrow and specific. Single-node clusters, edge boxes, lab machines, and any cluster where the data is fine living on one node's disk. The README describes the mechanism plainly: based on user configuration, it creates either hostPath or local based persistent volumes on the node automatically. If your workloads need to survive a node loss without a restore, this is not the project for you. If you want a PVC to just work on a k3s box in a cupboard, it is.

How the provisioner decides where a volume lives

The controller is not a CSI driver. It runs as a pod in the local-path-storage namespace and implements the external provisioner contract, which is why go.mod pulls in sigs.k8s.io/sig-storage-lib-external-provisioner/v11. When a PVC referencing the local-path StorageClass appears, the controller picks a node and a path, then creates the PV object pointing at that location.

The path decision comes from a ConfigMap named local-path-config. Its config.json holds a nodePathMap array. Each entry has a node and a paths list. The README shows a DEFAULT_PATH_FOR_NON_LISTED_NODES entry covering nodes that are not listed individually, plus per-node overrides. A node with an empty paths array, like the yasker-lp-dev3 example, gets nothing, which is how you exclude a node.

Creation and deletion are not done by the controller process itself. The ConfigMap also carries a setup script and a teardown script, plus a helperPod.yaml template. The controller runs the helper pod on the target node to execute setup (the README's default is mkdir -m 0777 -p "$VOL_DIR") and teardown (rm -rf "$VOL_DIR"). Those two scripts are the real interface to your disk, and they are editable.

Installing it and provisioning a first volume

The README gives a single kubectl apply against a pinned release tag. The provisioner lands in the local-path-storage namespace, and the default provisioning directory across nodes is /opt/local-path-provisioner.

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

The same page offers a kustomize route if you prefer building the manifests yourself, using the deploy directory at a ref.

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

After applying, the README says you should see a single running pod in that namespace. If it is not Running, the log is the next stop.

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

To exercise it, the repository ships example manifests under examples/pvc and examples/pod. Creating them yields a Bound PVC against a PV named after the claim UID, with the local-path StorageClass.

bash
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
kubectl get pv
kubectl get pvc

The README's own walkthrough then writes a file into /data inside the pod, deletes the pod, recreates it, and cats the file back. That round trip is the point: the data outlives the pod because it sits on the node. Deleting the PVC triggers teardown, and the README states the volume content stored on the node is automatically cleaned up.

The capacity limit is ignored, and that is not a footnote

The README's Cons section has one item, and it is blunt: no support for the volume capacity limit currently, and the capacity limit will be ignored for now. A PVC asking for 2Gi and a PVC asking for 2Ti behave the same way. The scheduler will place the pod as if the request were satisfiable, and the disk fills up on its own schedule.

That has a second-order effect. Because the provisioner does not track free space, it will happily bind claims on a node that is nearly full. The README's helperPod template is written with this in mind: it sets priorityClassName: system-node-critical and tolerates node.kubernetes.io/disk-pressure with effect NoSchedule. The README explains that the helper pod is allowed to run on nodes experiencing disk pressure so it can carry out cleanup tasks and free space in PVCs. That is a mitigation, not enforcement. If you need quota-backed storage, look at the examples/quota directory, but understand that the quota is a Kubernetes object you manage, not something the provisioner enforces per volume.

Other limits follow from the design. A local volume is tied to one node, so a pod using it is effectively pinned there. The repository has examples/pod-with-node-affinity and examples/pvc-with-node to make that explicit. And ReadWriteMany is not something a hostPath directory gives you across nodes; examples/pvc-with-rwop-access-mode and examples/pod-with-rwop-volume point at ReadWriteOncePod, which is a single-pod guarantee, not a shared-filesystem one.

Where it sits next to the built-in local volume provisioner and Longhorn

The most direct comparison is with the Kubernetes SIG Storage local static provisioner. Both manage local disks. The difference is timing: the static provisioner expects you to pre-create PVs for directories you have already prepared, and it binds claims to them. Local Path Provisioner creates the PV at claim time from a path template. The README states the static provisioner cannot do dynamic provisioning, and that is the whole pitch here. The cost of that convenience is that the provisioner chooses the path, and the capacity it reports carries no real meaning.

The other comparison people reach for is Longhorn, which Rancher also maintains. Longhorn replicates block storage across nodes and gives you snapshots, rebuilds, and a UI. Local Path Provisioner gives you a directory. There is no replication, no snapshot API, no rebuild. The trade is deliberate: no replication means no cross-node network traffic and no extra daemon per node, which is why it fits single-node and edge clusters. If a node dies with a Longhorn volume on it, the replica elsewhere can serve the data. If a node dies with a local-path volume on it, the data is on that disk and nowhere else. Pick based on whether that sentence is acceptable to you.

OpenEBS and the hostPath volume type come up too. A raw hostPath volume in a pod spec skips the PVC and StorageClass layer entirely and gives you no lifecycle management. Local Path Provisioner keeps the PVC abstraction and the reclaim policy, which is the reason to use it over a hand-written hostPath mount.

Upgrade cost, release cadence and the Apache-2.0 terms

Upgrades are a manifest swap. The README pins installation to a release tag, and the latest listed release is v0.0.37 from 2026-08-05, preceded by v0.0.37-rc1 and v0.0.37-rc2 in early August. The repository's last push was on 2026-09-22, so work is ongoing rather than frozen, but the version numbering is 0.0.x and the project makes no compatibility promises in the README beyond the Kubernetes v1.12+ requirement.

The practical upgrade risk is the ConfigMap, not the Deployment. If you have edited local-path-config to add node paths or to change the setup and teardown scripts, reapplying the upstream manifest can overwrite that. The README does not document a rollback procedure for a provisioner upgrade, and it does not describe a migration path for volumes created by an older version. Treat the ConfigMap as your own artifact and diff it before applying anything new.

On licensing, the repository carries Apache-2.0. That permits commercial use and modification, and it includes a patent grant. It also means you take on the obligation to preserve notices and to state changes if you redistribute a modified version. The setup and teardown scripts you write into the ConfigMap are your own code running as root on your nodes, and the README does not discuss the security implications of that. That is a question for your own review, not something the project answers.

Editorial conclusion

Use Local Path Provisioner when you want a StorageClass that provisions hostPath or local volumes on demand and you can live without capacity enforcement. Do not use it when you need replicated storage, multi-node ReadWriteMany semantics, or a hard per-volume size limit; the README states capacity limits are ignored, and the examples/pvc-with-rwop-access-mode directory exists precisely because ReadWriteOncePod is a separate opt-in. Before adopting it, check the config.json nodePathMap against your actual node names, confirm the helperPod tolerations match your cluster's taint situation, and read the setup and teardown scripts in the ConfigMap since they run on your nodes.

Frequently asked questions

What is the Local Path Provisioner in Kubernetes?

It is a controller that dynamically provisions persistent volumes from local disk on each node. Based on user configuration it creates either hostPath or local based persistent volumes automatically, which the README contrasts with the built-in local volume feature that requires pre-created PVs.

How do I install local path provisioner?

The README gives a single kubectl apply against the deploy/local-path-storage.yaml file at a release tag, which installs it into the local-path-storage namespace. A kustomize build against the deploy directory is offered as an alternative.

What is the difference between a storage class and a persistent volume?

In this project the StorageClass named local-path is what a PVC references, and the PersistentVolume is the object the provisioner creates in response. The README's walkthrough shows a PVC named local-path-pvc binding to a PV named after a UUID, with the local-path StorageClass recorded on both.

What is the difference between a PV and a PVC?

The PVC is the namespaced request a workload makes, and the PV is the cluster-scoped object that satisfies it. The README's example shows a PVC in the default namespace bound to a PV whose name is a UUID, with both reporting the same capacity and the local-path StorageClass.

What is the difference between local path provisioner and hostpath?

A hostPath volume is written directly into a pod spec and has no provisioning or lifecycle layer. Local Path Provisioner can create hostPath based persistent volumes, but it does so behind a PVC and a StorageClass, so the volume has a reclaim policy and is created on demand rather than declared by hand.

What is a local path provisioner alternative?

The README compares it with the Kubernetes SIG Storage local static provisioner, which cannot do dynamic provisioning and expects pre-created PVs. Longhorn is the other Rancher-maintained option, and it replicates block storage across nodes instead of exposing a single node's directory.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. rancher/local-path-provisioner on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rancher-local-path-provisioner.svg)](https://hysenlabs.com/projects/rancher-local-path-provisioner)