如何在多个Pod上安装相同的持久卷?

时间:2020-06-10 17:39:23

标签: kubernetes google-cloud-platform google-kubernetes-engine persistent-volumes persistent-volume-claims

我有一个三节点GCE集群和一个带有三个副本的单容器GKE部署。我这样创建了PV和PVC:

# Create a persistent volume for web content
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-content
  labels:
    type: local
spec:
  capacity:
    storage: 5Gi
  accessModes:
   - ReadOnlyMany
  hostPath:
    path: "/usr/share/nginx/html"
--
# Request a persistent volume for web content
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nginx-content-claim
  annotations:
    volume.alpha.kubernetes.io/storage-class: default
spec:
  accessModes: [ReadOnlyMany]
  resources:
    requests:
      storage: 5Gi

它们在容器规范中被引用如下:

    spec:
      containers:
      - image: launcher.gcr.io/google/nginx1
        name: nginx-container
        volumeMounts:
          - name: nginx-content
            mountPath: /usr/share/nginx/html
        ports:
          - containerPort: 80
      volumes:
      - name: nginx-content
        persistentVolumeClaim:
          claimName: nginx-content-claim

即使我将卷创建为ReadOnlyMany,在任何给定时间也只能安装一个Pod。其余的给出“错误400:RESOURCE_IN_USE_BY_ANOTHER_RESOURCE”。我该如何做,以便所有三个副本从同一卷中读取相同的Web内容?

4 个答案:

答案 0 :(得分:3)

首先,我想指出您的配置中的一个基本差异。请注意,当您使用示例中定义的PersistentVolumeClaim时,根本就不会使用nginx-content PersistentVolume。您可以通过运行以下命令轻松进行验证:

kubectl get pv

在您的 GKE集群上。您会注意到,除了手动创建的nginx-content PV之外,还有另一个是根据您应用的PVC自动进行设置的。

请注意,在您的PersistentVolumeClaim定义中,您明确引用了default存储类,该类与您手动创建的PV无关。实际上,即使您完全省略了注释,也可以:

annotations:
        volume.alpha.kubernetes.io/storage-class: default

它的工作方式完全相同,即无论如何都将使用default存储类。在 GKE 上使用默认存储类别意味着 GCE永久磁盘将用作您的卷配置程序。您可以阅读有关here的更多信息:

已配置诸如gcePersistentDisk之类的卷实现 通过StorageClass资源。 GKE为创建一个默认的StorageClass 您使用标准持久性磁盘类型(ext4)。默认值 当PersistentVolumeClaim未指定存储空间时使用StorageClass StorageClassName。您可以替换提供的默认StorageClass 与你自己的。

但是让我们继续解决您面临的问题。

解决方案:

首先,我想强调您不必使用任何类似NFS的文件系统即可达到目标

如果您需要PersistentVolumeReadOnlyMany模式下可用, GCE永久磁盘是一个完全满足您要求的完美解决方案。

许多ro可以同时以Pods模式安装,许多Pods更为重要的是,它们安排在不同的 GKE nodes。此外,它的配置非常简单,并且可以直接在 GKE 上运行。

如果您想以ReadWriteMany模式使用存储,我同意NFS之类的东西可能是唯一的解决方案,因为 GCE永久磁盘不提供这种功能。

让我们仔细看看我们如何配置它。

我们需要从定义PVC开始。此步骤实际上已经由您自己完成,但是您在后续步骤中迷失了一些。让我解释一下它是如何工作的。

以下配置正确(如我提到的annotations部分可以省略):

# Request a persistent volume for web content
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nginx-content-claim
spec:
  accessModes: [ReadOnlyMany]
  resources:
    requests:
      storage: 5Gi

不过,我想对此添加一条重要的评论。你说:

即使我将卷创建为ReadOnlyMany,也只有一个Pod可以 在任何给定时间安装卷。

好吧,实际上您没有。我知道这似乎有些棘手,有些令人惊讶,但这并不是定义accessModes真正起作用的方式。实际上,这是一个被广泛误解的概念。首先,您无法在PVC 中定义访问方式,因为它会放置所需的约束。受支持的访问模式是特定存储类型的固有功能。它们已经由存储提供商定义。

您实际上在PVC定义中所做的是请求一个PV支持特定访问模式的访问。请注意,它采用的是列表的形式,这意味着您可以提供您希望PV支持的许多不同的访问模式。

基本上,这就像说:“嘿!存储提供者!给我一个支持ReadOnlyMany模式的卷。” 您正在用这种方式要求一种满足您要求的存储。但是请记住,您可以得到比要求更多的东西。这也是我们在 GCP 中请求支持PV模式的ReadOnlyMany时的情况。它为我们创建了一个PersistentVolume,它符合我们在accessModes部分中列出的要求,但它也支持ReadWriteOnce模式。尽管我们没有要求也支持ReadWriteOnce的功能,但您可能会同意我的观点,即对这两种模式具有内置支持的存储完全可以满足我们对支持ReadOnlyMany的要求。所以基本上这就是它的工作方式。

