k8s uses localpath to dynamically provide storage for pods

In the k8s environment, we often use the local path as persistent storage. In the k8s official document, there are two ways to use local storage, one is hostPath, the other is local volume, neither of which supports dynamic expansion, and the program porting changes are relatively large, and local-path-provisioner is very good made up for this shortcoming.

Steps to use local-path-provisioner:
1. Create a local-path path

[root@node1 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sr0 11:0 1 470K 0 rom
vda 253:0 0 100G 0 disk
└─vda1 253:1 0 100G 0 part /
vdb 253:16 0 500G 0 disk
└─nfs-lvol0 252:0 0 495G 0 lvm /data
vdc 253:32 0 400G 0 disk ###Add a disk
[root@node1 ~]# mkdir /local ####Create directory


[root@node1 ~]# pvcreate /dev/vdc ####Create pv
WARNING: xfs signature detected on /dev/vdc at offset 0. Wipe it? [y/n]: y
  Wiping xfs signature on /dev/vdc.
  Physical volume "/dev/vdc" successfully created.

[root@node1 ~]# vgcreate local-path /dev/vdc ####Create vg
  Volume group "local-path" successfully created
[root@node1~]#
[root@node1 ~]# vgs
  VG #PV #LV #SN Attr VSize VFree
  local-path 1 0 0 wz--n- <400.00g <400.00g
  nfs 1 1 0 wz--n- <500.00g <5.00g
[root@node1~]#
[root@node1 ~]# lvcreate --size 300G local-path ####create lvm
  Logical volume "lvol0" created.
[root@node1~]#
[root@node1 ~]# mkfs.xfs /dev/local-path/lvol0
meta-data=/dev/local-path/lvol0 isize=512 agcount=4, agsize=19660800 blks
         = sectsz=512 attr=2, projid32bit=1
         = crc=1 finobt=0, sparse=0
data = bsize=4096 blocks=78643200, imaxpct=25
         = sunit=0 width=0 blks
naming=version 2 bsize=4096 ascii-ci=0 ftype=1
log=internal log bsize=4096 blocks=38400, version=2
         = sectsz=512 sunit=0 blks, lazy-count=1
realtime=none extsz=4096 blocks=0, rtextents=0
[root@node1~]#

[root@node1 ~]# mount /dev/local-path/lvol0 /local/ ####mount lvm to local
[root@node1~]#
[root@node1 ~]# cat /etc/fstab
LABEL=img-rootfs / xfs defaults 0 1
/dev/nfs/lvol0 /data xfs defaults 0 1
/dev/local-path/lvol0 /local xfs defaults 0 1 ####Write into fstab, it can be automatically mounted when booting
[root@node1~]#

2. Start local-path-provisioner

1: Edit the local-path-storage.yaml file as follows:
---
apiVersion: v1
kind:Namespace
metadata:
  name: local-path-storage

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: local-path-provisioner-service-account
  namespace: local-path-storage

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: local-path-provisioner-role
rules:
  - apiGroups: [ "" ]
    resources: [ "nodes", "persistent volume claims", "configmaps" ]
    verbs: [ "get", "list", "watch" ]
  - apiGroups: [ "" ]
    resources: [ "endpoints", "persistent volumes", "pods" ]
    verbs: [ "*" ]
  - apiGroups: [ "" ]
    resources: [ "events" ]
    verbs: [ "create", "patch" ]
  - apiGroups: [ "storage.k8s.io" ]
    resources: [ "storageclasses" ]
    verbs: [ "get", "list", "watch" ]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: local-path-provisioner-bind
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: local-path-provisioner-role
subjects:
  - kind: ServiceAccount
    name: local-path-provisioner-service-account
    namespace: local-path-storage

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: local-path-provisioner
  namespace: local-path-storage
spec:
  replicas: 1
  selector:
    matchLabels:
      app: local-path-provisioner
  template:
    metadata:
      labels:
        app: local-path-provisioner
    spec:
      serviceAccountName: local-path-provisioner-service-account
      containers:
        - name: local-path-provisioner
          image: docker.io/rancher/local-path-provisioner:v0.0.22
          imagePullPolicy: IfNotPresent
          command:
            -local-path-provisioner
            - --debug
            - start
            - --config
            - /etc/config/config.json
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config/
          env:
            - name: PROVISIONER_NAME
              value: rancher.io/local-path
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
      volumes:
        - name: config-volume
          configMap:
            name: local-path-config

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-path
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

---
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":["/local"] ##### replace the actual path
            }
            ]
    }
  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:
      containers:
      - name: helper-pod
        image: busybox
        imagePullPolicy: IfNotPresent
[root@node1 local]#
[root@node1 local]# kubectl apply -f local-path-storage.yaml

####Check if the pod starts normally
[root@node1 ~]# kubectl get po -n local-path-storage
NAME READY STATUS RESTARTS AGE
local-path-provisioner-c755757b6-5gcr6 1/1 Running 0 23d
[root@node1~]#

####View the log, the local path has been identified
[root@node1 ~]# kubectl logs local-path-provisioner-c755757b6-5gcr6 -n local-path-storage
time="2023-04-28T07:28:26Z" level=debug msg="Applied config: {"nodePathMap":[{"node":\ "DEFAULT_PATH_FOR_NON_LISTED_NODES","paths":["/local"]}]}"
time="2023-04-28T07:28:26Z" level=debug msg="Provisioner started"
I0428 07:28:26.478078 1 controller.go:773] Starting provisioner controller rancher.io/local-path_local-path-provisioner-c755757b6-5gcr6_d00cd9cb-89e8-4911-b9c3-f7ed5a89a368!
I0428 07:28:26.578610 1 controller.go:822] Started provisioner controller rancher.io/local-path_local-path-provisioner-c755757b6-5gcr6_d00cd9cb-89e8-4911-b9c3-f7ed5a89a368


2: Create a storage class, as follows:
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-path
provisioner: rancher.io/local-path ####The provisioner name defined above
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

Execute sc.yaml as follows:
[root@node1 local]# kubectl apply -f sc.yaml
[root@node1 ~]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUME BINDING MODE ALLOW VOLUME EXPANSION AGE
local-path rancher.io/local-path Delete WaitForFirstConsumer false 23d
[root@node1~]#

3: The use of local-path
In the yaml file, directly use the sc name to dynamically create pvc. The local-path is suitable for a stand-alone environment. If there are multiple nodes, you must ensure that each node has a local-path to ensure that the pod can be scheduled successfully.