Search code examples
kubernetespersistent-volumeskubernetes-pvc

kubernetes ignoring persistentvolume


I have created a persistent volume:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "C:/Users/xxx/Desktop/pv"

And want to make save mysql statefulset pods things on it. So, I wrote the volumeclaimtemplate:

  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

Thinking this would request the persistent storage from the only persistent volume I have. Instead, this is what happens: persistent volumes


Solution

  • StatefulSets requires you to use storage classes in order to bind the correct PVs with the correct PVCs.

    The correct way to make StatefulSets mount local storage is by using local type of volumes, take a look at the procedure below.


    First, you create a storage class for the local volumes. Something like the following:

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: local-storage
    provisioner: kubernetes.io/no-provisioner
    volumeBindingMode: WaitForFirstConsumer
    

    It has no-provisioner so it will not be able to automatically provision PVs, you'll need to create them manually, but that's exactly what you want for local storage.

    Second, you create your local PV, something as the following:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv-volume
    spec:
      capacity:
        storage: 5Gi
      volumeMode: Filesystem
      accessModes:
      - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain
      storageClassName: local-storage
      local:
        path: "C:/Users/xxx/Desktop/pv"
      nodeAffinity:
        required:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - the-node-hostname-on-which-the-storage-is-located
    

    This definition tells the local path on the node, but also forces the PV to be used on a specific node (which match the nodeSelectorTerms).

    It also links this PV to the storage class created earlier. This means that now, if a StatefulSets requires a storage with that storage class, it will receive this disk (if the space required is less or equal, of course)

    Third, you can now link the StatefulSet:

    volumeClaimTemplates:
      - metadata:
          name: data
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "local-storage"
          resources:
            requests:
              storage: 5Gi
    

    When the StatefulSet Pod will need to be scheduled for the first time, the following will happen:

    • A PVC will be created and it will go Bound with the PV you just created
    • The Pod will be scheduled to run on the node on which the bounded PV is restricted to run

    UPDATE:

    In case you want to use hostPath storage instead of local storage (because for example you are on minikube and that is supported out of the box directly, so it's more easy) you need to change the PV declaration a bit, something like the following:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv-volume
    spec:
      storageClassName: local-storage
      accessModes:
        - ReadWriteOnce
      capacity:
        storage: 5Gi
      hostPath:
        path: /data/pv0001/
    

    Now, the /data directory and all its content is persisted on the host (so if minikube gets restarted, it's still there) but if you want to mount specific directories of your host, you need to use minikube mount, for example:

    minikube mount <source directory>:<target directory>
    

    For example, you could do:

    minikube mount C:/Users/xxx/Desktop/pv:/host/my-special-pv

    and then you could use /host/my-special-pv as the hostPath inside the PV declaration.

    More info can be read in the docs.