Kubernetes 如何在多个POD上装载相同的持久卷?
我有一个三节点的GCE集群和一个带有三个副本的单pod GKE部署。我创建了PV和PVC,如下所示:Kubernetes 如何在多个POD上装载相同的持久卷?,kubernetes,google-cloud-platform,google-kubernetes-engine,persistent-volumes,persistent-volume-claims,Kubernetes,Google Cloud Platform,Google Kubernetes Engine,Persistent Volumes,Persistent Volume Claims,我有一个三节点的GCE集群和一个带有三个副本的单pod 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: - Rea
# 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\u IN\u由另一个\u资源使用”。如何使这三个副本从同一卷读取相同的web内容?您可以使用类似NFS的文件系统实现这一点。在谷歌云上,Filestore是这方面的合适产品(NFS管理)。您有一个实现配置的教程首先,我想指出配置中的一个基本问题。请注意,当使用示例中定义的
PersistentVolumeClaim
时,根本不使用nginx内容。您可以通过运行以下命令轻松验证:
kubectl get pv
kubectl exec -ti my-pod -- /bin/bash
在您的GKE集群上。您会注意到,除了手动创建的nginx内容
PV
,还有一个内容是根据您应用的PVC
自动设置的
请注意,在您的PersistentVolumeClaim
定义中,您明确地引用了默认的存储类,它与手动创建的PV
无关。实际上,即使您完全忽略了注释:
annotations:
volume.alpha.kubernetes.io/storage-class: default
它将以完全相同的方式工作,即无论如何都将使用default
存储类。在GKE上使用默认存储类意味着GCE持久磁盘将用作卷资源调配器。您可以阅读更多关于它的信息:
已配置卷实现,如gcePersistentDisk
通过StorageClass资源。GKE为创建默认的StorageClass
您可以选择使用标准持久磁盘类型(ext4)的磁盘。默认值
当PersistentVolumeClaim未指定
StorageClassName。您可以替换提供的默认StorageClass
用你自己的
但是,让我们继续讨论您面临的问题的解决方案
解决方案:
首先,我想强调的是,您不必使用任何类似NFS的文件系统来实现您的目标
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
如果您需要PersistentVolume
在ReadOnlyMany
模式下可用,GCE Persistent Disk是完全满足您需求的完美解决方案
它可以由多个pod
同时以ro
模式安装,更重要的是,可以由多个pod
安装在不同的GKE节点上。此外,它的配置非常简单,可以在开箱即用的GKE上运行
如果您想在ReadWriteMany
模式下使用存储,我同意像NFS这样的东西可能是唯一的解决方案,因为GCE持久磁盘不提供这种功能
让我们仔细看看如何配置它
我们需要从定义我们的PVC
开始。这一步实际上已经由你自己完成了,但你在进一步的步骤中迷失了一点。让我解释一下它是如何工作的
以下配置是正确的(如我所述,注释
部分可以省略):
不过,我想补充一点重要的意见。你说:
尽管我创建的卷是现成的,但只有一个pod可以
在任何给定时间装入卷
嗯,实际上你没有。我知道这看起来有点棘手,也有点令人惊讶,但这并不是定义accessModes
的真正方式。事实上,这是一个被广泛误解的概念。首先,您不能在PVC
中定义访问模式,这意味着要在那里设置所需的约束。支持的访问模式是特定存储类型的固有特征。它们已由存储提供程序定义
您在PVC
定义中实际执行的操作是请求支持特定访问模式的PV
。请注意,它是一种列表形式,这意味着您可以提供许多不同的访问模式,您希望您的PV
支持这些模式
基本上就像说:“嘿!存储提供商!给我一个支持ReadOnlyMany
模式的卷。”你这样问是为了一个能满足你需求的存储。但是请记住,你可以得到比你要求的更多的东西。这也是我们在请求在GCP中支持ReadOnlyMany
模式的PV
时的场景。它为我们创建了一个PersistentVolume
,它满足了我们在accessModes
部分中列出的要求,但它还支持ReadWriteOnce
模式。虽然我们没有要求提供同时支持ReadWriteOnce
的存储,但您可能会同意我的观点,即内置支持这两种模式的存储完全满足了我们对支持ReadOnlyMany
的存储的要求。所以基本上这就是它的工作方式
GCP为响应您的PVC
而自动配置的PV
支持这两种accessmode
,如果您没有在Pod
或Deployment
定义中明确指定要在只读模式下装载它,默认情况下,它以读写模式装入
您可以通过连接到能够成功装载PersistentVolume的Pod
来轻松验证它:
kubectl exec -ti pod-name -- /bin/bash
并试图在挂载的文件系统上写一些东西
您将收到以下错误消息:
"Error 400: RESOURCE_IN_USE_BY_ANOTHER_RESOURCE"
特别关注已由一个GKE安装的GCE持久磁盘
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
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>
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 10Gi
storageClassName: local-storage
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
kubectl exec -ti my-pod -- /bin/bash
cp /mnt/source/* /mnt/destination/
kubectl delete pod mypod
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