<p>So there is:</p>

<ul>
<li>the <em>StatefulSet</em> to control several replicas of a <em>Pod</em> in an ordered manner.</li>
<li>the <em>PersistentVolumeClaim</em> to provide volume to a <em>Pod</em>.</li>
<li>the <code>statefulset.spec.volumeClaimTemplate[]</code> to bind the previous two together.</li>
<li>the <em>PersistentVolumeSelector</em> to control which <em>PersistentVolume</em> fulfills which <em>PersistentVolumeClaim</em>.</li>
</ul>

<p>Suppose I have persistent volumes named <em>pv0</em> and <em>pv1</em>, and a statefulset with 2 replicas called <em>couchdb</em>. Concretely, the statefulset is:</p>

<pre><code>apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: couchdb
spec:
  ...
  replicas: 2
  template:
    ...
    spec:
      containers:
        - name: couchdb
          image: klaemo/couchdb:1.6
          volumeMounts:
            - name: db
              mountPath: /usr/local/var/lib/couchdb
      volumes:
        - name: db
          persistentVolumeClaim
            claimName: db
  volumeClaimTemplates:
    - metadata:
        name: db
      spec:
        ...
</code></pre>

<p>this <em>StatefulSet</em> generates two <em>PersistentVolumeClaim</em> named <em>db-couchdb-0</em> and <em>db-couchdb-1</em>. The problem is that it is not guaranteed that pvc <em>db-couchdb-0</em> will be always bound to <em>pv0</em>.</p>

<p>The question is: <strong>how do you ensure controlled binds for <em>PersistentVolumeClaim</em> managed by a <em>StatefulSet</em> controller?</strong></p>

<p>I tried adding a volume selector like this:</p>

<pre><code>selector:
  matchLabels:
    name: couchdb
</code></pre>

<p>to the <code>statefulset.spec.volumeClaimTemplate[0].spec</code> but the value of <em>name</em> doesn't get templated. Both claims will end up looking for a <em>PersistentVolume</em> labeled <em>name=couchdb</em>.</p>

<p>What you're looking for is a <code>claimRef</code> inside the persistent volume, which have the name and namespace of PVC, to which you want to bind your PV. Please have a look at the following jsons:</p>

<p>Pv-0.json</p>

<pre><code>{
  "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"
                ]
              }
            ]
          }
        ]
      }
    }
  }
}
</code></pre>

<p>Pv-1.json</p>

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

<p>Statefulset.json</p>

<pre><code>{
  "kind": "StatefulSet",
  "apiVersion": "apps/v1beta1",
  "metadata": {
    "name": "test-sf",
    "labels": {
      "state": "test-sf"
    }
  },
  "spec": {
    "replicas": 2,
    "template": {
      "metadata": {
        "labels": {
          "app": "test-sf"
        },
        "annotations": {
          "pod.alpha.kubernetes.io/initialized": "true"
        }
      }
      ...
      ...
    },
    "volumeClaimTemplates": [
      {
        "metadata": {
          "name": "data"
        },
        "spec": {
          "accessModes": [
            "ReadWriteOnce"
          ],
          "storageClassName": "local-storage",
          "resources": {
            "requests": {
              "storage": "10Gi"
            }
          }
        }
      }
    ]
  }
}
</code></pre>

<p>The <code>volumeClaimTemplate</code> will create two PVC <code>test-sf-data-0</code> and <code>test-sf-data-1</code>. The two PV definition contains the <code>claimRef</code> section which has the <code>namespace</code> and <code>PVC name</code> on which PV should bind to. Please note that you have to provide the <code>namespace</code> as a mandatory because PV's are independent of namespace and there might be two PVC with same name on two different namespace. Hence, how does kubernetes controller manager will understand on which PVC, PV should bind, if we don't provide namespace name.</p>

<p>Hope this answers your question. </p>
