在Kubernetes中,我们虽然可以使用volume将容器内目录挂载到宿主机目录上,但由于Pod调度的不确定性,这种数据存储方式是不牢靠的。对于有状态的应用,我们希望无论Pod被调度到哪个节点上,它们的数据总能够完整地恢复,这时候我们就不能用volume挂载了,而应该使用“网络共享存储”。PV/PVC就是用于解决问题而存在的,它们屏蔽了底层存储实现的细节,使得我们很容易上手使用。
PV
PersistentVolume(PV)是对底层网络共享存储的抽象,将共享存储定义为一种“资源”,Kubernetes支持的PV类型如下:
| 类型 | 描述 |
|---|---|
| AWSElasticBlockStore | AWS公有云提供的ElasticBlockStore |
| AzureFile | Azure公有云提供的File |
| AzureDisk | Azure公有云提供的Disk |
| CephFS | 一种开源共享存储系统 |
| FC(Fibre Channel) | 光纤存储设备 |
| FlexVolume | 一种插件式的存储机制 |
| Flocker | 一种开源共享存储系统 |
| GCEPersistentDisk | GCE公有云提供的PersistentDisk |
| Glusterfs | 一种开源共享存储系统 |
| HostPath | 宿主机目录,仅用于单机测试 |
| iSCSI | iSCSI存储设备 |
| Local | 本地存储设备,从Kubernetes 1.7版本引入,到1.14版本时更新为稳定版,目前可以通过指定块(Block)设备提供Local PV,或通过社区开发的sig-storage-local-static-provisioner插件https://github.com/kubernetes-sigs/sigstorage-local-static-provisioner来管理Local PV的生命周期 |
| NFS | 网络文件系统 |
| Portworx Volumes | Portworx提供的存储服务 |
| Quobyte Volumes | Quobyte提供的存储服务 |
| RBD(Ceph Block Device) | Ceph块存储 |
| ScaleIO Volumes | DellEMC的存储设备 |
| StorageOS | StorageOS提供的存储服务 |
| VsphereVolume | VMWare提供的存储系统 |
举个PV配置文件例子:
1 | apiVersion: v1 |
PV支持的accessModes有:
- ReadWriteOnce(RWO):读写权限,并且只能被单个Node挂载。
- ReadOnlyMany(ROX):只读权限,允许被多个Node挂载。
- ReadWriteMany(RWX):读写权限,允许被多个Node挂载。
不同的存储提供者支持的accessModes:
| Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
|---|---|---|---|
| AWSElasticBlockStore | ✓ | - | - |
| AzureFile | ✓ | ✓ | ✓ |
| AzureDisk | ✓ | - | - |
| CephFS | ✓ | ✓ | ✓ |
| Cinder | ✓ | - | - |
| CSI | depends on the driver | depends on the driver | depends on the driver |
| FC | ✓ | ✓ | - |
| FlexVolume | ✓ | ✓ | depends on the driver |
| Flocker | ✓ | - | - |
| GCEPersistentDisk | ✓ | ✓ | - |
| Glusterfs | ✓ | ✓ | ✓ |
| HostPath | ✓ | - | - |
| iSCSI | ✓ | ✓ | - |
| Quobyte | ✓ | ✓ | ✓ |
| NFS | ✓ | ✓ | ✓ |
| RBD | ✓ | ✓ | - |
| VsphereVolume | ✓ | - | - (works when Pods are collocated) |
| PortworxVolume | ✓ | - | ✓ |
| ScaleIO | ✓ | ✓ | - |
| StorageOS | ✓ | - | - |
PV支持的persistentVolumeReclaimPolicy有:
- Retain,不清理, 保留 Volume(需要手动清理)
- Recycle,删除数据,(只有 NFS 和 HostPath 支持)
- Delete,删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)
PV声明周期:
- Available:空闲状态;
- Bound:已经绑定到某个PVC上;
- Released:对应的PVC已经被删除,但资源还没有被集群收回;
- Failed:PV自动回收失败。
PVC
PersistentVolumeClaim(PVC),对存储资源的需求申请,主要包括存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。只有PVC和PV相匹配,才能绑定上。
定义一个PVC配置:
1 | kind: PersistentVolumeClaim |
该PVC声明了需要1Gi存储空间,访问模式为ReadWriteMany,刚刚定义的PV符合这个要求,所以会被绑定上。
实践
因为NFS类型存储演示起来方便,所以这里选择使用NFS作为存储提供者。
在Kubeadm安装Kubernetes1.16.2集群一节中,我们曾在以下虚拟机上搭建了Kubernetes集群:
| 操作系统 | IP | 角色 | CPU核心数 | 内存 | Hostname |
|---|---|---|---|---|---|
| centos7 | 192.168.33.11 | master | 2 | 4096M | master |
| centos7 | 192.168.33.12 | worker | 2 | 4096M | node1 |
| centos7 | 192.168.33.13 | worker | 2 | 4096M | node2 |
为了方便,这里就不再创建新的虚拟机安装NFS,直接在192.168.33.13节点上准备好NFS环境。
在192.168.33.13节点上执行以下bash命令:
1 | # 创建目录 |
exports内容如下所示:
1 | /nfs *(rw,insecure,sync,no_subtree_check,no_root_squash) |
让配置生效:
1 | exportfs -r |
启动NFS:
1 | systemctl enable nfs |
接着在master节点上,创建test-pv-pvc.yml配置文件:
1 | apiVersion: v1 |
上面的配置文件效果可以用下面这张图表示:

主要过程就是busybox通过nfs-pvc绑定了nfs-pv,然后定时将hello world写到容器内部/mnt/index.html文件中,而容器内部/mnt和PV的/nfs目录挂载;nginx也通过nfs-pvc绑定了nfs-pv,将/nfs目录和容器内部/usr/share/nginx/html目录挂载;我们后续可以通过访问浏览器http://192.168.33.11:30000/地址查看效果。
创建该配置文件:

查看192.168.33.13虚拟机/nfs目录下是否已经存在index.html文件,并查看内容:

浏览器访问http://192.168.33.11:30000/:

说明整个流程没问题。

