k8s中对存储的抽象
本篇介绍内容主要有VolumePersistenceVolumePersistentVolumeClaimPVC与PV的绑定Volume容器中的文件系统是不持久的,在容器中运行一些复杂的应用可能导致某些问题:第一,当容器崩溃,kubelet会重启它,但容器内的文件已经丢失了,因为每次当容器重启的时候,容器会以一个“干净”的初始状态启动。第二,当一组容器在同一个Pod上运行的时候,他...
本篇介绍内容主要有
- Volume
- PersistenceVolume
- PersistentVolumeClaim
- PV的提供方式(Provisioning)
- PVC与PV的绑定
- 示例:使用PVC
Volume
容器中的文件系统是不持久的,在容器中运行一些复杂的应用可能导致某些问题:第一,当容器崩溃,kubelet会重启它,但容器内的文件已经丢失了,因为每次当容器重启的时候,容器会以一个“干净”的初始状态启动。第二,当一组容器在同一个Pod上运行的时候,他们通常需要共享一些文件。k8s的Volume是为了解决这些问题而作的一个抽象。
On-disk files in a Container are ephemeral, which presents some problems for non-trivial applications when running in Containers. First, when a Container crashes, kubelet will restart it, but the files will be lost - the Container starts with a clean state. Second, when running Containers together in a Pod it is often necessary to share files between those Containers. The Kubernetes Volume abstraction solves both of these problems.
https://kubernetes.io/docs/concepts/storage/volumes/#background
Volume的生命周期跟Pod是一样的,所以Volume比任何在Pod中运行的容器的启动时间都早,所以当容器启动的时候,Volume就已经准备好了,当容器崩溃重启的时候,Volume也不会丢失。
k8s内置了许多Volume的类型:
- awsElasticBlockStore
- azureDisk
- nfs
- emptyDir
- hostPath
- nfs
- …
完整列表可以查看官方文档。
k8s通过一组抽象接口——CSI(Container Storage Interface) 与不同类型的“存储卷”进行通信,内置的Volume类型不仅包含像NFS这样的标准网络文件系统,还集成了许多云平台的存储服务,比如aws亚马逊云,GCE(Google Compute Engine)谷歌云等。这一组抽象的接口叫 。
换句话说,只要实现了CSI接口,就可以以Volume的方式被k8s所管理,比如阿里云,腾讯云,华为云等等的云存储卷均可以用k8s来管理(前提是要实现CSI接口)。
示例
在minikube环境下,以hostPath
为例,hostPath
表示将Volume挂载在Node节点上的文件系统上。
创建test-pd.yaml
文件:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: nginx:1.7.9
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
该配置文件表示将容器中的/test-pd
路径挂载到Node的目录/data
。
创建Pod:
$ kubectl create -f test-pd.yaml
pod "test-pd" created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
test-pd 0/1 ContainerCreating 0 14s
接下来验证一下:
查看Node主机上的/data
目录:
$ ls /data
minikube
验证Pod中/test-pd
中的内容是否跟Node中/data
目录的内容一致:
$ kubectl exec -it test-pd /bin/bash
root@test-pd:/# ls /test-pd
minikube
目录一致,说明Volume已经正确挂载了。
PersistenceVolume (PV)
通过上述的例子我们发现:Volume是定义在Pod上的,属于Pod——“计算资源”的一部分。而实际上,“网络资源”应当是相对于独立于“计算资源的”而存在的一种实体资源。
k8s提供PersistenceVolume来将“计算资源”和“网络资源”进行解耦。
PV跟Node一样都是k8s集群中的一种资源。PV与Volume很类似,但有以下区别:
- PV只能是网络存储(区别于上述的hostPath本地存储),不属于任何Node,但可以在每个Node上访问。
- PV并不是定义在Pod上的,而是独立于Pod之外定义。
- PV的生命周期与Pod是独立的。
示例
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
这个PV表示了一个使用NFS文件系统的,大小为5G的存储资源。
如果某个Pod想申请某种类型的PV,则首先需要定义一个PersistentVolumeClaim(PVC)。
关于accessModes
的一些定义:
- ReadWriteOnce – 该Volume只能被挂载在一个节点上,读写权限。
- ReadOnlyMany – 该Volume可以被挂载在多个节点上,只读权限。
- ReadWriteMany – 该Volume只能被挂载在多个节点上,读写权限。
PersistentVolumeClaim (PVC)
PVC是用户对“存储资源”(PV)的一种请求,它跟Pod类似。Pod消费Node资源,而PVC消费PV资源。对于用户而言,PVC屏蔽了Volume的一些细节——用户通过PVC请求具体大小和特定的access-mode的PV资源,而不需要关心底层Volume到底是哪一种类型。
但不同的Volume类型在使用上还是有一定差异,比如某些Volume类型是存储介质是SSD(固态硬盘),某些Volume类型的存储介质可能只是机械硬盘,所以对于用户来说,还需要对这些Volume做一个分类,而不能仅仅通过Volume的大小和access-mode来请求资源,毕竟请求到一块SSD硬盘和一块机械硬盘的区别还是很大的。
k8s提供StorageClass
资源来处理这个问题:集群管理员可以根据Volume的类型,划分出不同的StorageClass
类别,让用户自由选择。比如:StorageClass=ssd
的表示SSD,StorageClass=hhd
的表示机械硬盘。用户在请求PV的时候带上所需的StorageClass
,就可以获取到匹配的Volume了。
示例
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}
PV的提供方式(Provisioning)
一共有两种提供PV的方式:静态(static)或者动态(dynamic)。
静态
集群管理员通过预先分配的方式,创建一些PV资源。
动态
当PVC请求PV资源的时候,由集群动态生成PV资源。这种分配方式是基于StorageClass
的:PVC必须带StorageClass
来请求动态生成的PV资源。同时,也需要对应的Volume类型能支持动态分配。
PVC与PV的绑定
PVC跟PV是一个一对一的绑定关系,当PV跟PVC绑定之后,才能被Pod引用。
每当新建一个PVC的时候,k8s都会尝试寻找一个符合条件的PV(静态或动态)与之绑定,这种绑定关系是一对一的。一旦绑定成功,PVC能够得到满足其最小要求的PV资源,也有可能得到超过预期的资源。
如果没有任何一个PV能够满足PVC的需求,则该PVC会一直处于未绑定状态,直到找到可用的PV与之绑定。
比如:一个提供50G存储容量的PV不能与一个请求100G的PVC绑定。当一个至少包含100G存储容量的PV被创建出来之后,PVC才会与之绑定。
示例
通过一个示例来说明一下PV和PVC的绑定过程:
- 创建一个1G的PV,监控其绑定状态。
- 创建一个请求2G的PVC,监控其绑定状态。
- 创建一个2G的PV。
打开三个控制台,分别为c1
,c2
,c3
。
在c1
控制台创建1G的PV:
# 1g-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: 1g-pv
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
hostPath:
# 本地测试路径
path: /test
创建并监控PV的状态变化:
$ kubectl create -f 1g-pv.yaml
persistentvolume "1g-pv" created
$ get pv 1g-pvc -w
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
1g-pv 1Gi RWO Recycle Available slow 1m
在c2
控制台创建请求2G的PVC:
# 2g-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: 2g-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 2Gi
storageClassName: slow
创建并监控状态:
$ kubectl create -f 2g-pvc.yaml
persistentvolumeclaim "2g-pvc" created
$ kubectl get pvc 2g-pvc -w
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
2g-pvc Pending slow 1m
至此,我们创建了一个1G的PV,一个请求2G资源的PVC,由于1G的PV并不能满足2G的PVC的请求,所以此时该PV和PVC还未有绑定关系:
//c1控制台,1g-pv处于Available状态
$ kubectl get pv 1g-pv -w
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
1g-pv 1Gi RWO Recycle Available slow 1m
//c2控制台,2g-pvc处于Pending状态
$ kubectl get pvc 2g-pvc -w
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
2g-pvc Pending slow 1m
接下来在c3
控制台创建2G的PV:
# 2g-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: 2g-pv
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
hostPath:
# 本地测试路径
path: /test
创建并且查看状态:
//c3控制台
$ create -f 2g-pv.yaml
persistentvolume "2g-pv" created
$ kubectl get pv 2g-pv -w
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
2g-pv 2Gi RWO Recycle Available slow 5s
2g-pv 2Gi RWO Recycle Available default/2g-pvc slow 9s
2g-pv 2Gi RWO Recycle Bound default/2g-pvc slow 9s
可以看到2g的PV创建出来没多久,就被绑定到2g-pvc上了。
同样的可以查看c2
控制台:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
2g-pvc Pending slow 5s
2g-pvc Pending 2g-pv 0 slow 27s
2g-pvc Bound 2g-pv 2Gi RWO slow 27s
2g-pvc
已经跟2g-pv
绑定上了。
由于1G的PV资源还是处于“无人认领”状态,所以查看c1
控制台,发现1g-pv
的状态是没有发生变化的:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
1g-pv 1Gi RWO Recycle Available slow 30s
示例:使用PVC
Pod通过定义PVC来请求PV资源,下面通过一个例子加以说明。
创建test-pv.yaml
,test-pvc.yaml
,test-po.yaml
文件,内容如下:
# test-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: test-pv
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
hostPath:
# 本地测试路径
path: /test
# test-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 5Gi
storageClassName: slow
# test-po.yaml
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx:1.7.9
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
创建PV/PVC/POD:
$ kubectl create -f test-po.yaml
pod "mypod" created
$ kubectl create -f test-pv.yaml
persistentvolume "test-pv" created
$ kubectl create -f test-pvc.yaml
persistentvolumeclaim "myclaim" created
通过查询得到pod的IP地址是172.17.0.5,用curl
验证是否绑定成功:
$ echo "hello word" > test.html
$ curl 172.17.0.5/test.html
hello word
更多推荐
所有评论(0)