我们可以简化整个过程。在GKE上,您实际上不需要基于GCE持久磁盘手动创建PV
。您只需要定义适当的PVC
,它可以如下所示:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: webserver-content-claim
spec:
accessModes: [ReadOnlyMany]
resources:
requests:
storage: 5Gi
请注意,在
PVC
中,您不能定义访问模式以限制特定的约束条件。您所做的基本上只是请求支持此特定访问模式的存储。请注意,它是以列表的形式呈现的,这意味着您可以提供许多不同的访问模式,以便您的
PV
支持。我在
此答案中详细解释了这一点。但关键点在于,通过在
PVC
定义中设置
ReadOnlyMany
访问模式,您仅请求支持此类型访问的卷,但这并不意味着它不支持其他模式。
如果您没有像@Ievgen Goichuk建议的那样在
volumes
部分的
Pod
模板中指定
readOnly:true
,则默认情况下会以
rw
模式挂载。由于
GCE Persistent Disk不支持
ReadWriteMany
访问模式,因此其他
Pods
无法挂载已经由一个特定
node
上调度的一个
Pod
以
rw
模式挂载的这种卷。这个
Pod
可以以
rw
模式挂载,是因为
GCE Persistent Disk还支持
ReadWriteOnce
访问模式,根据
官方文档的说法,意味着“该卷可以被一个节点以读写方式挂载”。这就是为什么在其他节点上调度的
Pods
无法挂载它的原因。
但现在让我们转向实际解决方案。
一旦您创建了上述
PVC
,您将看到相应的
PV
也已经被创建(
kubectl get pv
),并且其
STATUS
为
Bound
。
现在我们只需要在开始以
ReadOnlyMany
访问模式使用它之前以某种方式预先填充它。我将分享对我最有效的方法。
如果您已经在您的工作节点的
node-pool中的其中之一上传了数据,则可以跳过下一步。
我假设您已在本地计算机上安装了
gcloud。
gcloud compute scp /local/path instance:/remote/path
这是实现目标的正确方式。如果您遇到“permission denied”错误,这可能意味着您定义的“/remote/path”是某个受限制的目录,作为非root用户,您无法访问该目录。如果您尝试将本地文件系统上的内容复制到远程机器上的“/etc”目录中,则会看到此错误。最安全的方法是将文件复制到您有权限访问的主目录中:
gcloud compute scp --recurse /home/<username>/data/* <instance-name>:~ --zone <zone-name>
如果您想要从源目录复制所有文件和目录及其内容,请使用--recurse
选项。
一旦我们的数据上传到其中一个工作节点,我们需要将其复制到我们新创建的PersistentVolume
中。有几种不同的方法可以实现这一点。
我决定使用一个临时的Pod
,并使用本地卷来完成它。
为了使我们已经存在于一个GKE工作节点上的数据也可用于我们的临时Pod
,让我们创建以下内容:
storage-class-local.yaml
:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
pv-local.yaml
:
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /home/<username>
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- <gke-node-name>
以及pvc-local.yaml
:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 10Gi
storageClassName: local-storage
在下一步中,让我们创建一个临时的
Pod
,它将使我们能够从
node
复制数据,并将其作为本地卷挂载到
Pod
中,然后基于
GCE Persistent Disk
创建
PV
。它的定义可能如下所示:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/mnt/source"
name: local-volume
- mountPath: "/mnt/destination"
name: gce-pd-volume
volumes:
- name: local-volume
persistentVolumeClaim:
claimName: myclaim
- name: gce-pd-volume
persistentVolumeClaim:
claimName: webserver-content-claim
当 Pod
运行时,我们可以通过以下方式连接到它:
kubectl exec -ti mypod -- /bin/bash
复制我们的文件:
cp -a /mnt/source/* /mnt/destination/
现在我们可以删除临时的Pod、本地PV和PVC。我们的
PersistentVolume
已经预先填充了数据,并且可以以
ro
模式挂载。
为了测试它,我们可以运行以下
Deployment
:
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: webserver-content
volumes:
- name: webserver-content
persistentVolumeClaim:
claimName: webserver-content-claim
readOnly: true