首先,我想指出您的配置中的一个根本差异。请注意,当您使用您的PersistentVolumeClaim
如您的示例中所定义,您不使用您的nginx-content
PersistentVolume
根本不。您可以通过运行以下命令轻松验证它:
kubectl get pv
on your GKE集群。您会注意到,除了手动创建的nginx-content
PV
,还有另外一个,是根据PVC
你申请的。
请注意,在您的PersistentVolumeClaim
您明确引用的定义default
与您手动创建的存储类无关PV
。实际上即使你完全省略注释:
annotations:
volume.alpha.kubernetes.io/storage-class: default
它将以完全相同的方式工作,即default
无论如何都会使用存储类。使用默认存储类别GKE意思是GCE持久磁盘将用作您的卷配置程序。您可以阅读更多相关内容here https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes#storageclasses:
配置了 gcePersistentDisk 等卷实现
通过 StorageClass 资源。 GKE 为以下对象创建默认 StorageClass
使用标准永久磁盘类型 (ext4) 的您。默认
当 PersistentVolumeClaim 未指定时,使用 StorageClass
存储类名称。您可以替换提供的默认 StorageClass
与你自己的。
但让我们继续解决您所面临的问题。
解决方案:
首先我想强调一下您不必使用任何类似 NFS 的文件系统来实现您的目标.
如果您需要您的PersistentVolume
可用于ReadOnlyMany
mode, 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
支持特定的访问模式或访问模式。请注意,它的形式为a list这意味着您可以提供许多您想要的不同访问模式PV
支持。
基本上就像是在说:“嘿!存储提供商!给我一个支持的卷ReadOnlyMany
mode."您以这种方式请求能够满足您要求的存储。但请记住,你得到的可能比你要求的更多。这也是我们请求时的场景PV
支持ReadOnlyMany
模式在GCP。它为我们创造了一个PersistentVolume
这符合我们列出的要求accessModes
部分但它也支持ReadWriteOnce
模式。虽然我们没有要求也支持的东西ReadWriteOnce
您可能会同意我的观点,即内置支持这两种模式的存储完全满足我们对支持的要求ReadOnlyMany
。基本上这就是它的工作原理。
Your PV
由 GCP 自动配置以响应您的PVC
支持这两个accessModes
如果你没有明确指定Pod
or Deployment
您想要将其安装到的定义只读模式,默认安装在读写 mode.
您可以通过附加到Pod
就能够成功挂载了PersistentVolume
:
kubectl exec -ti pod-name -- /bin/bash
并尝试在已安装的文件系统上写入一些内容。
您收到的错误消息:
"Error 400: RESOURCE_IN_USE_BY_ANOTHER_RESOURCE"
特别关注GCE持久磁盘已经被一个安装了GKE node
in ReadWriteOnce
模式,并且不能被其他人安装node
你的其余部分Pods
已安排。
如果你想把它安装在ReadOnlyMany
mods,您需要在您的Deployment
定义通过添加readOnly: true
中的声明volumes
下的部分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
这仅用于复制已上传到我们的其中之一的数据GKE 节点到我们的目的地PV
.
请注意,预填充PersistentVolume
可以通过多种不同的方式来处理数据。你可以安装在这样的Pod
只有你的PersistentVolume
您将在您的Deployment
并使用获取您的数据curl
or wget
从某个外部位置将其直接保存在您的目的地PV
。由你决定。
在我的示例中,我展示了如何使用额外的方法来做到这一点local https://kubernetes.io/docs/concepts/storage/volumes/#local允许我们安装到我们的体积Pod
a directory
, partition
or disk
(在我的示例中,我使用一个目录/var/tmp/test
位于我的 GKE 节点之一)可在我们的 kubernetes 节点之一上使用。它的解决方案比hostPath
因为我们不必关心这样的安排Pod
到包含数据的特定节点。具体的节点亲和力规则已经定义在PersistentVolume
and Pod
自动调度到特定节点上。
要创建它,我们需要三件事:
StorageClass
:
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
这仅用于从我们的复制数据GKE node to our GCE持久磁盘.
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
只需运行:
cp /mnt/source/* /mnt/destination/
就这样。现在我们可以exit
并删除我们的临时Pod
:
kubectl delete pod mypod
一旦它消失了,我们就可以应用我们的Deployment
和我们的PersistentVolume
最后可以安装在readOnly
模式由所有Pods
位于各个GKE 节点:
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
顺便提一句。如果您同意您的事实Pods
仅在一个特定节点上调度,您可以放弃使用GCE持久磁盘根本并切换到上面提到的local https://kubernetes.io/docs/concepts/storage/volumes/#local体积。这样你所有的Pods
不仅可以读取它,还可以同时写入它。唯一需要注意的是所有这些Pods
将在单个节点上运行。