<p>I am trying to do a install of RabbitMQ in Kubernetes and following the entry on the RabbitMQ site <a href="https://www.rabbitmq.com/blog/2020/08/10/deploying-rabbitmq-to-kubernetes-whats-involved/" rel="nofollow noreferrer">https://www.rabbitmq.com/blog/2020/08/10/deploying-rabbitmq-to-kubernetes-whats-involved/</a>.</p>
<p>Please note my CentOS 7 and Kubernetes 1.18.  Also, I am not even sure this is the best way to deploy RabbitMQ, its the best documentation I could find though. I did find something that said that volumeClaimTemplates does not support NFS so I am wondering if that is the issue.</p>
<p>I have added the my Persistent Volume using NFS:</p>
<pre><code>kind: PersistentVolume
apiVersion: v1
metadata:
  name: rabbitmq-nfs-pv
  namespace: ninegold-rabbitmq
spec:
  capacity:
    storage: 5Gi
  accessModes:
  - ReadWriteOnce
  nfs:
    path: /var/nfsshare
    server: 192.168.1.241
  persistentVolumeReclaimPolicy: Retain
</code></pre>
<p>It created the PV correctly.</p>
<pre><code>[admin@centos-controller ~]$ kubectl get pv -n ninegold-rabbitmq
NAME                                      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                                     STORAGECLASS   REASON   AGE
ninegold-platform-custom-config-br        1Gi        RWX            Retain           Bound       ninegold-platform/ninegold-db-pgbr-repo                           22d
ninegold-platform-custom-config-pgadmin   1Gi        RWX            Retain           Bound       ninegold-platform/ninegold-db-pgadmin                             21d
ninegold-platform-custom-config-pgdata    1Gi        RWX            Retain           Bound       ninegold-platform/ninegold-db                                     22d
rabbitmq-nfs-pv                           5Gi        RWO            Retain           Available                                                                     14h
</code></pre>
<p>I then add my StatefulSet.</p>
<pre><code>apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rabbitmq
  namespace: ninegold-rabbitmq
spec:
  selector:
    matchLabels:
      app: &quot;rabbitmq&quot;
  # headless service that gives network identity to the RMQ nodes, and enables them to cluster
  serviceName: rabbitmq-headless # serviceName is the name of the service that governs this StatefulSet. This service must exist before the StatefulSet, and is responsible for the network identity of the set. Pods get DNS/hostnames that follow the pattern: pod-specific-string.serviceName.default.svc.cluster.local where &quot;pod-specific-string&quot; is managed by the StatefulSet controller.
  volumeClaimTemplates:
  - metadata:
      name: rabbitmq-data
      namespace: ninegold-rabbitmq
    spec:
      storageClassName: local-storage
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: &quot;5Gi&quot;
  template:
    metadata:
      name: rabbitmq
      namespace: ninegold-rabbitmq
      labels:
        app: rabbitmq
    spec:
      initContainers:
      # Since k8s 1.9.4, config maps mount read-only volumes. Since the Docker image also writes to the config file,
      # the file must be mounted as read-write. We use init containers to copy from the config map read-only
      # path, to a read-write path
      - name: &quot;rabbitmq-config&quot;
        image: busybox:1.32.0
        volumeMounts:
        - name: rabbitmq-config
          mountPath: /tmp/rabbitmq
        - name: rabbitmq-config-rw
          mountPath: /etc/rabbitmq
        command:
        - sh
        - -c
        # the newline is needed since the Docker image entrypoint scripts appends to the config file
        - cp /tmp/rabbitmq/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf &amp;&amp; echo '' &gt;&gt; /etc/rabbitmq/rabbitmq.conf;
          cp /tmp/rabbitmq/enabled_plugins /etc/rabbitmq/enabled_plugins
      volumes:
      - name: rabbitmq-config
        configMap:
          name: rabbitmq-config
          optional: false
          items:
          - key: enabled_plugins
            path: &quot;enabled_plugins&quot;
          - key: rabbitmq.conf
            path: &quot;rabbitmq.conf&quot;
      # read-write volume into which to copy the rabbitmq.conf and enabled_plugins files
      # this is needed since the docker image writes to the rabbitmq.conf file
      # and Kubernetes Config Maps are mounted as read-only since Kubernetes 1.9.4
      - name: rabbitmq-config-rw
        emptyDir: {}
      - name: rabbitmq-data
        persistentVolumeClaim:
          claimName: rabbitmq-data
      serviceAccount: rabbitmq
      # The Docker image runs as the `rabbitmq` user with uid 999 
      # and writes to the `rabbitmq.conf` file
      # The security context is needed since the image needs
      # permission to write to this file. Without the security 
      # context, `rabbitmq.conf` is owned by root and inaccessible
      # by the `rabbitmq` user
      securityContext:
        fsGroup: 999
        runAsUser: 999
        runAsGroup: 999
      containers:
      - name: rabbitmq
        # Community Docker Image
        image: rabbitmq:latest
        volumeMounts:
        # mounting rabbitmq.conf and enabled_plugins
        # this should have writeable access, this might be a problem
        - name: rabbitmq-config-rw
          mountPath: &quot;/etc/rabbitmq&quot;
          # mountPath: &quot;/etc/rabbitmq/conf.d/&quot;
          mountPath: &quot;/var/lib/rabbitmq&quot;
        # rabbitmq data directory
        - name: rabbitmq-data
          mountPath: &quot;/var/lib/rabbitmq/mnesia&quot;
        env:
        - name: RABBITMQ_DEFAULT_PASS
          valueFrom:
            secretKeyRef:
              name: rabbitmq-admin
              key: pass
        - name: RABBITMQ_DEFAULT_USER
          valueFrom:
            secretKeyRef:
              name: rabbitmq-admin
              key: user
        - name: RABBITMQ_ERLANG_COOKIE
          valueFrom:
            secretKeyRef:
              name: erlang-cookie
              key: cookie
        ports:
        - name: amqp
          containerPort: 5672
          protocol: TCP
        - name: management
          containerPort: 15672
          protocol: TCP
        - name: prometheus
          containerPort: 15692
          protocol: TCP
        - name: epmd
          containerPort: 4369
          protocol: TCP
        livenessProbe:
          exec:
            # This is just an example. There is no &quot;one true health check&quot; but rather
            # several rabbitmq-diagnostics commands that can be combined to form increasingly comprehensive
            # and intrusive health checks.
            # Learn more at https://www.rabbitmq.com/monitoring.html#health-checks.
            #
            # Stage 2 check:
            command: [&quot;rabbitmq-diagnostics&quot;, &quot;status&quot;]
          initialDelaySeconds: 60
          # See https://www.rabbitmq.com/monitoring.html for monitoring frequency recommendations.
          periodSeconds: 60
          timeoutSeconds: 15
        readinessProbe: # probe to know when RMQ is ready to accept traffic
          exec:
            # This is just an example. There is no &quot;one true health check&quot; but rather
            # several rabbitmq-diagnostics commands that can be combined to form increasingly comprehensive
            # and intrusive health checks.
            # Learn more at https://www.rabbitmq.com/monitoring.html#health-checks.
            #
            # Stage 1 check:
            command: [&quot;rabbitmq-diagnostics&quot;, &quot;ping&quot;]
          initialDelaySeconds: 20
          periodSeconds: 60
          timeoutSeconds: 10
