# Kubernetes存储卷 我们知道默认情况下容器的数据都是非持久化的,在容器消亡以后数据也跟着丢失,所以Docker提供了Volume机制以便将数据持久化存储。类似的,Kubernetes提供了更强大的Volume机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。 ## Volume 目前,Kubernetes支持以下Volume类型: - emptyDir - hostPath - gcePersistentDisk - awsElasticBlockStore - nfs - iscsi - flocker - glusterfs - rbd - cephfs - gitRepo - secret - persistentVolumeClaim - downwardAPI - azureFileVolume - vsphereVolume - flexvolume 注意,这些volume并非全部都是持久化的,比如emptyDir、secret、gitRepo等,这些volume会随着Pod的消亡而消失。 ## PersistentVolume 对于持久化的Volume,PersistentVolume (PV)和PersistentVolumeClaim (PVC)提供了更方便的管理卷的方法:PV提供网络存储资源,而PVC请求存储资源。这样,设置持久化的工作流包括配置底层文件系统或者云数据卷、创建持久性数据卷、最后创建claim来将pod跟数据卷关联起来。PV和PVC可以将pod和数据卷解耦,pod不需要知道确切的文件系统或者支持它的持久化引擎。 ### PV PersistentVolume(PV)是集群之中的一块网络存储。跟 Node 一样,也是集群的资源。PV 跟 Volume (卷) 类似,不过会有独立于 Pod 的生命周期。比如一个NFS的PV可以定义为 ```yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv0003 spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: path: /tmp server: 172.17.0.2 ``` PV的访问模式有三种: * 第一种,ReadWriteOnce:是最基本的方式,可读可写,但只支持被单个Pod挂载。 * 第二种,ReadOnlyMany:可以以只读的方式被多个Pod挂载。 * 第三种,ReadWriteMany:这种存储可以以读写的方式被多个Pod共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。 ### StorageClass 上面通过手动的方式创建了一个NFS Volume,这在管理很多Volume的时候不太方便。Kubernetes还提供了[StorageClass](https://kubernetes.io/docs/user-guide/persistent-volumes/#storageclasses)来动态创建PV,不仅节省了管理员的时间,还可以封装不同类型的存储供PVC选用。 GCE的例子: ```yaml kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: slow provisioner: kubernetes.io/gce-pd parameters: type: pd-standard zone: us-central1-a ``` Ceph RBD的例子: ```yaml apiVersion: storage.k8s.io/v1beta1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/rbd parameters: monitors: 10.16.153.105:6789 adminId: kube adminSecretName: ceph-secret adminSecretNamespace: kube-system pool: kube userId: kube userSecretName: ceph-secret-user ``` ### PVC PV是存储资源,而PersistentVolumeClaim (PVC) 是对PV的请求。PVC跟Pod类似:Pod消费Node的源,而PVC消费PV资源;Pod能够请求CPU和内存资源,而PVC请求特定大小和访问模式的数据卷。 ```yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: myclaim spec: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi selector: matchLabels: release: "stable" matchExpressions: - {key: environment, operator: In, values: [dev]} ``` PVC可以直接挂载到Pod中: ```yaml kind: Pod apiVersion: v1 metadata: name: mypod spec: containers: - name: myfrontend image: dockerfile/nginx volumeMounts: - mountPath: "/var/www/html" name: mypd volumes: - name: mypd persistentVolumeClaim: claimName: myclaim ``` ## emptyDir 如果Pod配置了emptyDir类型Volume, Pod 被分配到Node上时候,会创建emptyDir,只要Pod运行在Node上,emptyDir都会存在(容器挂掉不会导致emptyDir丢失数据),但是如果Pod从Node上被删除(Pod被删除,或者Pod发生迁移),emptyDir也会被删除,并且永久丢失。 ```yaml apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: gcr.io/google_containers/test-webserver name: test-container volumeMounts: - mountPath: /test-pd name: test-volume volumes: - name: test-volume hostPath: # directory location on host path: /data ``` ## 其他Volume说明 ### hostPath hostPath允许挂载Node上的文件系统到Pod里面去。如果Pod有需要使用Node上的文件,可以使用hostPath。 ```yaml - hostPath: path: /tmp/data name: data ``` ### NFS NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。 ```yaml volumes: - name: nfs nfs: # FIXME: use the right hostname server: 10.254.234.223 path: "/" ``` ### FlexVolume 注意要把volume plugin放到`/usr/libexec/kubernetes/kubelet-plugins/volume/exec//`,plugin要实现`init/attach/detach/mount/umount`等命令(可参考lvm的[示例](https://github.com/kubernetes/kubernetes/tree/master/examples/volumes/flexvolume))。 ```yaml - name: test flexVolume: driver: "kubernetes.io/lvm" fsType: "ext4" options: volumeID: "vol1" size: "1000m" volumegroup: "kube_vg" ```