<p>For example in the following example:</p>

<pre><code>apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: exmaple-pvc
spec:
  accessModes:
    - ReadOnlyMany
    - ReadWriteMany
  storageClassName: standard
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
</code></pre>

<p>Why is this allowed? What is the actual behavior of the volume in this case? Read only? Read and write?</p>

Chris Stryczynski
<p>To be able to fully understand why a certain structure is used in a specific field of <code>yaml</code> definition, first we need to understand the purpose of this particular field. We need to ask what it is for, what is its function in this particular <strong>kubernetes api-resource</strong>.</p>
<p>I struggled a bit finding the proper explanation of <code>accessModes</code> in <code>PersistentVolumeClaim</code> and I must admit that <a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes" rel="nofollow noreferrer">what I found</a> in <strong>official kubernetes docs</strong> did not safisfy me:</p>
<blockquote>
<p>A <code>PersistentVolume</code> can be mounted on a host in any way supported by
the resource provider. As shown in the table below, providers will
have different capabilities and each PV’s access modes are set to the
specific modes supported by that particular volume. For example, NFS
can support multiple read/write 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>
<p>Fortunately this time I managed to find really great explanation of this topic in <a href="https://docs.openshift.com/dedicated/storage/understanding-persistent-storage.html#pv-access-modes_understanding-persistent-storage" rel="nofollow noreferrer">OpenShift documentation</a>. We can read there:</p>
<blockquote>
<p>Claims are matched to volumes with similar access modes. The only two
matching criteria are access modes and size. A claim’s access modes
represent a request. Therefore, you might be granted more, but never
less. 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.</p>
<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>
<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><strong>And now probably the most important part:</strong></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>
<p>I emphasized this part as <code>AccessModes</code> can be very easily misunderstood. Let's look at the example:</p>
<pre><code>apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: exmaple-pvc-2
spec:
  accessModes:
  - ReadOnlyMany
  storageClassName: standard
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
</code></pre>
<p>The fact that we specified in our <code>PersistentVolumeClaim</code> definition only <code>ReadOnlyMany</code> access mode doesn't mean it cannot be used in other <code>accessModes</code> supported by our storage provider. It's important to understand that we cannot put here any constraint on how the requested storage can be used by our <code>Pods</code>. If our storage provider, hidden behind our <code>standard</code> storage class, supports also <code>ReadWriteOnce</code>, it will be also available for use.</p>
<p><strong>Answering your particular question...</strong></p>
<blockquote>
<p>Why is this allowed? What is the actual behavior of the volume in this
case? Read only? Read and write?</p>
</blockquote>
<p>It doesn't define behavior of the volume at all. The volume will behave according to its <strong>capabilities</strong> (we don't define them, they are imposed in advance, being part of the storage specification). In other words we will be able to use it in our <code>Pods</code> in all possible ways, in which it is allowed to be used.</p>
<p>Let's say our <code>standard</code> storage provisioner, which in case of <strong>GKE</strong> happens to be <strong>Google Compute Engine Persistent Disk</strong>:</p>
<pre><code>$ kubectl get storageclass
NAME                 PROVISIONER            AGE
standard (default)   kubernetes.io/gce-pd   10d
</code></pre>
<p>currently supports two <code>AccessModes</code>:</p>
<ul>
<li><code>ReadWriteOnce</code></li>
<li><code>ReadOnlyMany</code></li>
</ul>
<p>So we can use all of them, no matter what we specified in our claim e.g. this way:</p>
<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: debian
  template:
    metadata:
      labels:
        app: debian
    spec:
      containers:
      - name: debian
        image: debian
        command: ['sh', '-c', 'sleep 3600']
        volumeMounts:
         - mountPath: &quot;/mnt&quot;
           name: my-volume
           readOnly: true
      volumes:
      - name: my-volume
        persistentVolumeClaim:
          claimName: example-pvc-2
      initContainers:
      - name: init-myservice
        image: busybox
        command: ['sh', '-c', 'echo &quot;Content of my file&quot; &gt; /mnt/my_file']
        volumeMounts:
         - mountPath: &quot;/mnt&quot;
           name: my-volume
</code></pre>
<p>In the above example <strong>both capabilities are used</strong>. First our volume is mounted in <code>rw</code> mode by the <code>init container</code> which saves to it some file and after that it is mounted to the <code>main container</code> as read-only file system. We are still able to do it even though we specified in our <code>PersistentVolumeClaim</code> only one access mode:</p>
<pre><code>spec:
  accessModes:
  - ReadOnlyMany
</code></pre>
<p>Going back to the question you asked in the title:</p>
<blockquote>
<p>Why can you set multiple accessModes on a persistent volume?</p>
</blockquote>
<p><strong>the answer is:</strong> You cannot set them at all as they are already set by the storage provider, you can only request this way what storage you want, what requirements it must meet and one of these requirements are access modes it supports.</p>
<p>Basically by typing:</p>
<pre><code>spec:
  accessModes:
    - ReadOnlyMany
    - ReadWriteOnce
</code></pre>
<p>in our <code>PersistentVolulmeClaim</code> definition we say:</p>
<p><em>&quot;Hey! Storage provider! Give me a volume that supports this set of <code>accessModes</code>. I don't care if it supports any others, like <code>ReadWriteMany</code>, as I don't need them. Give me something that meets my requirements!&quot;</em></p>
<p>I believe that further explanation why <em>an array</em> is used here is not needed.</p>
