Pod affinity to host node of bound local persistent volume

4/9/2019

I'm working on a bare-metal inst of k8s, and am trying out local persistent volume using k8s v1.14. The purpose is to allow me to create an HA postgres deployment using postgres-operator. Since I'm on bare metal, I cannot make use of dynamic PVCs, as seems to be normal in the tutorials.

To begin with, I created some PVs bound to manually created volumes on the host nodes. The PVs are assigned, using nodeAffinity, to specific nodes. i.e. primary-vol PV is assigned to node1, and replica-vol-1 is assigned to node2 and so on.

I am then binding my pod to the PV using a PVC as documented here.

What I've found is that the k8s scheduler has placed my pod (which is bound to a PV on node1) on node2 rather than node1 as I expected.

Is there a way, using affinity on the pod, to ensure that the pod is created on the same node as the PV it is bound to?

EDIT: to simplify the question (with apologies to artists and architects everywhere)

How can the pod know what node the PV is assigned to, when it doesn't even know what PV it is bound to?

How can the pod know what node the PV is assigned to, when it doesn't even know what PV it is bound to?

-- Andrew Matthews
kubernetes

1 Answer

4/9/2019

Yes, you can achieve it using the claimRef in your PV definition. By using claimRef in your PV, you're binding a PVC with specific name to that PV and you can use that PVC name in your pod definition in persistentVolumeClaim.

You should have PV definition like following:

{
  "kind": "PersistentVolume",
  "apiVersion": "v1",
  "metadata": {
    "name": "pv-data-vol-0",
    "labels": {
      "type": "local"
    }
  },
  "spec": {
    "capacity": {
      "storage": "10Gi"
    },
    "accessModes": [
      "ReadWriteOnce"
    ],
    "storageClassName": "local-storage",
    "local": {
      "path": "/prafull/data/pv-0"
    },
    "claimRef": {
      "namespace": "default",
      "name": "data-test-sf-0"
    },
    "nodeAffinity": {
      "required": {
        "nodeSelectorTerms": [
          {
            "matchExpressions": [
              {
                "key": "kubernetes.io/hostname",
                "operator": "In",
                "values": [
                  "ip-10-0-1-46.ec2.internal"
                ]
              }
            ]
          }
        ]
      }
    }
  }
}

In the above json file, the claimRef, name should be the name of the PVC you want to bind that PV to and namespace should be the namespace in which the PVC reside.

Note: namespace is mandatory field as PV's are independent of namespace and PVC are bound in namespace and hence PV should know in which namespace it should look for PVC.

So once you're able to bind the specific PV to specific PVC, you can bind that specific PVC to the specific POD and hence that pod will always come on the same node where PV is present.

For reference, please have a look at my following answer:

Is it possible to mount different pods to the same portion of a local persistent volume?

Hope this helps

-- Prafull Ladha
Source: StackOverflow