主要内容
简介
Pod中的数据默认并没有进行持久化,它们会随着Pod的销毁而一同被消灭。 我们都知道,Pod并不总是稳定可靠的,它有可能会被频繁销毁并重建,我们并不希望重要的数据(例如MySQL中的数据)跟着Pod一同被销毁。这就需要引入一种持久的存储系统。
Volume和Persistent Volume
Kubernetes提供了两种储存介质,它们是Volume和Persistent Volume。简单来说,Volume中的数据不能被持久化,Pod销毁,数据消失;而Persistent Volume中的数据则独立于Pod,即使Pod销毁,数据依然可以永久保存,除非你不希望。
注意:Volume的生命周期和Pod一样长,它对应的是Pod,而不是容器。即数据在容器重启过程中依然保留下来,除非Pod被销毁
常用的(Persistent)Volume
除了一些云平台提供的Volume,以下几种Volume类型是最常用的
- emptyDir(非Persistent Volume)
- hostPath (Persistent Volume)
- nfs( Persistent Volume)
emptyDir:和Docker中的的匿名Volume比较类似,当我们指定使用emptyDir作为储存的时候,它会和Pod一起被初始化,并且随着Pod的销毁而销毁。因此,emptyDir比较适合于容器间的临时数据交换。
hostPath:通常是Host主机中的一个目录,数据持久性比emptyDir好,即使Pod被销毁,数据依然存在。hostPath适合需要从文件系统读取配置的Pod,例如Kubernetes的一些核心组件;用于监控的Pod如cAdvisor等。
nfs:网络文件系统,当Pod销毁,只是单纯卸载nfs的挂载点,并不会把数据删除,因此同样可用于数据持久化。
emptyDir和hostPath通常由Host主机提供储存设备,属于内部储存设备,因此Pod对它们有一定的依赖性,而nfs是一种网络文件系统,属于外部储存设备,可以跨网络访问,因此它的依赖性相对来说更小,移植性更好。
使用Volume
.spec.volumes
指定提供的volume类型
.spec.containers.volumeMounts
指定volume在容器中的挂载点
下面我们创建包含两个容器的Pod(vol.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
apiVersion: v1 kind: Pod metadata: name: volume-test spec: containers: - name: busybox1 image: busybox volumeMounts: - name: temp #名称要和volumes字段中的一致 mountPath: /tmp args: - /bin/sh - -c - sleep 30000 - name: busybox2 image: busybox volumeMounts: - name: temp #名称要和volumes字段中的一致 mountPath: /tmp args: - /bin/sh - -c - sleep 30000 volumes: - name: temp #volumeMounts字段使用这个名称引用volume emptyDir: {} |
准备好之后使用kubectl apply -f vol.yaml
命令创建资源。Pod中的两个容器使用的是相同的volume,可以通过下面的命令查看
1 2 3 |
[root@centos7-host2 ~]# docker container inspect k8s_busybox1_volume-test_default_ce517185-d0f1-11e8-89d4-000c296679f3_0 [root@centos7-host2 ~]# docker container inspect k8s_busybox2_volume-test_default_ce517185-d0f1-11e8-89d4-000c296679f3_0 |
返回的结果中关于Mounts的部分信息如下
1 2 3 4 5 6 7 8 9 10 |
"Mounts": [ { "Type": "bind", "Source": "/var/lib/kubelet/pods/ce517185-d0f1-11e8-89d4-000c296679f3/volumes/kubernetes.io~empty-dir/temp", "Destination": "/tmp", "Mode": "", "RW": true, "Propagation": "rprivate" }, |
可见它们确实使用了同一个volume保存数据。
emptyDir的使用相当于执行了docker run -v /tmp
命令。
使用Persistent Volume的两种方式
hostPath和nfs都属于Persistent Volume,可以通过两种方式使用它们
- 方法一:和emptyDir使用相同的方法,即通过
.spec.volumes
和.spec.containers.volumeMounts
- 方法二:依赖于方法一,通过
persistentVolume
和persistentVolumeClaim
关键字,但更灵活
方法一
用hostPath作为例子,把宿主机中的/home/storage目录挂载到容器中。
创建Pod的文件(hostpath.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
apiVersion: v1 kind: Pod metadata: name: hostpath-test spec: containers: - name: busybox image: busybox volumeMounts: - name: storage mountPath: /storage args: - /bin/sh - -c - echo "test file" > /storage/test.txt volumes: - name: storage hostPath: path: /home/storage |
创建Pod并等待它执行完毕,到Pod所在的主机查看/home/storage下是否有test.txt文件。
方法二
方法二使用的是persistentVolume(PV)和persistentVolumeClaim(PVC),那么它们是什么?简单来说persistentVolume用于定义存储设备,而persistentVolumeClaim则用于向已有设备申请存储空间。如图(图片来自网络)
它们带来的好处是职责划分:管理员负责管理储存设备和空间的划分,开发者不需要了解过多的细节,只管申请空间即可。
用nfs来作为例子,master提供nfs储存空间
1 2 3 4 |
[k8s@centos7-server ~]$ showmount -e Export list for centos7-server: /nfsdata * |
注意:kubernetes节点如果要正常挂载nfs,需要安装nfs-utils(centos7)
创建persistentVolume
nfspv.yaml文件的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
apiVersion: v1 kind: PersistentVolume metadata: name: nfspv spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /nfsdata/pv1 server: 192.168.11.3 |
上面的文件创建了一个容量1G的PV。
accessModes
指定了PV的访问模式,可选的模式有
- ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
- ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
- ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点。
persistentVolumeReclaimPolicy
指定了PV的回收策略,可选的策略有
- Retain – 需要管理员手工回收。
- Recycle – 清除 PV 中的数据,效果相当于执行
rm -rf /thevolume/*
。 - Delete – 删除 Storage Provider 上的对应存储资源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
storageClassName
指定了PV的分类,它可以是任意值,只要语义明确即可。
然后就是通过apply命令创建PV
1 2 3 4 5 6 |
[k8s@centos7-server ~]$ kubectl apply -f nfspv.yaml persistentvolume/nfspv created [k8s@centos7-server ~]$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfspv 1Gi RWO Retain Available nfs 3s |
创建PersistentVolumeClaim
PVC的创建比PV稍微简单(nfspvc.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 |
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfspvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: nfs |
storageClassName中的值和PV中的对应
1 2 3 4 5 6 7 8 9 |
[k8s@centos7-server ~]$ kubectl apply -f nfspvc.yaml persistentvolumeclaim/nfspvc created [k8s@centos7-server ~]$ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfspvc Bound nfspv 1Gi RWO nfs 5s [k8s@centos7-server ~]$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfspv 1Gi RWO Retain Bound default/nfspvc nfs 82m |
当PVC创建完成,再次查看PV的状态,已经变为Bound,且已经被nfspvc申请使用。
在Pod中使用储存空间
PVC创建好之后,Pod就可以引用这部分的储存容量(nfspod.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
apiVersion: v1 kind: Pod metadata: name: nfspod spec: containers: - name: mysql image: mysql env: - name: MYSQL_ROOT_PASSWORD value: password volumeMounts: - name: mysqldata mountPath: /var/lib/mysql volumes: - name: mysqldata persistentVolumeClaim: claimName: nfspvc #对应pvc的名称 |
相比起第一种方法而言,这种方法中的volumes
字段没有直接创建储存设备,而是通过persistentVolumeClaim间接使用了我们定义好的储存设备。
如果发现mysql启动失败,提示/var/lib/mysql没有操作权限,请在nfs配置文件/etc/exports中添加no_root_squash
回收PersistentVolume
当储存空间不再需要时,可以通过删除PVC进行回收。
1 2 |
kubectl delete -f nfspvc.yaml |
Kubernetes会根据PV的回收策略判断是否需要删除数据,因为之前我们设置的策略是Retain
,因此数据得以保留,如果是Recycle
,那么数据就会被清除。
删除任何PVC之前记得确保它们没有被引用,否则删除的时候它们的状态一直停留在terminating导致删除失败。
动态PV
动态PV是指使用PVC之前不需要创建PV,而是在PVC申请存储空间的时候自动根据条件创建,也叫做动态供给(Dynamical Provision)。动态供给的基础是StorageClass,详细可参考:
转载请注明:Pure nonsense » Kubernetes数据管理