【本文目标】
- Kubernetes集群怎样通过Volume做数据持久化的?
- 持久卷组件 -
Persistemt Volume
- 使用持久卷,组件 -
Persistent Volume Claim
- 在使用持久卷中想要自动创建持久卷,组件 -
Storage Class
【前置文章】
- 【k8s学习】Kubernetes学习——核心组件和架构
- 【k8s学习】minikube、kubectl、yaml配置文件的介绍
- 【k8s学习】在minikube上布署MongoDB和MongoExpress
- 【k8s学习】kubernetes namespace介绍
- 【k8s学习】Kubernetes Ingress介绍
- 【k8s学习】Kubernetes打包工具Helm介绍
1. Volume使用场景
1.1 Use Case-1:mysql Pod需要Storage:
假设我们有个项目叫my-app,接连了另一个Pod叫mysql,如果mysql重启了,那么里面存放的数据也会丢失,原因是Kubernetes并没有提供在Pod之外的持久化,一旦Pod重启了,数据就丢失了。
-
Storage that doesn't depend on the pod lifecycle
:我们需要在Pod外有存储数据,以便不受Pod重启的影响。 -
Storage must be available on all nodes
:假设一个mysql Pod挂掉了,那么admin controller manager发现后,就会让scheduler再找合适的Node重新创建一个Pod,所以新的Pod有可能创建在活着的Worker Node中的任一一个,即这个存储要对所有的节点都可见。 -
Storage needs to survive even if cluster crashes
:当所有的节点都挂了,Storage里的数据也不能丢失。
1.2 Use Case-2:my-app本身可能也需要读写文件
比如一些session或是额外的配置等信息,my-app Pod本身,也可能会读写数据,这时候我们就可以配置Persistent Volume
,简称pv。
2. Persistent Volume
官网:https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/
2.1 介绍
-
a cluster resource
:集群中的一种资源,比如ram内存或是cpu。 -
created via YAML file
:和别的组件一样,可以通过YAML文件创建。- 创建的时候kind为
PersistentVolume
。 - spec中定义了一些自有的属性,比如占有空间为多少?(
spec.capacity.storage
)
- 创建的时候kind为
-
Needs actual physical storage
:持久化的地方必须是能支持存储的地方,如集群里的某个存储空间或是集群外的某台Server或是云服务器。所以这里有个问题就是如何让Kubernetes集群读取到这些存储。 -
what type of storage do you need? need to create & manage them by yourself
:Persistent Volume更像是一个接口,它只提供了一些规范,至于存储的类型以及创建和管理、备份,都在Kubernetes之外,并不归K8s集群管理。
2.2 yaml配置示例
下述示例中的Storage的地方是NFS文件系统:
apiVersion:
kind: persistentVolume
metadata:
name: pv-name
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessMode:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.0
nfs:
path: /dir/path/on/nfs/server
server: nfs-server-ip-address
上述spec中定义了三部分:
- 存储能力
- 额外的信息比如进入的模式
- nfs参数
不同的存储类型,配置可能会长不一样。
从官网上可以看到,卷的类型超过了20种:https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
Persistent Volume并不从属于某个命令空间,它是全局的组件
。即所有的命名空间下的组件,都可引用到该pv组件。
2.3 Local Volume vs. Remote Volume
根据存放地点分类:
-
Local Volume
(在Kubernetes集群内),这种Storage就违反了1.1章的特点2和特点3,即它是跟集群中的某个Node绑定了,所以有可能会挂掉,以及如果集群down了,这个Storage也可能down掉。正因为此,像DB数据库的持久化存储,最好放在集群外,即Remove Volume中。 -
Remote Volume
,即集群外部存储,符合1.1章节的三个特点。
什么时候创建Persistent Volume?
如果某个Pod依赖于pv,那么这个pv需要在Pod被创建之前创建。
谁来创建?
一般来说,开发人员需要告诉admin(可能是DevOps Team)某个项目需要用到Persistent Volume,然后DevOps人员根据开发人员的需求,在Kubernetes集群中帮忙定义并创建好了该pv。
在定义好之后,开发人员则需要在具体的Pod的yaml中定义引用该pv,在yaml中声明需要用到某个pv,这时候需要另一个组件,叫Persistent Volume Claim
,简称pvc
。
3. Persistent Volume Claim
官网:
- https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/#binding
- https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
3.1 Persistent Volume Claim yaml示例
pvc如何找到pv?通过属性例如大小等找到合适的pv:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-name
spec:
storageClassName: manual
volumeMode: Filesystem
accessMode:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
定义了pvc后,怎么在Pod中引用呢?即通过spec.volumes.persistenceVolumeClaim.claimName
进行关联:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: pvc-name
【整个过程】
Pod通过pv claim请求volume
--> pv claim尝试在集群中找到合适的volume
--> 找到的volume才是真正拥有存储空间的地方。
--> 这时候volume会被mounted(挂载)到这个Pod
--> 然后才被挂载到Pod中的Container(这也是为什么上述Container中定义了volumeMounts属性)
--> 至此,具体的app应用才能读写该volume
pvc并不是全局的组件,它可以被创建到某个namespace下,pvc所属的namespace必须要和Pod相同(因为Pod定义中需要引用到pvc组件)。
3.2 思考:为什么需要这么多层抽像?
- DevOps人员声明并创建全局组件
pv
。 - 开发人员声明并创建
pvc
,并在Pod中使用。
这样设计的主要好处是开发人员友好,因为开发人员并不需要具体知道Storage存放地点(解藕),而只需要使用即可。
3.3 通过spec.volumes引用ConfigMap和Secret
ConfigMap
组件和Secret
组件:
-
local volumes
:这两个组件都是本地存储卷。 -
not created via pv and pvc
:不是通过pv和pvc声明创建的。 managed by Kubernetes
我们也可以通过volume属性定义这两个组件,然后在container中mounts,以下是示例:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: busybox-container
image: busybox
volumeMounts:
- name: config-dir
mountPath: /etc/config
volumes:
- name: config-dir
configMap:
name: bb-configmap
注:一个Pod可以有多个volume claim。
4. Storage Class
官网:https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/
为了让pv创建以及pvc创建更加高效,则需要第三个组件,叫Storage Class
,简称sc。
sc可以根据PersistentVolumeClaim的定义,动态的生成pv。
示例:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: storage-class-name
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
iopsPerGB: "10"
fsType: ext4
-
via "provisioner" attribute
:provisioner意思为供应方,声明了pv的具体提供商,每个Storage类型都有自己的provisioner,在需要的时候查阅官网:https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#provisioner -
configure "parameters" for storage we want to request for Persistent Volume
:parameters属性定义了pv所需要的信息,例如类型,空间大小等。
sc主要是为了减少DevOps的工具,即可以动态的生成pv,那么谁来引入sc组件呢?答案很明显,是pvc。即开发人员不需要每次让DevOps的人手动创建pv,而是通过Storage Class来自动创建pv。
在pvc中使用:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
spec:
accessMode:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: storage-class-name
【整个过程】
-
Pod
通过pvc
请求存储。 -
pvc
通过sc
请求存储。 -
sc
自动创建可以满足要求的pv
。
参考:
https://www.youtube.com/watch?v=X48VuDVv0do