Skip to content

Host Directory Mounting

In this tutorial you will share a directory from your host machine with pods running inside a kinder cluster. Because kinder nodes are Docker (or Podman) containers, a host directory cannot reach a pod in a single step — it travels through two hops: the host directory is mounted into the node container via extraMounts, and from there a Kubernetes hostPath PersistentVolume exposes it to pods. By the end of this guide you will have a running pod that reads a file written on your host.

  • kinder installed
  • Docker (or Podman) installed and running
  • kubectl installed and on PATH
  • A host directory you want to share with the cluster

Create the directory and add a test file so you can verify the mount end-to-end:

Terminal window
mkdir -p ~/shared-data
echo "hello from the host" > ~/shared-data/hello.txt

Step 2: Create the cluster with extraMounts

Section titled “Step 2: Create the cluster with extraMounts”

Save the following as cluster-config.yaml. The extraMounts field tells kinder (and the underlying kind cluster) to bind-mount ~/shared-data from your host into each node container at /mnt/host-data:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- hostPath: /Users/you/shared-data
containerPath: /mnt/host-data

Replace /Users/you/shared-data with the absolute path of the directory you created in Step 1 (use echo ~/shared-data to resolve the tilde).

Create the cluster:

Terminal window
kinder create cluster --config cluster-config.yaml

Step 3: Create a PersistentVolume and PersistentVolumeClaim

Section titled “Step 3: Create a PersistentVolume and PersistentVolumeClaim”

Now that the directory is available inside every node container at /mnt/host-data, create a Kubernetes hostPath PersistentVolume that points to that containerPath. Save the following as pv-pvc.yaml:

apiVersion: v1
kind: PersistentVolume
metadata:
name: host-data-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: manual
hostPath:
path: /mnt/host-data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: host-data-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: manual
resources:
requests:
storage: 1Gi

Apply it:

Terminal window
kubectl apply -f pv-pvc.yaml

Verify the PV is bound:

Terminal window
kubectl get pv host-data-pv

Expected output:

NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS AGE
host-data-pv 1Gi RWO Retain Bound default/host-data-pvc manual 10s

Step 4: Deploy a pod that consumes the PVC

Section titled “Step 4: Deploy a pod that consumes the PVC”

Save the following as reader-pod.yaml. The pod mounts the PVC at /data and reads hello.txt:

apiVersion: v1
kind: Pod
metadata:
name: host-data-reader
spec:
containers:
- name: reader
image: busybox:1.37.0
command: ["sh", "-c", "cat /data/hello.txt && sleep 3600"]
volumeMounts:
- name: host-data
mountPath: /data
volumes:
- name: host-data
persistentVolumeClaim:
claimName: host-data-pvc

Apply it:

Terminal window
kubectl apply -f reader-pod.yaml

Wait for the pod to be running:

Terminal window
kubectl get pod host-data-reader

Expected output:

NAME READY STATUS RESTARTS AGE
host-data-reader 1/1 Running 0 15s

Read the logs from the pod to confirm it can see the file from your host:

Terminal window
kubectl logs host-data-reader

Expected output:

hello from the host

The pod read hello.txt directly from your host machine through the two-hop mount chain.

Data travels through two hops to reach the pod:

Host machine Node container Pod
~/shared-data ---> /mnt/host-data ---> /data
(extraMounts) (hostPath PV) (volumeMount)
  1. Hop 1 — extraMounts: kinder passes the hostPath/containerPath pair to the container runtime (Docker or Podman) when it creates the node container. The host directory appears at containerPath inside the node.
  2. Hop 2 — hostPath PV: Kubernetes creates a PersistentVolume backed by hostPath: /mnt/host-data. Because this path already exists in the node’s filesystem (from Hop 1), the volume is immediately available. The PVC binds to the PV and the pod mounts it.

On macOS, Docker Desktop runs a Linux VM. For a host directory to reach a kinder node container, Docker Desktop must be configured to share it with that VM first.

File sharing: Open Docker Desktop → Settings → Resources → File sharing. Add the parent directory of your hostPath (e.g., /Users/you) if it is not already listed. The default shared paths are /Users, /Volumes, /private, /tmp, and /var/folders. Paths outside these directories will not be accessible.

Mount propagation: The propagation field in extraMounts controls whether sub-mounts created at runtime are visible across the host/node boundary. On macOS, propagation modes other than None are not supported for paths that originate on the macOS host (outside the Docker Desktop VM). Set propagation: None (the default) unless you are mounting a path that exists only inside the Docker Desktop Linux VM.

Windows paths must use forward slashes and be expressed as WSL paths (e.g., /mnt/c/Users/you/shared-data rather than C:\Users\you\shared-data). Ensure the directory is within a WSL 2 filesystem or is exposed via Docker Desktop’s drive sharing.

On Linux, Docker (or Podman) runs natively and there is no intermediate VM. All host paths are directly accessible. Mount propagation modes (HostToContainer, Bidirectional) work as expected.

Delete the pod and Kubernetes objects:

Terminal window
kubectl delete pod host-data-reader
kubectl delete pvc host-data-pvc
kubectl delete pv host-data-pv

Delete the cluster:

Terminal window
kinder delete cluster

Optionally remove the host directory:

Terminal window
rm -rf ~/shared-data