344 lines
16 KiB
Markdown
344 lines
16 KiB
Markdown
|
<h1><center>kubernetes持久化存储</center></h1>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
------
|
|||
|
|
|||
|
## 一:简介
|
|||
|
|
|||
|
存储的管理是一个与计算实例的管理完全不同的问题。PV子系统为用户 和管理员提供了一组 API,将存储如何供应的细节从其如何被使用中抽象出来。 为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。
|
|||
|
|
|||
|
持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者使用存储类(Storage Class)来动态供应。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
|
|||
|
|
|||
|
持久卷申领(PersistentVolumeClaim,PVC)表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式。
|
|||
|
|
|||
|
尽管 PersistentVolumeClaim 允许用户消耗抽象的存储资源,常见的情况是针对不同的问题用户需要的是具有不同属性(如,性能)的 PersistentVolume 卷。 集群管理员需要能够提供不同性质的 PersistentVolume,并且这些 PV 卷之间的差别不仅限于卷大小和访问模式,同时又不能将卷是如何实现的这些细节暴露给用户;为了满足这类需求,就有了存储类(StorageClass) 资源。
|
|||
|
|
|||
|
PV 卷是集群中的资源。PVC 申领是对这些资源的请求,也被用来执行对资源的申领检查。
|
|||
|
|
|||
|
#### 1.PV卷供应的方式
|
|||
|
|
|||
|
静态供应:
|
|||
|
|
|||
|
集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息,并且对集群 用户可用(可见)。PV 卷对象存在于 Kubernetes API 中,可供用户消费(使用)。
|
|||
|
|
|||
|
动态供应:
|
|||
|
|
|||
|
如果管理员所创建的所有静态 PV 卷都无法与用户的 PVC 匹配, 集群可以尝试为该 PVC 申领动态供应一个存储卷。 这一供应操作是基于 StorageClass 来实现的:PVC 申领必须请求某个 存储类,同时集群管理员必须 已经创建并配置了该类,这样动态供应卷的动作才会发生。 如果 PVC 申领指定存储类为 "",则相当于为自身禁止使用动态供应的卷。
|
|||
|
|
|||
|
## 二:基于NFS的持久化存储
|
|||
|
|
|||
|
#### 1.部署NFS
|
|||
|
|
|||
|
```shell
|
|||
|
安装部署nfs服务,并创建nfsdata作为共享目录。
|
|||
|
[root@master ~]# yum -y install nfs-utils
|
|||
|
[root@master ~]# systemctl start nfs
|
|||
|
[root@master ~]# mkdir /nfsdata
|
|||
|
[root@master ~]# vim /etc/exports
|
|||
|
/nfsdata *(rw,no_root_squash,no_all_squash,sync)
|
|||
|
[root@master ~]# exportfs -r
|
|||
|
修改配置文件重启nfs
|
|||
|
[root@master ~]# vim /etc/sysconfig/nfs
|
|||
|
RPCNFSDARGS="-N 2 -N 3"
|
|||
|
RPCNFSDARGS="-N 4"
|
|||
|
[root@master ~]# systemctl restart nfs
|
|||
|
所有节点需要安装ntf-utils,目的是识别NFS文件系统
|
|||
|
[root@node-1 ~]# yum -y install nfs-utils
|
|||
|
```
|
|||
|
|
|||
|
#### 2.创建PV+PVC+nginx应用
|
|||
|
|
|||
|
```shell
|
|||
|
[root@master ~]# cat pv.yaml
|
|||
|
apiVersion: v1
|
|||
|
kind: PersistentVolume
|
|||
|
metadata:
|
|||
|
name: nfs-pv
|
|||
|
spec:
|
|||
|
capacity:
|
|||
|
storage: 1000Mi
|
|||
|
accessModes:
|
|||
|
- ReadWriteMany
|
|||
|
nfs:
|
|||
|
server: 10.0.0.110
|
|||
|
path: /nfsdata
|
|||
|
[root@master ~]# cat pvc.yaml
|
|||
|
apiVersion: v1
|
|||
|
kind: PersistentVolumeClaim
|
|||
|
metadata:
|
|||
|
name: nfs-pvc
|
|||
|
spec:
|
|||
|
accessModes:
|
|||
|
- ReadWriteMany
|
|||
|
resources:
|
|||
|
requests:
|
|||
|
storage: 90Mi
|
|||
|
|
|||
|
---
|
|||
|
apiVersion: v1
|
|||
|
kind: Pod
|
|||
|
metadata:
|
|||
|
name: nginx-volume-pvc
|
|||
|
|
|||
|
spec:
|
|||
|
containers:
|
|||
|
- name: nginx
|
|||
|
image: 10.0.0.144/library/nginx:1.18
|
|||
|
ports:
|
|||
|
- containerPort: 80
|
|||
|
volumeMounts:
|
|||
|
- name: html-pv
|
|||
|
mountPath: /usr/share/nginx/html
|
|||
|
volumes:
|
|||
|
- name: html-pv
|
|||
|
persistentVolumeClaim:
|
|||
|
claimName: nfs-pvc
|
|||
|
[root@master ~]# kubectl create -f pv.yaml
|
|||
|
[root@master ~]# kubectl create -f pvc.yaml
|
|||
|
```
|
|||
|
|
|||
|
#### 3.查看创建好的PV和PVC
|
|||
|
|
|||
|
```shell
|
|||
|
[root@master ~]# kubectl get pv
|
|||
|
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
|
|||
|
nfs-pv 1000Mi RWX Retain Bound default/nfs-pvc 6m37s
|
|||
|
[root@master ~]# kubectl get pvc
|
|||
|
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
|
|||
|
nfs-pvc Bound nfs-pv 1000Mi RWX 6m39s
|
|||
|
```
|
|||
|
|
|||
|
#### 4.查看创建好的应用
|
|||
|
|
|||
|
```shell
|
|||
|
[root@master ~]# kubectl get pod
|
|||
|
NAME READY STATUS RESTARTS AGE
|
|||
|
nginx-volume-pvc 1/1 Running 0 8m47s
|
|||
|
```
|
|||
|
|
|||
|
#### 5.验证存储卷
|
|||
|
|
|||
|
```shell
|
|||
|
[root@master nfsdata]# echo "hello world" > index.html
|
|||
|
[root@master nfsdata]# ls
|
|||
|
index.html
|
|||
|
[root@master nfsdata]# kubectl get pod -o wide
|
|||
|
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
|||
|
nginx-volume-pvc 1/1 Running 0 9m52s 10.244.3.9 node-3 <none> <none>
|
|||
|
[root@master nfsdata]# curl 10.244.3.9
|
|||
|
hello world
|
|||
|
```
|
|||
|
|
|||
|
## 三:使用过程
|
|||
|
|
|||
|
#### 1.绑定
|
|||
|
|
|||
|
用户创建一个带有特定存储容量和特定访问模式需求的 PVC 对象; 在动态供应场景下,这个 PVC 对象可能已经创建完毕。 主控节点中的控制回路监测新的 PVC 对象,寻找与之匹配的 PV 卷(如果可能的话), 并将二者绑定到一起。 如果为了新的 PVC 申领动态供应了 PV 卷,则控制回路总是将该 PV 卷绑定到这一 PVC 申领。 否则,用户总是能够获得他们所请求的资源,只是所获得的 PV 卷可能会超出所请求的配置。 一旦绑定关系建立,则 PersistentVolumeClaim 绑定就是排他性的,无论该 PVC 申领是 如何与 PV 卷建立的绑定关系。 PVC 申领与 PV 卷之间的绑定是一种一对一的映射,实现上使用 ClaimRef 来记述 PV 卷 与 PVC 申领间的双向绑定关系。
|
|||
|
|
|||
|
#### 2.使用
|
|||
|
|
|||
|
Pod 将 PVC 申领当做存储卷来使用。集群会检视 PVC 申领,找到所绑定的卷,并 为 Pod 挂载该卷。对于支持多种访问模式的卷,用户要在 Pod 中以卷的形式使用申领时指定期望的访问模式
|
|||
|
|
|||
|
一旦用户有了申领对象并且该申领已经被绑定,则所绑定的 PV 卷在用户仍然需要它期间 一直属于该用户。用户通过在 Pod 的volumes块中包含persistentVolumeClaim节区来调度 Pod,访问所申领的 PV 卷
|
|||
|
|
|||
|
#### 3.回收
|
|||
|
|
|||
|
当用户不再使用其存储卷时,他们可以从 API 中将 PVC 对象删除,从而允许 该资源被回收再利用。PersistentVolume 对象的回收策略告诉集群,当其被 从申领中释放时如何处理该数据卷。 目前,数据卷可以被 Retained(保留)、Recycled(回收)或 Deleted(删除)
|
|||
|
|
|||
|
#### 4.保留
|
|||
|
|
|||
|
回收策略 Retain使得用户可以手动回收资源。当 PVC对象 被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为"已释放"。 由于卷上仍然存在这前一申领人的数据,该卷还不能用于其他申领。 管理员可以通过下面的步骤来手动回收该卷:
|
|||
|
|
|||
|
删除 PersistentVolume 对象。与之相关的、位于外部基础设施中的存储资产 (例如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)在 PV 删除之后仍然存在
|
|||
|
|
|||
|
根据情况,手动清除所关联的存储资产上的数据。手动删除所关联的存储资产;如果你希望重用该存储资产,可以基于存储资产的 定义创建新的 PersistentVolume 卷对象
|
|||
|
|
|||
|
#### 5.删除
|
|||
|
|
|||
|
对于支持 Delete回收策略的卷插件,删除动作会将 PV对象从 Kubernetes 中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 动态供应的卷会继承其 StorageClass 中设置的回收策略,该策略默认 为Delete。管理员需要根据用户的期望来配置 StorageClass;否则 PV 卷被创建之后必须要被编辑或者修补
|
|||
|
|
|||
|
## 四:PV参数解释
|
|||
|
|
|||
|
#### 1.持久卷
|
|||
|
|
|||
|
每个 PV 对象都包含spec部分和status部分,分别对应卷的规约和状态
|
|||
|
|
|||
|
```shell
|
|||
|
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
|
|||
|
```
|
|||
|
|
|||
|
#### 2.容量
|
|||
|
|
|||
|
一般而言,每个 PV 卷都有确定的存储容量。 容量属性是使用 PV 对象的capacity属性来设置的。目前,存储大小是可以设置和请求的唯一资源。 未来可能会包含 IOPS、吞吐量等属性
|
|||
|
|
|||
|
#### 3.卷模式
|
|||
|
|
|||
|
针对 PV 持久卷,Kubernetes 支持两种卷模式(volumeModes):Filesystem(文件系统)和Block(块)。 volumeMode是一个可选的 API 参数。 如果该参数被省略,默认的卷模式是Filesystem
|
|||
|
|
|||
|
volumeMode属性设置为Filesystem的卷会被 Pod 挂载(Mount) 到某个目录。 如果卷的存储来自某块设备而该设备目前为空,Kuberneretes 会在第一次挂载卷之前在设备上创建文件系统
|
|||
|
|
|||
|
你可以将volumeMode设置为Block,以便将卷作为原始块设备来使用。 这类卷以块设备的方式交给 Pod 使用,其上没有任何文件系统。 这种模式对于为 Pod 提供一种使用最快可能方式来访问卷而言很有帮助,Pod 和 卷之间不存在文件系统层。另外,Pod 中运行的应用必须知道如何处理原始块设备
|
|||
|
|
|||
|
#### 4.访问模式
|
|||
|
|
|||
|
PersistentVolume 卷可以用资源提供者所支持的任何方式挂载到宿主系统上。 如下表所示,提供者(驱动)的能力不同,每个 PV 卷的访问模式都会设置为 对应卷所支持的模式值。 例如,NFS 可以支持多个读写客户,但是某个特定的 NFS PV 卷可能在服务器 上以只读的方式导出。每个 PV 卷都会获得自身的访问模式集合,描述的是特定 PV 卷的能力
|
|||
|
|
|||
|
访问模式有:
|
|||
|
|
|||
|
ReadWriteOnce -- 卷可以被一个节点以读写方式挂载
|
|||
|
|
|||
|
ReadOnlyMany -- 卷可以被多个节点以只读方式挂载
|
|||
|
|
|||
|
ReadWriteMany -- 卷可以被多个节点以读写方式挂载
|
|||
|
|
|||
|
在命令行接口(CLI)中,访问模式也使用以下缩写形式:
|
|||
|
|
|||
|
RWO - ReadWriteOnce
|
|||
|
|
|||
|
ROX - ReadOnlyMany
|
|||
|
|
|||
|
RWX - ReadWriteMany
|
|||
|
|
|||
|
注意:
|
|||
|
|
|||
|
每个卷只能同一时刻只能以一种访问模式挂载,即使该卷能够支持 多种访问模式
|
|||
|
|
|||
|
#### 5.类
|
|||
|
|
|||
|
每个 PV 可以属于某个类(Class),通过将其storageClassName属性设置为某个 StorageClass 的名称来指定。 特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。 未设置storageClassName的 PV 卷没有类设定,只能绑定到那些没有指定特定 存储类的 PVC 申领
|
|||
|
|
|||
|
#### 6.回收策略
|
|||
|
|
|||
|
Retain -- 手动回收
|
|||
|
|
|||
|
Recycle -- 基本擦除 (rm -rf /thevolume/*)
|
|||
|
|
|||
|
Delete -- 诸如 AWS EBS、GCE PD、Azure Disk 或 OpenStack Cinder 卷这类关联存储资产也被删除
|
|||
|
|
|||
|
目前,仅 NFS 和 HostPath 支持回收。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支持删除(Delete)
|
|||
|
|
|||
|
#### 7.节点亲和性
|
|||
|
|
|||
|
每个 PV 卷可以通过设置 节点亲和性 来定义一些约束,进而限制从哪些节点上可以访问此卷。 使用这些卷的 Pod 只会被调度到节点亲和性规则所选择的节点上执行
|
|||
|
|
|||
|
#### 8.阶段
|
|||
|
|
|||
|
Available(可用)-- 卷是一个空闲资源,尚未绑定到任何申领
|
|||
|
|
|||
|
Bound(已绑定)-- 该卷已经绑定到某申领
|
|||
|
|
|||
|
Released(已释放)-- 绑定的申领已被删除,资源尚未被集群回收
|
|||
|
|
|||
|
Failed(失败)-- 卷的自动回收操作失败
|
|||
|
|
|||
|
## 五:PVC参数解释
|
|||
|
|
|||
|
#### 1.PersistentVolumeClaims
|
|||
|
|
|||
|
每个 PVC 对象都有spec和status部分,分别对应申领的规约和状态
|
|||
|
|
|||
|
```shell
|
|||
|
apiVersion: v1
|
|||
|
kind: PersistentVolumeClaim
|
|||
|
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]}
|
|||
|
```
|
|||
|
|
|||
|
#### 2.访问模式
|
|||
|
|
|||
|
ReadWriteOnce -- 卷可以被一个节点以读写方式挂载
|
|||
|
|
|||
|
ReadOnlyMany -- 卷可以被多个节点以只读方式挂载
|
|||
|
|
|||
|
ReadWriteMany -- 卷可以被多个节点以读写方式挂载
|
|||
|
|
|||
|
#### 3.卷模式
|
|||
|
|
|||
|
针对 PV 持久卷,Kubernetes 支持两种卷模式(volumeModes):Filesystem(文件系统)和Block(块)。 volumeMode是一个可选的 API 参数。 如果该参数被省略,默认的卷模式是Filesystem
|
|||
|
|
|||
|
#### 4.资源
|
|||
|
|
|||
|
申领和 Pod 一样,也可以请求特定数量的资源。在这个上下文中,请求的资源是存储。 卷和申领都使用相同的资源模型
|
|||
|
|
|||
|
#### 5.选择算符
|
|||
|
|
|||
|
申领可以设置标签选择算符 来进一步过滤卷集合。只有标签与选择算符相匹配的卷能够绑定到申领上。 选择算符包含两个字段:
|
|||
|
|
|||
|
matchLabels - 卷必须包含带有此值的标签
|
|||
|
|
|||
|
matchExpressions - 通过设定键(key)、值列表和操作符(operator) 来构造的需求
|
|||
|
|
|||
|
合法的操作符有 In、NotIn、Exists 和 DoesNotExist
|
|||
|
|
|||
|
注意:
|
|||
|
|
|||
|
来自matchLabels和matchExpressions的所有需求都按逻辑与的方式组合在一起, 这些需求都必须被满足才被视为匹配
|
|||
|
|
|||
|
#### 6.类
|
|||
|
|
|||
|
申领可以通过为storageClassName属性设置 StorageClass 的名称来请求特定的存储类。 只有所请求的类的 PV 卷,即storageClassName值与 PVC 设置相同的 PV 卷, 才能绑定到 PVC申领
|
|||
|
|
|||
|
PVC 申领不必一定要请求某个类。如果 PVC 的 `storageClassName` 属性值设置为 `""`, 则被视为要请求的是没有设置存储类的 PV 卷,因此这一 PVC 申领只能绑定到未设置 存储类的 PV 卷(未设置注解或者注解值为 `""` 的 PersistentVolume(PV)对象在系统中不会被删除,因为这样做可能会引起数据丢失。 未设置 `storageClassName` 的 PVC 与此大不相同,也会被集群作不同处理,具体筛查方式取决于`DefaultStorageClass` 准入控制器插件是否被启用
|
|||
|
|
|||
|
如果准入控制器插件被启用,则管理员可以设置一个默认的 StorageClass。 所有未设置 storageClassName 的 PVC 都只能绑定到隶属于默认存储类的 PV 卷。 设置默认 StorageClass 的工作是通过将对应 StorageClass 对象的注解 storageclass.kubernetes.io/is-default-class 赋值为 true 来完成的。 如果管理员未设置默认存储类,集群对 PVC 创建的处理方式与未启用准入控制器插件 时相同。如果设定的默认存储类不止一个,准入控制插件会禁止所有创建 PVC 操作
|
|||
|
|
|||
|
如果准入控制器插件被关闭,则不存在默认 StorageClass 的说法。 所有未设置 `storageClassName` 的 PVC 都只能绑定到未设置存储类的 PV 卷。 在这种情况下,未设置 `storageClassName` 的 PVC 与 `storageClassName` 设置未 `""` 的 PVC 的处理方式相同
|
|||
|
|
|||
|
#### 7.使用申领作为卷
|
|||
|
|
|||
|
Pod 将申领作为卷来使用,并藉此访问存储资源。 申领必须位于使用它的 Pod 所在的同一名字空间内。 集群在 Pod 的名字空间中查找申领,并使用它来获得申领所使用的 PV 卷。 之后,卷会被挂载到宿主上并挂载到 Pod 中
|
|||
|
|
|||
|
```shell
|
|||
|
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: myclaim
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|