2017-05-14 19:39:33 +08:00
# Kubernetes存储卷
2017-05-14 19:08:56 +08:00
我们知道默认情况下容器的数据都是非持久化的, 在容器消亡以后数据也跟着丢失, 所以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/< vendor ~ driver > /< driver > `, 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"
```