kubernetes | Volume & PVC 和 PV
2022年3月17日 · 6078 字 · 13 分钟 · Kubernetes
一、Volume
1.1、Volume 概述
Volume 是 Pod 中能够被多个容器访问的共享目录。Kubernetes 的 Volume 定义在 Pod 上, 它被一个 Pod 中的多个容器挂载到具体的文件目录下。Volume 与 Pod 的生命周期相同, 但与容器的生命周期不相关,当容器终止或重启时,Volume 中的数据也不会丢失。要使用 volume,pod 需要指定 volume 的类型和内容,和映射到容器的位置。
Kubernetes 支持多种类型的 Volume,包括:emptyDir、hostPath、gcePersistentDisk、 awsElasticBlockStore、nfs、iscsi、flocker、glusterfs、rbd、cephfs、gitRepo、 secret、persistentVolumeClaim、downwardAPI、azureFileVolume、azureDisk、 vsphereVolume、Quobyte、PortworxVolume、ScaleIO。
1.2、EmptyDir
emptyDir 类型的 volume 在 pod 分配到 node 上时被创建,kubernetes 会在 node 上自动分配一个目录,因此无需指定宿主机 node 上对应的目录文件。这个目录的初始内容为空,一旦这个 pod 离开了这个宿主机,EmptyDir 中的数据就会被永久删除。所以目前 EmptyDir 类型的 volume 主要用作临时空间,比如 Web 服务器写日志或者 tmp 文件需要的临时目录。
多容器(Sidecar)共享存储案例。
点击查看完整的
emptydir.ymlapiVersion: apps/v1
kind: Deployment
metadata:
name: test-volume-deployment
namespace: default
labels:
app: test-volume-deployment
spec:
selector:
matchLabels:
app: test-volume-pod
template:
metadata:
labels:
app: test-volume-pod
spec:
containers:
- name: nginx-writer-a
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
- containerPort: 443
name: https
volumeMounts:
- mountPath: /data/
name: empty
command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
- name: os-writer-b
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /data/
name: empty
command: ['/bin/sh','-c','while true;do echo "busybox" >> /data/index.html;sleep 2;done']
volumes:
- name: empty
emptyDir: {}
验证:
kubectl exec -it <pod-name> -c nginx-writer-a -- tail -f /data/index.html
kubectl exec -it <pod-name> -c os-writer-b -- tail -f /data/index.html
1.3、hostPath
hostPath 类型则是映射 node 文件系统中的文件或者目录到 pod 里。在使用 hostPath 类型的存储卷时,也可以设置 type 字段,支持的类型有文件、目录、File、Socket、CharDevice 和 BlockDevice。
HostPath 属性的 volume 使得对应的容器能够访问当前宿主机上的指定目录。例如,需要运行一个访问 Docker 系统目录的容器,那么就使用 /var/lib/docker 目录作为一个 HostDir 类型的 volume;或者要在一个容器内部运行 CAdvisor,那么就使用 /dev/cgroups 目录作为一个 HostDir 类型的 volume。一旦这个 pod 离开了这个宿主机,HostDir 中的数据虽然不会被永久删除,但数据也不会随 pod 迁移到其他宿主机上。因此,需要注意的是, 由于各个宿主机上的文件系统结构和内容并不一定完全相同,所以相同 pod 的 HostDir 可 能会在不同的宿主机上表现出不同的行为。
点击查看完整的
hostpath.ymlapiVersion: v1
kind: Pod
metadata:
name: vol-hostpath
namespace: default
spec: # 指定所提供的存储卷
volumes:
- name: html
hostPath:
path: /data/pod/volume1/ # 这是指 K8s 宿主机(Node) 上的真实路径。
type: DirectoryOrCreate # 如果宿主机上还没有 /data/pod/volume1/ 这个目录,K8s 会自动帮你创建它(权限设为 0755)。
containers:
- name: myapp
image: nginx
# 指定所提供的存储卷
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/ # 这是 容器内部 的路径。
注意事项:
- Node 绑定风险:这是最大的问题。如果你的集群有多个节点(Node A 和 Node B),Pod 这次运行在 Node A,数据存在 A 上。如果下次 Pod 被调度到了 Node B,它会发现挂载目录是空的,因为它找不到 A 上的数据。
- 权限问题:容器内的程序通常以非 root 用户运行,可能没有权限读写宿主机上的目录,除非手动调整宿主机的文件夹权限。
- 安全性:允许 Pod 访问宿主机文件系统存在安全隐患。如果 Pod 被攻破,攻击者可能会通过挂载卷访问宿主机的关键配置文件。
hostPath 非常适合单节点集群(如 Minikube) 或 需要读取 Node 本机配置(如日志收集器、监控插件)的场景。如果是跨节点的生产业务,建议下一步了解 PV (PersistentVolume) 和 PVC (PersistentVolumeClaim)。
1.4、nfs
NFS 使得我们可以挂载已经存在的共享到我们的 Pod 中,和 emptyDir 不同的是,当 Pod 被删除时,emptyDir 也会被删除。但是 nfs 不会被删除,仅仅是解除挂载状态而已,这就意味着 NFS 能够允许我们提前对数据进行处理,而且这些数据可以在 Pod 之间相互传递,并且 nfs 可以同时被多个 pod 挂在并进行读写。
1、所有节点上安装 NFS
yum install nfs-utils.x86_64 -y
2、配置 NFS
点击查看完整配置
[root@kubernetes-master-001 nfs]# mkdir -p /nfs/v {1..5}
[root@kubernetes-master-001 nfs]# cat > /etc/exports <<EOF
/nfs/v1 172.16.0.0/16 (rw,no_root_squash)
/nfs/v2 172.16.0.0/16 (rw,no_root_squash)
/nfs/v3 172.16.0.0/16 (rw,no_root_squash)
/nfs/v4 172.16.0.0/16 (rw,no_root_squash)
/nfs/v5 172.16.0.0/16 (rw,no_root_squash)
EOF
[root@kubernetes-master-001 nfs]# exportfs -arv
exporting 172.16.0.0/16:/nfs/v5
exporting 172.16.0.0/16:/nfs/v4
exporting 172.16.0.0/16:/nfs/v3
exporting 172.16.0.0/16:/nfs/v2
exporting 172.16.0.0/16:/nfs/v1
[root@kubernetes-master-001 nfs]# showmount -e
Export list for kubernetes-master-001:
/nfs/v5 172.16.0.0/16
/nfs/v4 172.16.0.0/16
/nfs/v3 172.16.0.0/16
/nfs/v2 172.16.0.0/16
/nfs/v1 172.16.0.0/16
点击查看完整的
nfs.ymlkind: Deployment
apiVersion: apps/v1
metadata:
name: nfs # 定义了这个 Deployment 资源 在当前命名空间(Namespace)下的名字。
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html/
name: nfs
volumes:
- name: nfs
nfs:
path: /nfs/v1 # NFS 服务器上共享出来的真实路径
server: 192.168.12.71 # NFS 服务器 IP 地址
[root@kubernetes-master-01 ~]# kubectl get pods -l app=nginx # -l:是 --selector 的缩写。
NAME READY STATUS RESTARTS AGE
nfs-5f56db5995-9shkg 1/1 Running 0 24s
nfs-5f56db5995-ht7ww 1/1 Running 0 24s
[root@kubernetes-master-01 ~]# echo "index" > /nfs/v1/index.html
[root@kubernetes-master-01 ~]# kubectl exec -it nfs-5f56db5995-ht7ww -- bash
root@nfs-5f56db5995-ht7ww:/# cd /usr/share/nginx/html/
root@nfs-5f56db5995-ht7ww:/usr/share/nginx/html# ls
index.html
NFS 类型 volume。允许一块现有的网络硬盘在同一个 pod 内的容器间共享。
点击查看完整的
nfs.ymlapiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: redis
spec:
selector:
matchLabels:
app: redis
revisionHistoryLimit: 2 # 规定了 Kubernetes 为这个 Deployment 保留多少个旧版本的 ReplicaSet(即版本历史)
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis
imagePullPolicy: IfNotPresent # 应用的内部端口
ports:
- containerPort: 6379
name: redis6379
env:
- name: ALLOW_EMPTY_PASSWORD
value: "yes"
- name: REDIS_PASSWORD
value: "redis"
volumeMounts:
- name: redis-persistent-storage
mountPath: /data
volumes:
- name: redis-persistent-storage
nfs:
path: /k8s-nfs/redis/data
server: 192.168.126.112
# 进入 Pod 查看挂载目录
kubectl exec -it redis -- ls -l /data
# 测试写入数据
kubectl exec -it redis -- redis-cli -a redis set k8s_test "hello"
二、 PVC 和 PV
2.1、基本概念
管理存储是管理计算的一个明显问题。该 PersistentVolume 子系统为用户和管理员提供了一个 API,用于抽象如何根据消费方式提供存储的详细信息。为此,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。
PersistentVolume(PV)是集群中由管理员配置的一段网络存储。 它是集群中的资源,就像节点是集群资源一样。 PV 是容量插件,如 Volumes,但其生命周期独立于使用 PV 的任何单个 pod。 此 API 对象捕获存储实现的详细信息,包括 NFS,iSCSI 或特定于云提供程序的存储系统。PersistentVolumeClaim(PVC)是由用户进行存储的请求。 它类似于 pod。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以一次读 / 写或多次只读)。
虽然 PersistentVolumeClaims 允许用户使用抽象存储资源,但是 PersistentVolumes 对于不同的问题,用户通常需要具有不同属性(例如性能)。群集管理员需要能够提供各种 PersistentVolumes 不同的方式,而不仅仅是大小和访问模式,而不会让用户了解这些卷的实现方式。对于这些需求,有 StorageClass 资源。
StorageClass 为管理员提供了一种描述他们提供的存储的 “类” 的方法。 不同的类可能 映射到服务质量级别,或备份策略,或者由群集管理员确定的任意策略。 Kubernetes 本 身对于什么类别代表是不言而喻的。 这个概念有时在其他存储系统中称为 “配置文件”。PVC 和 PV 是一一对应的。
2.2、生命周期
PV 是群集中的资源。PVC 是对这些资源的请求,并且还充当对资源的检查。PV 和 PVC 之间的相互作用遵循以下生命周期:Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling
供应准备 Provisioning:通过集群外的存储系统或者云平台来提供存储持久化支持。- 静态提供 Static:集群管理员创建多个 PV。 它们携带可供集群用户使用的真实存储的 详细信息。 它们存在于 Kubernetes API 中,可用于消费。
- 动态提供 Dynamic:当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试为 PVC 动态配置卷。 此配置基于 StorageClasses:PVC 必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。
绑定 Binding:用户创建 pvc 并指定需要的资源和访问模式。在找到可用 pv 之前,pvc 会保持未绑定状态。使用 Using:用户可在 pod 中像 volume 一样使用 pvc。释放 Releasing:用户删除 pvc 来回收存储资源,pv 将变成 “released” 状态。由于还保留着之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他 pvc 使用。回收 Recycling:pv 可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。- 保留策略:允许人工处理保留的数据。
- 删除策略:将删除 pv 和外部关联的存储资源,需要插件支持。
- 回收策略:将执行清除操作,之后可以被新的 pvc 使用,需要插件支持。
PV 的访问模式(accessModes)
ReadWriteOnce(RWO)可读可写,但只支持被单个节点挂载。ReadOnlyMany(ROX)只读,可以被多个节点挂载。ReadWriteMany(RWX)多路可读可写。这种存储可以以读写的方式被多个节点共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是 NFS。在 PVC 绑定 PV 时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。
PV 的回收策略(persistentVolumeReclaimPolicy)
Retain不清理,保留 Volume(需要手动清理)Recycle删除数据,即 rm -rf /thevolume/*(只有 NFS 和 HostPath 支持)Delete删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)
PV 的状态
Available可用。Bound已经分配给 PVC。ReleasedPVC 解绑但还未执行回收策略。
2.3、PV 类型
GCEPersistentDisk
AWSElasticBlockStore
AzureFile
AzureDisk
FC (Fibre Channel)
Flexvolume
Flocker
NFS
iSCSI
RBD (Ceph Block Device)
CephFS
Cinder (OpenStack block storage)
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath (Single node testing only – local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
Portworx Volumes
ScaleIO Volumes
StorageOS
2.4、PV 卷阶段状态
Available资源尚未被 claim 使用Bound卷已经被绑定到 claim 了Releasedclaim 被删除,卷处于释放状态,但未被集群回收。Failed卷自动回收失败
2.5、创建 PV
(1)第一步:编写 yaml 文件,并创建 pv
创建 5 个 pv,存储大小各不相同,是否可读也不相同 pv.yaml。
点击查看完整的
pv.ymlapiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
name: pv001
spec:
nfs: # 定义了底层的物理存储指向
path: /data/volumes/v1 # server: nfs 被共享出来的那个文件夹路径
server: nfs # “文件服务器”或者“NAS 存储”。要求集群内必须能解析名为 nfs 的主机名,或者建议直接改回 IP 地址。
accessModes: ["ReadWriteMany","ReadWriteOnce"] # 访问模式 (RWO): 卷可以被一个节点以读写方式挂载。(RWX): 卷可以被多个节点以读写方式挂载(NFS 天然支持这种模式,非常适合多副本共享数据)
capacity:
storage: 2Gi # 定义了该存储卷的大小
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/volumes/v2
server: nfs
accessModes: ["ReadWriteOnce"]
capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/volumes/v3
server: nfs
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv004
labels:
name: pv004
spec:
nfs:
path: /data/volumes/v4
server: nfs
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels:
name: pv005
spec:
nfs:
path: /data/volumes/v5
server: nfs
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 15Gi # kubernetes 的标准单位是 Gi(二进制千兆字节)。建议统一写成 15Gi 以避免识别问题。
[root@kubernetes-master-001 ~]# kubectl apply -f pv.yaml
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
(3)第三步:查询验证
[root@kubernetes-master-001 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 2Gi RWO,RWX Retain Available 3m12s
pv002 5Gi RWO Retain Available 3m11s
pv003 20Gi RWO,RWX Retain Available 3m11s
pv004 10Gi RWO,RWX Retain Available 3m11s
pv005 15Gi RWO,RWX Retain Available 3m10s
调度逻辑
PV 一旦创建,就会进入 Available 状态。当有一个 PVC 请求(例如请求 8Gi 存储且模式为 RWX)时,K8s 会进行筛选:
1、pv001 (2Gi) -> 太小,跳过。
2、pv002 (5Gi) -> 模式不匹配(只有 RWO),跳过。
3、pv004 (10Gi) -> 匹配! 绑定成功。
注意:如果匹配到了 20Gi 的 pv003,剩下的 10Gi 空间也就“浪费”了,因为一个 PV 只能绑定一个 PVC。
NFS Server 连通性
配置里 server: nfs。如果这是一个外部服务器,请确保每个 Node 节点的 /etc/hosts 里有 nfs 的解析,或者直接使用 IP。
server: nfs 就是指存数据的物理机器在哪里。它不在 K8s 集群的“控制”范围内,它是一个外部的、提供磁盘空间的“服务商”。
2.6、创建 PVC
1、编写 yaml 文件,创建一个 pvc,需要 6G 存储;所以不会匹配 pv001、pv002、pv003,pvc.yaml。
点击查看完整的
pvc.ymlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default # PV 是集群级别的(不属于任何空间),但 PVC 是属于特定命名空间的。
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 6Gi
---
apiVersion: v1
kind: Pod
metadata:
name: vol-pvc
namespace: default
spec:
volumes:
- name: html
persistentVolumeClaim:
claimName: mypvc # 指向上面定义的 PVC 名字
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
[root@kubernetes-master-001 ~]# kubectl apply -f pvc.yaml
persistentvolumeclaim/mypvc created
pod/vol-pvc created
3、查询验证
[root@kubernetes-master-001 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound pv004 10Gi RWO,RWX 91s
[root@kubernetes-master-001 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 2Gi RWO,RWX Retain Available 20m
pv002 5Gi RWO Retain Available 20m
pv003 20Gi RWO,RWX Retain Available 20m
pv004 10Gi RWO,RWX Retain Bound default/mypvc 20m
pv005 15G RWO,RWX Retain Available 20m
[root@kubernetes-master-001 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
vol-pvc 1/1 running 0 11m
[root@kubernetes-master-001 ~]# curl 10.244.2.117 # NFS 服务器的网页内容
<h1>NFS stor 04</h1>
系统通常会选择满足条件的最小那个 PV。在这种情况下,mypvc 很有可能会与 pv004 (10Gi) 绑定。
2.7、StorageClass
在一个大规模的 Kubernetes 集群里,可能有成千上万个 PVC,这就意味着运维人员必须实现创建出这个多个 PV,此外,随着项目的需要,会有新的 PVC 不断被提交,那么运维人员就需要不断的添加新的,满足要求的 PV,否则新的 Pod 就会因为 PVC 绑定不到 PV 而导致创建失败。而且通过 PVC 请求到一定的存储空间也很有可能不足以满足应用对于存储设备的各种需求,而且不同的应用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等,为了解决这一问题,Kubernetes 又为我们引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可以将存储资源定义为某种类型的资源,比如快速存储、慢速存储等,kubernetes 根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了。
定义 StorageClass
每一个存储类都包含 provisioner、parameters 和 reclaimPolicy 这三个参数域,当一个属于某个类的 PersistentVolume 需要被动态提供时,将会使用上述的参数域。
# 下载 helm
wget https://get.helm.sh/helm-v3.3.4-linux-amd64.tar.gz
# 解压
tar xf helm-v3.3.4-linux-amd64.tar.gz
# 安装
mv linux-amd64/helm/usr/local/bin/
# 验证
helm version
# 添加阿里云镜像仓库
helm repo add ali-stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
# 添加官方仓库
helm repo add stable https://kubernetes-charts.storage.googleapis.com/
# 添加微软云 helm 仓库
helm repo add azure http://mirror.azure.cn/kubernetes/charts/
# 下载 nfs
helm pull stable/nfs-client-provisioner
# 解压安装包
tar xf nfs-client-provisioner-1.2.11.tgz && cd nfs-client-provisioner/
# 修改配置文件 values.yaml
# 安装 nfs client
helm install nfs ./
# 使用 -f 参数指定你的配置文件
helm install nfs-storage ./nfs-client-provisioner -f my-values.yaml
点击查看完整的
values.yml# nfs-client-provisioner values.yaml
nfs:
# 必填:NFS 服务器的 IP 地址或主机名
server: 192.168.12.71
# 必填:NFS 服务器上共享的导出目录
path: /data/nfs/dynamic
# 挂载参数,通常保持默认即可
mountOptions:
storageClass:
# 存储类的名字,以后在 PVC 的 storageClassName 字段就写这个
name: nfs-storage
# 是否将此存储类设置为集群默认的存储类。写 PVC 时不写 storageClassName,系统会自动动用这个 NFS 存储。
defaultClass: true
# 回收策略:Delete (删除 PVC 时同时删除 NFS 上的数据)
# 或 Retain (保留数据,需手动清理)
reclaimPolicy: Delete
# 是否允许 PVC 创建后扩容(需底层存储支持,NFS 通常支持)
allowVolumeExpansion: true
# 归档模式:如果设为 true,删除 PVC 时数据会被重命名备份而非直接删除。NFS 上的文件夹会加上 archived- 前缀保留下来,而不是被彻底抹除。
archiveOnDelete: false
rbac:
# 必填:必须创建 RBAC 角色,否则 Provisioner 没有权限在集群内创建 PV
create: true
# 镜像配置
image:
repository: quay.io/external_storage/nfs-client-provisioner
tag: v3.1.0-k8s1.11
pullPolicy: IfNotPresent
# 资源限制,防止 Provisioner 占用过多系统资源
resources:
limits:
cpu: 100m # 1.0 CPU = 1 核 = 1000m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
# 如果你的 Node 节点有特殊污点,需要设置容忍度
tolerations: []
# 节点亲和性设置
nodeSelector: {}
运行案例
点击查看完整的
storage.ymlkind: PersistentVolumeClaim
apiVersion: v1
metadata:
namespace: default
name: test-nfs
labels:
app: test-nfs
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-storage # NFS 服务器的共享目录下创建一个子目录(名字通常类似 default-test-nfs-pvc-xxxx)
resources:
requests:
storage: 8Gi
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: test-nfs-storageclass
namespace: default
labels:
app: test-nfs
spec:
selector:
matchLabels:
app: test-nfs
template:
metadata:
labels:
app: test-nfs
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /usr/share/nginx/html
name: test-nfs
volumes:
- name: test-nfs
persistentVolumeClaim:
claimName: test-nfs # 指向了名为 test-nfs 的 PVC
验证:
[root@kubernetes-master-001 helm]# vim storage.yml
[root@kubernetes-master-001 helm]# kubectl apply -f storage.yml
persistentvolumeclaim/test-nfs created
deployment.apps/test-nfs-storageclass created
[root@kubernetes-master-001 helm]# kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/test-nfs Bound pvc-cf0c8175-f145-438a-ba5c-35effc080231 8Gi RWX nfs-client 7s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-cf0c8175-f145-438a-ba5c-35effc080231 8Gi RWX Delete Bound default/test-nfs nfs-client 6s
[root@kubernetes-master-001 helm]# ll /nfs/v1
total 4
drwxrwxrwx 2 root root 4096 Oct 16 09:56 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231
编写一个 index.html 测试网络存储:
[root@kubernetes-master-001 helm]# cd /nfs/v1/default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231/
[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# echo "index" > index.html
[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# kubectl get pods -l app=test-nfs
NAME READY STATUS RESTARTS AGE
test-nfs-storageclass-68c8996847-lsxwn 1/1 Running 0 75s
[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# kubectl get pods -l app=test-nfs -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-nfs-storageclass-68c8996847-lsxwn 1/1 Running 0 80s 10.244.0.12 instance-gvpb80ao <none> <none>
[root@kubernetes-master-001 default-test-nfs-pvc-cf0c8175-f145-438a-ba5c-35effc080231]# curl 10.244.0.12
index