apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-path annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: rancher.io/local-path volumeBindingMode: WaitForFirstConsumer reclaimPolicy: Delete --- apiVersion: v1 kind: ConfigMap metadata: name: local-path-config namespace: kube-system data: config.json: |- { "nodePathMap":[ { "node":"DEFAULT_PATH_FOR_NON_LISTED_NODES", "paths":["/var/lib/rancher/k3s/storage"] } ] } # The Setup script runs when a PVC is created setup: |- #!/bin/sh set -eu # Variables provided by the provisioner: # $VOL_DIR = The ugly UUID path (e.g., .../pvc-1234-abcd) # $PV_NAME = The PersistentVolume name (e.g., pvc-1234-abcd) # Extract PVC namespace and name from PV's claimRef via Kubernetes API if [ -z "${PVC_NAMESPACE:-}" ] || [ -z "${PVC_NAME:-}" ]; then if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]; then TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) API_SERVER="https://kubernetes.default.svc:443" CA_CERT="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" # First, try to get from PV's claimRef if PV_NAME is available if [ -n "${PV_NAME:-}" ]; then PV_JSON=$(wget -qO- --ca-certificate="$CA_CERT" --header="Authorization: Bearer $TOKEN" \ "$API_SERVER/api/v1/persistentvolumes/$PV_NAME" 2>/dev/null || echo "") if [ -n "$PV_JSON" ]; then # Extract claimRef namespace and name using sed # Look for "claimRef" followed by namespace and name fields TMP_NAMESPACE=$(echo "$PV_JSON" | sed -n 's/.*"claimRef":{[^}]*"namespace":"\([^"]*\)"[^}]*}.*/\1/p' | head -1) TMP_NAME=$(echo "$PV_JSON" | sed -n 's/.*"claimRef":{[^}]*"name":"\([^"]*\)"[^}]*}.*/\1/p' | head -1) # If the above didn't work, try a different pattern (claimRef might span multiple lines) if [ -z "$TMP_NAMESPACE" ]; then TMP_NAMESPACE=$(echo "$PV_JSON" | sed -n '/"claimRef":{/,/}/s/.*"namespace":"\([^"]*\)".*/\1/p' | head -1) fi if [ -z "$TMP_NAME" ]; then TMP_NAME=$(echo "$PV_JSON" | sed -n '/"claimRef":{/,/}/s/.*"name":"\([^"]*\)".*/\1/p' | head -1) fi if [ -n "$TMP_NAMESPACE" ]; then PVC_NAMESPACE="$TMP_NAMESPACE" fi if [ -n "$TMP_NAME" ]; then PVC_NAME="$TMP_NAME" fi fi fi fi # Final fallback if we still don't have the values if [ -z "${PVC_NAMESPACE:-}" ] || [ -z "${PVC_NAME:-}" ]; then echo "Error: Could not determine PVC_NAMESPACE or PVC_NAME" echo "Debug info - Available environment variables:" env | grep -E "(PVC_|PV_|VOL_)" || echo " (none found)" echo "PV_NAME: ${PV_NAME:-not set}" echo "VOL_DIR: ${VOL_DIR:-not set}" echo "" echo "Note: The local-path-provisioner should provide PVC_NAMESPACE and PVC_NAME" echo "as environment variables. If they are not available, the provisioner version" echo "may not support this feature, or the helper pod needs proper RBAC permissions." exit 1 fi fi # 1. Define your pretty path in /data/pvc for easier management PRETTY_PATH="/data/pvc/${PVC_NAMESPACE}/${PVC_NAME}" # 2. Create the pretty folder mkdir -p "$PRETTY_PATH" chmod 777 "$PRETTY_PATH" # 3. Create a symlink: Ugly UUID -> Pretty Path # Kubernetes looks at the UUID path, but data is actually written to Pretty Path ln -s "$PRETTY_PATH" "$VOL_DIR" # The Teardown script runs when a PVC is deleted teardown: |- #!/bin/sh set -eu # Variables provided: $VOL_DIR (The UUID path) # 1. Resolve where the symlink points to (The pretty path) if [ -L "$VOL_DIR" ]; then PRETTY_PATH=$(readlink "$VOL_DIR") # 2. Remove the Symlink (The UUID entry) rm "$VOL_DIR" fi helperPod.yaml: |- apiVersion: v1 kind: Pod metadata: name: helper-pod spec: serviceAccountName: local-path-provisioner-service-account containers: - name: helper-pod image: busybox imagePullPolicy: IfNotPresent