为什么可以在持久卷上设置多个访问模式?

Chr*_*ski 5 kubernetes

例如在以下示例中:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: exmaple-pvc
spec:
  accessModes:
    - ReadOnlyMany
    - ReadWriteMany
  storageClassName: standard
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
Run Code Online (Sandbox Code Playgroud)

为什么这是允许的?在这种情况下,卷的实际行为是什么?只读?读和写?

mar*_*rio 6

为了能够完全理解为什么在特定的yaml定义领域中使用某种结构,首先我们需要了解这个特定领域的目的。我们需要问它是做什么的,它在这个特定的kubernetes api-resource 中的功能是什么。

我努力找到了对accessModesin的正确解释,PersistentVolumeClaim我必须承认官方 kubernetes 文档中发现内容并没有让我满意:

APersistentVolume可以以资源提供者支持的任何方式挂载在主机上。如下表所示,提供者将具有不同的能力,并且每个 PV 的访问模式被设置为该特定卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能会在服务器上以只读形式导出。每个 PV 都有自己的一组访问模式来描述该特定 PV 的功能。

幸运的是,这次我设法在openshift 文档中找到了对这个主题的非常好的解释。我们可以在那里阅读:

声明与具有类似访问模式的卷相匹配。仅有的两个匹配标准是访问模式和大小。声明的访问模式代表一个请求。因此,您可能会获得更多,但绝不会更少。例如,如果声明请求 RWO,但唯一可用的卷是 NFS PV (RWO+ROX+RWX),则该声明将匹配 NFS,因为它支持 RWO。

总是首先尝试直接匹配。卷的模式必须匹配或包含比您请求的更多的模式。大小必须大于或等于预期的大小。如果两种类型的卷(例如 NFS 和 iSCSI)具有相同的访问模式集,则它们中的任何一个都可以将声明与这些模式匹配。卷类型之间没有排序,也无法选择一种类型而不是另一种类型。

所有具有相同模式的卷被分组,然后按大小排序,从最小到最大。活页夹获取具有匹配模式的组,并按大小顺序迭代每个组,直到一个大小匹配。

现在可能是最重要的部分:

AccessModes 是卷功能的描述符。它们不是强制约束。存储提供程序负责因无效使用资源而导致的运行时错误。

我强调了这部分,因为AccessModes很容易被误解。让我们看一下这个例子:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: exmaple-pvc-2
spec:
  accessModes:
  - ReadOnlyMany
  storageClassName: standard
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
Run Code Online (Sandbox Code Playgroud)

我们在PersistentVolumeClaim定义中指定onlyReadOnlyMany访问模式的事实并不意味着它不能用于accessModes我们的存储提供商支持的其他模式。重要的是要理解,我们不能在这里对我们的Pods. 如果我们的存储提供程序隐藏在我们的standard存储类后面,也支持ReadWriteOnce,那么它也可以使用。

回答您的特定问题...

为什么这是允许的?在这种情况下,卷的实际行为是什么?只读?读和写?

它根本没有定义卷的行为。卷将根据其功能运行(我们没有定义它们,它们是预先强加的,是存储规范的一部分)。换句话说,我们将能够以我们Pods允许使用的所有可能方式使用它。

假设我们的standard存储配置器,在GKE 的情况下恰好是Google Compute Engine Persistent Disk

$ kubectl get storageclass
NAME                 PROVISIONER            AGE
standard (default)   kubernetes.io/gce-pd   10d
Run Code Online (Sandbox Code Playgroud)

目前支持两种AccessModes

  • ReadWriteOnce
  • ReadOnlyMany

因此,无论我们在声明中指定了什么,我们都可以使用它们,例如:

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: "/mnt"
           name: my-volume
           readOnly: true
      volumes:
      - name: my-volume
        persistentVolumeClaim:
          claimName: example-pvc-2
      initContainers:
      - name: init-myservice
        image: busybox
        command: ['sh', '-c', 'echo "Content of my file" > /mnt/my_file']
        volumeMounts:
         - mountPath: "/mnt"
           name: my-volume
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,使用了两种功能。首先我们的卷被挂载到rw模式中,init container它保存了一些文件,然后它被挂载到main container只读文件系统。即使我们PersistentVolumeClaim只指定了一种访问模式,我们仍然可以这样做:

spec:
  accessModes:
  - ReadOnlyMany
Run Code Online (Sandbox Code Playgroud)

回到你在标题中提出的问题:

为什么可以在持久卷上设置多个访问模式?

答案是:您根本无法设置它们,因为它们已经由存储提供商设置,您只能通过这种方式请求您想要的存储、它必须满足的要求以及这些要求之一是它支持的访问模式。

基本上通过键入:

spec:
  accessModes:
    - ReadOnlyMany
    - ReadWriteOnce
Run Code Online (Sandbox Code Playgroud)

在我们的PersistentVolulmeClaim定义中,我们说:

“嘿!存储提供商!给我一个卷支持这套accessModes我不在乎。它是否支持任何其他的像ReadWriteMany,因为我不需要他们给我的东西,符合我的要求!”

我相信这里不需要进一步解释为什么使用数组


Din*_*esh 0

持久卷可以由不同节点上的多个 Pod 同时挂载。一个 Pod 一次只能以一种访问模式挂载持久卷,其他 Pod 可以以不同的访问模式挂载相同的持久卷。但 Pod 只能使用一种访问模式挂载持久卷。

为那些不理解该问题的人提供的文档参考:持久卷访问模式