ConfigMap、Secret、emptyDir、hostPath等属于临时性存储,当pod被调度到某个节点上时,它们随pod的创建而创建,临时占用节点存储资源,当pod离开节点时,存储资源被交还给节点,pod一旦离开它们就失效,不具备持久化存储数据的能力。与此相反,持久化存储拥有独立的生命周期,具备持久化存储能力,其后端一般是独立的存储系统如NFS、iSCSI、cephfs、glusterfs等
kubernetes存储卷
- 我们知道默认情况下容器的数据都是非持久化的,在容器消亡以后数据也跟着丢失,所以Docker提供了Volume机制以便将数据持久化存储。类似的。
- Kubernetes提供了更强大的Volume机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。
- 与Docker不同,Kubernetes Volume的生命周期与Pod绑定
- 容器挂掉后Kubelet再次重启容器时,Volume的数据依然还在
- 而Pod删除时,Volume才会清理。数据是否丢失取决于具体的Volume类型,比如emptyDir的数据会丢失,而PV的数据则不会丢
NFS
NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。
- NFS安装,所有节点都需要安装
# 安装nfs
yum install -y nfs-utils
# 创建共享目录
mkdir -p /data/nfs
# 赋予权限
chmod 777 -R /data/nfs
- NFS配置-只在共享目录节点设置
# 编辑配置文件
vim /etc/exports
# 新增如下内容
/data/nfs *(rw,no_root_squash)
# 启动nfs
systemctl enable nfs
systemctl restart nfs
PV与PVC
- pv: persistentVolume # 持久卷
- 是集群中由系统管理员配置的一段网络存储。它是集群中的资源,就像node是集群资源一样。PV也是像是Volumes一样的存储插件,但其生命周期独立于使用PV的任何单个Pod。PV配置存储实现的详细信息,包括NFS,iSCSI或特定于云提供程序的存储系统。PV属于集群级别资源,不属于任何的Namespace
- pvc: persistentVolumeClaim # 持久卷声明
- 是使用存储的请求,属于Namespace中的资源。PVC类似于Pod,Pod消耗node资源,PVC消耗PV资源。Pod可以请求特定级别的计算资源(CPU和内存),PVC可以请求特定大小和访问模式的存储资源。
- persistentVolume (PV) 和 PersistentVolumeClaim (PVC) 提供了方便的持久化卷:PV提供网络存储资源,而 PVC 请求存储资源。这样,设置持久化的工作流包括配置底层文件系统或者云数据卷、创建持久性数据卷PV、最后创建 PVC 来将 Pod 跟数据卷关联起来。PV和 PVC 可以将 pod 和数据卷解耦,pod 不需要知道确切的文件系统或者支持它的持久化引擎。
- pv和pvc是一对一绑定的,一旦一个pv和一个pvc完成绑定,除非pvc被删除,否则pv是不可以再被别的pvc绑定使用的
- PV和PVC模式是需要运维人员先创建好PV,然后开发人员定义好PVC进行一对一的Bond
PV【persistentVolume 】持久卷
创建PV
apiVersion: v1
kind: PersistentVolume
# metadata
metadata:
name: mypv
labels:
release: "stable"
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
nfs:
path: /data/nfs/mysql
server: 192.168.0.180
persistentVolumeReclaimPolicy: Recycle
mountOptions:
- hard
- nfsvers=4.1
- tcp
PV的生命周期
PV的生命周期包括5个阶段
- Provisioning,即PV的创建,可以直接创建PV(静态方式),也可以使用StorageClass动态创建
- Binding,将PV分配给PVC
- Using,Pod通过PVC使用该Volume
- Releasing,Pod释放Volume并删除PVC
- Reclaiming,回收PV,可以保留PV以便下次使用,也可以直接从存储中删除
PV的状态
根据PV生命周期5个阶段,PV的状态有以下4种
- Available:可用
- Bound:已经分配给PVC
- Released:PVC解绑但还未执行回收策略
- Failed:发生错误
PV的访问模式
PV的访问模式(accessModes)有三种:
- ReadWriteOnce(RWO):是最基本的方式,可读可写,但只支持被单个Pod挂载。
- ReadOnlyMany(ROX):可以以只读的方式被多个Pod挂载共享。
- ReadWriteMany(RWX):这种存储可以以读写的方式被多个Pod挂载共享。
不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。
PV的回收状态
PV的回收策略(persistentVolumeReclaimPolicy,即PVC释放卷的时候PV该如何操作)也有三种
- Retain,不清理, 保留Volume(需要手动清理)【比较常用】【缺省配置】
- Recycle,删除数据,即rm -rf /thevolume/*(只有NFS和HostPath支持)
- Delete,删除存储资源,比如删除AWS EBS卷(只有AWS EBS, GCE PD, Azure Disk和Cinder支持)
PVC [persistentVolumeClaim] 持久卷声明
创建pvc
# gvk
apiVersion: v1
kind: PersistentVolumeClaim
# metadata
metadata:
name: db-data
spec:
# 访问模式
accessModes:
- ReadWriteOnce
# 存储类型
volumeMode: Filesystem
# 存储大小
resources:
requests:
storage: 2Gi
PV与PVC绑定
- master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态 调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求 的数量。一旦 PV 和 PVC 绑定后, PersistentVolumeClaim 绑定是排他性的,不管它们是如何绑定的。 PVC 跟 PV 绑定是一对一的映射
- 用户创建包含容量、访问模式等信息的PVC,向系统请求存储资源。系统查找已存在PV或者监控新创建PV,如果与PVC匹配则将两者绑定。如果PVC创建动态PV,则系统将一直将两者绑定。PV与PVC的绑定是一一对应关系,不能重复绑定与被绑定。如果系统一直没有为PVC找到匹配PV,则PVC无限期维持在"unbound"状态,直到系统找到匹配PV。实际绑定的PV容量可能大于PVC中申请的容量
在POD中使用PVC
- 示例
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dbserver
name: dbserver
spec:
replicas: 1
selector:
matchLabels:
app: dbserver
strategy: {}
template:
metadata:
labels:
app: dbserver
spec:
volumes:
- name: datadir
persistentVolumeClaim:
claimName: db-data
#nfs:
# server: 192.168.0.180
# path: /data/nfs/mysql
#nodeSelector:
# kubernetes.io/hostname: k8s03
containers:
- image: registry.cn-zhangjiakou.aliyuncs.com/breezey/mysql:5.7
name: mysql
volumeMounts:
- name: datadir
mountPath: /var/lib/mysql
ports:
- name: mysql
containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: cka123
- name: MYSQL_DATABASE
value: wordpress
resources: {}
storageClass
- 监视集群当中的pvc,然后根据pvc的需求,自动的创建满足pvc类型的pv
- PV和PVC模式是需要运维人员先创建好PV,然后开发人员定义好PVC进行一对一的Bond,但是如果PVC请求成千上万,那么就需要创建成千上万的PV,对于运维人员来说维护成本很高,**Kubernetes提供一种自动创建PV的机制,叫StorageClass,它的作用就是创建PV的模板 **
- StorageClass还可以封装不同类型的存储供PVC选用
StorageClass结构
StorageClass包括四个部分
- provisioner:指定Volume插件的类型,包括内置插件(如kubernetes.io/glusterfs)和外部插件(如external-storage提供的ceph.com/cephfs)。
- mountOptions:指定挂载选项,当PV不支持指定的选项时会直接失败。比如NFS支持hard和nfsvers=4.1等选项。
- parameters:指定provisioner的选项,比如kubernetes.io/aws-ebs支持type、zone、iopsPerGB等参数。
- reclaimPolicy:指定回收策略,同PV的回收策略。
在使用PVC时,可以通过DefaultStorageClass准入控制设置默认StorageClass, 即给未设置storageClassName的PVC自动添加默认的StorageClass
要使用 StorageClass,我们就得安装对应的自动配置程序,比如这里我们存储后端使用的是 nfs,那么我们就需要使用到⼀个 nfs-client 的自动配置程序,我们也叫它 Provisioner,这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。
- 存储卷绑定模式 Volume Binding Mode: StorageClass 根据存储卷绑定模式的选项,确定何时执行 存储卷与存储卷声明的绑定、何时执行动态存储卷提供(动态创建存储卷)。可选项有
- Immediate: 即刻绑定 , 存储卷声明创建后,立刻动态创建存储卷并将其绑定到存储卷声明
- WaitForFirstConsumer : 首次使用时绑定 , 直到存储卷声明第一次被容器组使用时,才创建存储卷,并将其绑定到存储卷声明 ** **
CSI 【Container Storage Interface】 容器存储接口
- Container Storage Interface是由来自Kubernetes、Mesos、Docker等社区member联合制定的一个行业标准接口规范,旨在将任意存储系统暴露给容器化应用程序。
- CSI规范定义了存储提供商实现CSI兼容的Volume Plugin的最小操作集和部署建议。CSI规范的主要焦点是声明Volume Plugin必须实现的接口。
基于NFS的storageClass
storageclass --> nfs-csi --> nfs
部署nfs-csi
- github地址: https://github.com/kubernetes-csi/csi-driver-nfs/tree/master/deploy
- 需要如图4个文件
- 部署 kubectl app -f **.yaml
创建StorageClass
# gvk
apiVersion: storage.k8s.io/v1
kind: StorageClass
# metadata # global
metadata:
name: nfs-sc
# 提供商
provisioner: nfs.csi.k8s.io
parameters:
server: 192.168.0.180
share: /data/nfs
reclaimPolicy: Retain # only retain is supported
volumeBindingMode: Immediate
mountOptions:
- hard
- nfsvers=4.1
创建pvc
# gvk
apiVersion: v1
kind: PersistentVolumeClaim
# metadata
metadata:
name: db-data2
spec:
# 访问模式
accessModes:
- ReadWriteOnce
# 存储类型
volumeMode: Filesystem
# 存储大小
resources:
requests:
storage: 2Gi
storageClassName: nfs-sc
创建Pod使用基于StorageClass的PVC
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dbserver
name: dbserver
spec:
replicas: 1
selector:
matchLabels:
app: dbserver
strategy: {}
template:
metadata:
labels:
app: dbserver
spec:
volumes:
- name: datadir
persistentVolumeClaim:
claimName: db-data2
#nfs:
# server: 192.168.0.180
# path: /data/nfs/mysql
#nodeSelector:
# kubernetes.io/hostname: k8s03
containers:
- image: registry.cn-zhangjiakou.aliyuncs.com/breezey/mysql:5.7
name: mysql
volumeMounts:
- name: datadir
mountPath: /var/lib/mysql
ports:
- name: mysql
containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: cka123
- name: MYSQL_DATABASE
value: wordpress
resources: {}