</code></pre>
<p>However my stateful set is not binding, I am getting the following error:</p>
<pre><code>running &quot;VolumeBinding&quot; filter plugin for pod &quot;rabbitmq-0&quot;: pod has unbound immediate PersistentVolumeClaims
</code></pre>
<p>The PVC did not correctly bind to the PV but stays in pending state.</p>
<pre><code>[admin@centos-controller ~]$ kubectl get pvc -n ninegold-rabbitmq
NAME                       STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGE
rabbitmq-data-rabbitmq-0   Pending                                      local-storage   14h
</code></pre>
<p>I have double checked the capacity, accessModes, I am not sure why this is not binding.
My example came from here <a href="https://github.com/rabbitmq/diy-kubernetes-examples/tree/master/gke" rel="nofollow noreferrer">https://github.com/rabbitmq/diy-kubernetes-examples/tree/master/gke</a>, the only changes I have done is to bind my NFS volume.</p>
<p>Any help would be appreciated.</p>

<p>In your YAMLs I found some misconfigurations.</p>
<ol>
<li><code>local-storage</code> class.</li>
</ol>
<p>I assume, you used <a href="https://kubernetes.io/docs/concepts/storage/storage-classes/#local" rel="nofollow noreferrer">Documentation example</a> to create <code>local-storage</code>. There is information that:</p>
<blockquote>
<p>Local volumes do not currently support dynamic provisioning, however a StorageClass should still be created to delay volume binding until Pod scheduling.</p>
</blockquote>
<p>When you want to use <code>volumeClaimTemplates</code>, you will use <a href="https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/" rel="nofollow noreferrer">Dynamic Provisioning</a>. It's well explained in <a href="https://medium.com/@zhimin.wen/persistent-volume-claim-for-statefulset-8050e396cc51" rel="nofollow noreferrer">Medium article</a>.</p>
<blockquote>
<p><strong>PV in StatefulSet</strong></p>
<p>Specifically to the volume part, <code>StatefulSet</code> provides a key named as <code>volumeClaimTemplates</code>. With that, you can request the <code>PVC</code> from the storage class dynamically. As part of your new <code>statefulset</code> app definition, replace the volumes ... The <code>PVC</code> is named as <code>volumeClaimTemplate name + pod-name + ordinal number</code>.</p>
</blockquote>
<p>As <code>local-storage</code> does not support <code>dynamic provisioning</code>, it will not work. You would need to use <code>NFS storageclass</code> with proper provisioner or create <code>PV</code> manually.</p>
<p>Also, when you are using <code>volumeClaimTemplates</code> for each pod it will create <code>Pv</code> and <code>PVC</code>. In addition <code>PVC</code> and <code>PV</code> are bounding in 1:1 relationship. For more details you can check <a href="https://stackoverflow.com/questions/57839938/kubernetes-pvcs-sharing-a-single-pv/57924275">this SO thread</a>.</p>
<ol start="2">
<li>Error <code>unbound immediate PersistentVolumeClaims</code></li>
</ol>
<p>It means that <code>dynamic provisioning</code> didn't work as expected. If you would check <code>kubectl get pv,pvc</code> you would not see any new <code>PV</code>,<code>PVC</code> with name: <code>volumeClaimTemplate name + pod-name + ordinal number</code>.</p>
<ol start="3">
<li><code>claimName: rabbitmq-data</code></li>
</ol>
<p>I assume, in this claim you wanted to mount it to <code>PV</code> created by <code>volumeClaimTemplates</code> but it was not created. Also <code>PV</code> would have name <code>rabbitmq-data-rabbitmq-0</code> for first pod and <code>rabbitmq-data-rabbitmq-1</code> for the second one.</p>
<p>As last part, this article - <a href="https://medium.com/@myte/kubernetes-nfs-and-dynamic-nfs-provisioning-97e2afb8b4a9" rel="nofollow noreferrer">Kubernetes : NFS and Dynamic NFS provisioning</a> might be helpful.</p>
