<p>Our platform which runs on K8s has different components. We need to share the storage between two of these components (comp-A and comp-B) but by mistake, we defined the PV and PVC for that as <code>ReadWriteOnce</code> and even when those two components were running on different nodes everything was working and we were able to read and write to the storage from both components.</p>
<p>Based on the K8s docs the <code>ReadWriteOnce</code> can be mounted to one node and we have to use <code>ReadWriteMany</code>:</p>
<ul>
<li>ReadWriteOnce -- the volume can be mounted as read-write by a single node</li>
<li>ReadOnlyMany -- the volume can be mounted read-only by many nodes</li>
<li>ReadWriteMany -- the volume can be mounted as read-write by many nodes&quot;</li>
</ul>
<p>So I am wondering why everything was working fine while it shouldn't?</p>
<p>More info:
We use NFS for storage and we are not using dynamic provisioning and below is how we defined our pv and pvc (we use helm):</p>
<pre class="lang-yaml prettyprint-override"><code>- apiVersion: v1
  kind: PersistentVolume
  metadata:
    name: gstreamer-{{ .Release.Namespace }}
  spec:
    capacity:
      storage: 10Gi
    accessModes:
      - ReadWriteOnce
    persistentVolumeReclaimPolicy: Recycle
    mountOptions:
      - hard
      - nfsvers=4.1
    nfs:
      server: {{ .Values.global.nfsserver }}
      path: /var/nfs/general/gstreamer-{{ .Release.Namespace }}

- apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
    name: gstreamer-claim
    namespace: {{ .Release.Namespace }}
  spec:
    volumeName: gstreamer-{{ .Release.Namespace }}
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 10Gi
</code></pre>
<h2>Update</h2>
<p>The output of some kubectl commands:</p>
<pre class="lang-sh prettyprint-override"><code>$ kubectl get -n 149 pvc
NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
gstreamer-claim   Bound    gstreamer-149                              10Gi       RWO                           177d


$ kubectl get -n 149 pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                       STORAGECLASS   REASON   AGE
gstreamer-149                              10Gi       RWO            Recycle          Bound    149/gstreamer-claim                                                 177d

</code></pre>
<p>I think somehow it takes care of it because the only thing the pods need to do is connecting to that IP.</p>

<p>It's quite misleading concept regarding <code>accessMode</code>, especially in <code>NFS</code>.</p>
<p>In Kubernetes <a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes" rel="noreferrer">Persistent Volume docs</a> it's mentioned that <code>NFS</code> supports all types of Access. <code>RWO</code>, <code>RXX</code> and <code>RWX</code>.</p>
<p>However <code>accessMode</code> is something like <code>matching criteria</code>, same as <code>storage size</code>. It's described better in <a href="https://docs.openshift.com/dedicated/4/storage/understanding-persistent-storage.html#pv-access-modes_understanding-persistent-storage" rel="noreferrer">OpenShift Access Mode documentation</a></p>
<blockquote>
<p>A <code>PersistentVolume</code> can be mounted on a host in any way supported by the resource provider. Providers have different capabilities and each PV’s <code>access modes</code> are set to the specific modes supported by that particular volume. For example, NFS can support multiple <code>read-write</code> clients, but a specific NFS PV might be exported on the server as read-only. Each PV gets its own set of access modes describing that specific PV’s capabilities.</p>
</blockquote>
<blockquote>
<p>Claims are matched to volumes with similar access modes. <strong>The only two matching criteria are access modes and size. A claim’s access modes represent a request.</strong> Therefore, you might be granted more, but never less. <strong>For example, if a claim requests RWO, but the only volume available is an NFS PV (RWO+ROX+RWX), the claim would then match NFS because it supports RWO.</strong></p>
</blockquote>
<blockquote>
<p>Direct matches are always attempted first. The volume’s modes must match or contain more modes than you requested. The size must be greater than or equal to what is expected. If two types of volumes, such as NFS and iSCSI, have the same set of access modes, either of them can match a claim with those modes. There is no ordering between types of volumes and no way to choose one type over another.</p>
</blockquote>
<blockquote>
<p>All volumes with the same modes are grouped, and then sorted by size, smallest to largest. The binder gets the group with matching modes and iterates over each, in size order, until one size matches.</p>
</blockquote>
<p>In the next paragraph:</p>
<blockquote>
<p><strong>A volume’s <code>AccessModes</code> are descriptors of the volume’s capabilities. They are not enforced constraints.</strong> The storage provider is responsible for runtime errors resulting from invalid use of the resource.</p>
</blockquote>
<blockquote>
<p><strong>For example, NFS offers ReadWriteOnce access mode. You must mark the claims as read-only if you want to use the volume’s ROX capability.</strong> Errors in the provider show up at runtime as mount errors.</p>
</blockquote>
<p>Another example is that you can choose a few <code>AccessModes</code> as it is not <strong>constraint</strong> but a <strong>matching criteria</strong>.</p>
<pre><code>$ cat &lt;&lt;EOF | kubectl create -f -
&gt; apiVersion: v1
&gt; kind: PersistentVolumeClaim
&gt; metadata:
&gt;   name: exmaple-pvc
&gt; spec:
&gt;   accessModes:
&gt;     - ReadOnlyMany
&gt;     - ReadWriteMany
&gt;     - ReadWriteOnce
&gt;   resources:
&gt;     requests:
&gt;       storage: 1Gi
&gt; EOF
</code></pre>
<p>or as per GKE example:</p>
<pre><code>$ cat &lt;&lt;EOF | kubectl create -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: exmaple-pvc-rwo-rom
spec:
  accessModes:
    - ReadOnlyMany
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
EOF               
persistentvolumeclaim/exmaple-pvc-rwo-rom created
</code></pre>
<p><strong>PVC Output</strong></p>
<pre><code>$ kubectl get pvc
NAME                  STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
exmaple-pvc           Pending                                                                        standard       2m18s
exmaple-pvc-rwo-rom   Bound     pvc-d704d346-42b3-4090-af96-aebeee3053f5   1Gi        RWO,ROX        standard       6s
persistentvolumeclaim/exmaple-pvc created
</code></pre>
<p><code>exmaple-pvc</code> is in <code>Pending</code> state as default GKE <code>GCEPersistentDisk</code> its not supporting RreadWriteMany.</p>
<pre><code>Warning  ProvisioningFailed  10s (x5 over 69s)  persistentvolume-controller  Failed to provision volume with StorageClass &quot;standard&quot;: invalid AccessModes [ReadOnlyMany ReadWriteMany ReadWr
iteOnce]: only AccessModes [ReadWriteOnce ReadOnlyMany] are supported
</code></pre>
<p>However second pvc <code>exmaple-pvc-rwo-rom</code> were created and you can see it have 2 access mode <code>RWO, ROX</code>.</p>
<p>In short <code>accessMode</code> is more like requirement for PVC/PV to <code>Bind</code>. If <code>NFS</code> which is providing all <code>access modes</code> binds with <code>RWO</code> it fulfill requirement, however it will work as RWM as <code>NFS</code> providing that capability.</p>
<p>Hope it answered cleared a bit.</p>
<p>In addition you can check other <a href="https://stackoverflow.com/questions/57754103/how-to-pre-populate-a-readonlymany-persistent-volume">StackOverflow threads regarding accessMode</a></p>