由GCP为您的PV自动提供的PVC支持这两个accessModes,如果您未在Pod或{{1 }}的定义,您希望以只读模式挂载它,默认情况下,它以读写模式挂载。

您可以通过将其附加到能够成功装入Deployment的{​​{1}}来轻松地进行验证:

Pod

并尝试在已挂载的文件系统上写一些东西。

您收到的错误消息:

PersistentVolume

特别关注 GCE永久磁盘,该磁盘已经由一个 GKE kubectl exec -ti pod-name -- /bin/bash "Error 400: RESOURCE_IN_USE_BY_ANOTHER_RESOURCE" 模式下安装,而不能由另一个{{ 1}},其余node都安排在此位置。

如果您希望以ReadWriteOnce模式挂载它,则需要在node定义中明确指定它,方法是在Pods部分的{{1} {1}}模板规范如下:

ReadOnlyMany

但是请记住,要能够以Deployment模式挂载它,首先我们需要用数据预填充该卷。否则,您将看到另一条错误消息,提示未格式化的卷不能以只读模式挂载。

最简单的方法是创建一个readOnly: true,该volumes仅用于将已经上传到我们的 GKE节点之一的数据复制到目标{{1} }。

请注意,可以用许多不同的方式来预填充Pod's数据。您可以仅将apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 volumeMounts: - mountPath: "/usr/share/nginx/html" name: nginx-content volumes: - name: nginx-content persistentVolumeClaim: claimName: nginx-content-claim readOnly: true 装入要在readOnly中使用的Pod中,并使用PVPersistentVolume从外部位置保存中获取数据它直接在您的目的地Pod上。由你决定。

在我的示例中,我演示了如何使用额外的local卷来执行此操作,该卷允许我们将PersistentVolumeDeployment或{{1 }}(在我的示例中,我使用位于我的一个GKE节点上的目录curl)在我们的kubernetes节点之一上可用。它比wget更加灵活,因为我们不必关心将PV调度到包含数据的特定节点。已在Pod中定义了特定的节点关联性规则,并且directory已自动安排在特定节点上。

要创建它,我们需要三件事:

partition

disk

/var/tmp/test定义:

hostPath

最后是Pod

PersistentVolume

然后,我们可以创建临时Pod,该临时StorageClass仅用于将数据从 GKE节点复制到我们的 GCE永久磁盘

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

您在上面看到的路径并不是很重要。 PersistentVolume的任务只是允许我们将数据复制到目标apiVersion: v1 kind: PersistentVolume metadata: name: example-pv spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: path: /var/tmp/test nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - <gke-node-name> 。最终,我们的PersistentVolumeClaim将被安装在完全不同的路径上。

创建apiVersion: v1 kind: PersistentVolumeClaim metadata: name: myclaim spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 10Gi storageClassName: local-storage 并成功挂载两个卷后,我们可以通过运行以下命令将其附加:

Pod

只需运行apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: myfrontend image: nginx volumeMounts: - mountPath: "/mnt/source" name: mypd - mountPath: "/mnt/destination" name: nginx-content volumes: - name: mypd persistentVolumeClaim: claimName: myclaim - name: nginx-content persistentVolumeClaim: claimName: nginx-content-claim

Pod

仅此而已。现在我们可以PV并删除我们的临时PV了:

Pod

一旦它消失了,我们就可以应用kubectl exec -ti my-pod -- /bin/bash 了,我们的Pod最后可以通过位于各种 GKE上的所有cp /mnt/source/* /mnt/destination/ exit方式安装节点

Pod

顺便说一句。如果您确定kubectl delete pod mypod 仅安排在一个特定节点上,那么您完全可以放弃使用 GCE永久磁盘并切换到上述{{3 }}卷。这样,您所有的Deployment不仅可以读取它,还可以同时对其进行写入。唯一的警告是所有这些PersistentVolume将在单个节点上运行。

答案 1 :(得分:1)

您可以使用类似NFS的文件系统来实现。在Google Cloud上,Filestore是适合此产品的产品(由NFS管理)。您有教程here用于实现配置

答案 2 :(得分:0)

如果要跨不同节点共享卷并提供高度可扩展的解决方案,则需要使用ReadWriteMany(RWX)类型的共享卷声明。就像使用NFS服务器一样。

您可以在此处了解如何部署NFS服务器:

https://www.shebanglabs.io/run-nfs-server-on-ubuntu-20-04/

然后您可以按以下方式装载卷(来自NFS服务器的目录):

https://www.shebanglabs.io/how-to-set-up-read-write-many-rwx-persistent-volumes-with-nfs-on-kubernetes/

我已经使用这种方式在+8个k8s部署(+200个pod)之间交付共享的静态内容,通过Nginx每月服务10亿个请求。它确实与NFS设置完美配合:)

答案 3 :(得分:0)

Google提供了类似NFS的文件系统,称为Google Cloud Filestore。您可以将其安装在多个Pod上。