目录
- 0. ConfigMap 和 Secret 中的 Volume
- 1. PersistentVolume
- 2. 使用 YAML 描述 PersistentVolume
- 3. 使用 YAML 描述 PersistentVolumeClaim
- 4. 在 Kubernetes 中使用 PersistentVolume
- 5. 为 Pod 挂载 PersistentVolume
- 资料
0. ConfigMap 和 Secret 中的 Volume
【Kubernetes】K8s笔记(五):应用的配置管理 ConfigMap / Secret 提到了 Volume 存储卷的概念。它使用字段 volumes
和 volumeMounts
将配置信息挂载到 Pod 中供进程使用。
本篇笔记会讲述 Volume 的高级用法,看看 Kubernetes 管理存储资源的 API 对象 PersistentVolume、PersistentVolumeClaim、StorageClass,然后使用本地磁盘来创建实际可用的存储卷。
1. PersistentVolume
Pod 里的容器是由镜像产生的,而镜像文件本身是只读的,进程要读写磁盘只能用一个临时的存储空间,一旦 Pod 销毁,临时存储也就会立即回收释放,数据也就丢失了。为了保证即使 Pod 销毁后重建数据依然存在,Kubernetes 就顺着 Volume 的概念,延伸出了 PersistentVolume 对象,它专门用来表示持久存储设备,但隐藏了存储的底层实现,我们只需要知道它能安全可靠地保管数据就可以了(由于 PersistentVolume 这个词很长,一般都把它简称为 PV)。
作为存储的抽象,PV 实际上就是一些存储设备、文件系统,比如 Ceph、GlusterFS、NFS,甚至是本地磁盘,管理它们已经超出了 Kubernetes 的能力范围,所以,一般会由系统管理员单独维护,然后再在 Kubernetes 里创建对应的 PV。
要注意的是,PV 属于集群的系统资源,是和 Node 平级的一种对象,Pod 对它没有管理权,只有使用权。
PersistentVolumeClaim 和 StorageClass
PV 无法直接挂载到 Pod 里面使用,因为不同的存储设备的差异巨大:速度快慢、共享/独占读写、容量大小...这么多种存储设备,只用一个 PV 对象来管理还是有点太勉强了,不符合“单一职责”的原则,让 Pod 直接去选择 PV 也很不灵活。
于是 Kubernetes 就又增加了两个新对象,PersistentVolumeClaim 和 StorageClass,用的还是“中间层”的思想,把存储卷的分配管理过程再次细化。
PersistentVolumeClaim 简称 PVC。它是用来向 Kubernetes 申请存储资源的 API 对象,用来给 Pod 使用,相当于 Pod 的存储代理,代表 Pod 向系统申请 PV。一旦资源申请成功,Kubernetes 就会把 PV 和 PVC 关联在一起,这个动作叫做“绑定”(bind)。
但是,系统里的存储资源非常多,如果要 PVC 去直接遍历查找合适的 PV 也很麻烦,所以就要用到 StorageClass。
StorageClass 抽象了特定类型的存储系统(比如 Ceph、NFS),在 PVC 和 PV 之间充当“协调人”的角色,帮助 PVC 找到合适的 PV。也就是说它可以简化 Pod 挂载“虚拟盘”的过程,让 Pod 看不到 PV 的实现细节。
2. 使用 YAML 描述 PersistentVolume
Kubernetes 里有很多种类型的 PV,最基础的是本机存储 HostPath
。它和 Docker 中使用 docker run -v
使用的参数 -v
非常相似。
因为 Pod 会在集群的任意节点上运行,所以首先,我们要作为系统管理员在每个节点上创建一个目录,它将会作为本地存储卷挂载到 Pod 里:在 /tmp
目录下建立名字为 host-10mb-pv
的文件夹,表示一个容量为 10 MB 的存储设备。
目前只能用 kubectl api-resources
kubectl explain
查看 PV 的字段说明,手动编写 PV 的 YAML 描述文件。
apiVersion: v1
kind: PersistentVolume
metadata:
name: host-10m-pv
spec:
storageClassName: host-manual
accessModes:
- ReadWriteOnce
capacity:
storage: 10Mi
hostPath:
path: /tmp/host-10mib-pv/
storageClassName
是对存储类型的抽象 StorageClass 的名字。这个 PV 是手动管理的,名字可以任意起。
accessModes
定义了存储设备的访问模式。简单来说就是虚拟盘的读写权限,和 Linux 的文件访问模式差不多,目前 Kubernetes 里有 4 种:
-
ReadWriteOnce
:存储卷可读可写,但只能被一个节点上的 Pod 挂载 -
ReadOnlyMany
:存储卷只读不可写,可以被任意节点上的 Pod 多次挂载 -
ReadWriteMany
:存储卷可读可写,也可以被任意节点上的 Pod 多次挂载 -
ReadWriteOncePod
:卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本
前三种 3 种访问模式限制的对象是节点而不是 Pod,因为存储是系统级别的概念,不属于 Pod 里的进程。显然,本地目录只能是在本机使用,所以这个 PV 使用了 ReadWriteOnce。
在命令行接口(CLI)中,访问模式也使用以下缩写形式:
RWO - ReadWriteOnce
ROX - ReadOnlyMany
RWX - ReadWriteMany
RWOP - ReadWriteOncePod
capacity
表示存储设备的容量,这里我设置为 10MB。Kubernetes 里定义存储容量使用的是国际标准,要写成 Ki/Mi/Gi。
hostPath
指定了存储卷的本地路径,也就是我们在节点上创建的目录。
用这些字段把 PV 的类型、访问模式、容量、存储位置都描述清楚,一个存储设备就创建好了。
3. 使用 YAML 描述 PersistentVolumeClaim
有了 PV,就表示集群里有了这么一个持久化存储可以供 Pod 使用,我们需要再定义 PVC 对象,向 Kubernetes 申请存储。
下面这份 YAML 就是一个 PVC,要求使用一个 5MB 的存储设备,访问模式是 ReadWriteOnce
:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: host-5mib-pvc
spec:
storageClassName: host-manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Mi
PVC 的内容与 PV 很像,但它不表示实际的存储,而是一个“申请”或者“声明”,spec
里的字段描述的是对存储的“期望状态”。所以 PVC 里的 storageClassName
accessModes
和 PV 是一样的,但不会有字段 capacity
,而是要用 resources.requests.storage
表示希望要有多大的容量。
这样,Kubernetes 就会根据 PVC 里的描述,去找能够匹配 StorageClass 和容量的 PV,然后把 PV 和 PVC“绑定”在一起,实现存储的分配。
4. 在 Kubernetes 中使用 PersistentVolume
创建 PV 对象,然后查看它的状态
$ kubectl apply -f host-path-pv.yaml
persistentvolume/host-10m-pv created
$ kubectl get pv -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
host-10m-pv 10Mi RWO Retain Available host-manual 8s Filesystem
可以看到,这个 PV 的容量是 10 MiB,访问模式是 RWO(ReadWriteOnce),StorageClass 是自定义的 host-manual
,状态是可用(Available),可以随时分配给 Pod 使用。
创建PVC申请存储资源
$ kubectl apply -f host-path-pvc.yaml
persistentvolumeclaim/host-5mib-pvc created
$ kubectl get pvc -o wide
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
host-5mib-pvc Bound host-10m-pv 10Mi RWO host-manual 5s Filesystem
$ kubectl get pv -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
host-10m-pv 10Mi RWO Retain Bound default/host-5mib-pvc host-manual 14m Filesystem
一旦 PVC 对象创建成功,Kubernetes 就会立即通过 StorageClass
resources
等条件在集群里查找符合要求的 PV,如果找到合适的存储对象就会把它俩“绑定”(bind)在一起,绑定后的状态就是 Bound。
PVC 对象申请的是 5MB,但现在系统里只有一个 10MB 的 PV,没有更合适的对象,所以 Kubernetes 也只能把这个 PV 分配出去。
如果把 PVC 的申请容量改大一些,超过现有可用 PV 的容量,PVC 就会一直处于 Pending 状态,这意味着 Kubernetes 没有在系统中找到合适的存储,无法分配资源,只有等满足要求的 PV 出现才能完成绑定。
5. 为 Pod 挂载 PersistentVolume
有了持久化存储就可以为 Pod 挂载存储卷。先要在 spec.volumes
定义存储卷,然后在 containers.volumeMounts
挂载进容器。因为我们用的是 PVC,所以要在 volumes 里用字段 persistentVolumeClaim
指定 PVC 的名字。
下面就是 Pod 的 YAML 描述文件,把存储卷挂载到了 Nginx 容器的 /tmp
目录:
apiVersion: v1
kind: Pod
metadata:
name: host-pvc-pod
spec:
volumes:
- name: host-pvc-vol
persistentVolumeClaim:
claimName: host-5mib-pvc
containers:
- name: ngx-pvc-pod
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: host-pvc-vol
mountPath: /tmp
现在启动这个 Pod:
$ kubectl apply -f ngx-pvc-pod.yaml
pod/host-pvc-pod created
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
host-pvc-pod 1/1 Running 0 21s 10.10.1.70 worker1 <none> <none>
我们在 Pod 中创建一个文件,然后取宿主机上看看文件是否被创建:
$ kubectl exec -it host-pvc-pod -- sh
/ # cd /tmp/
/tmp # echo yeah! > file.text
登录宿主机:
root@worker1:~# ls /tmp/host-10mib-pv/
file.text
root@worker1:~# cat /tmp/host-10mib-pv/file.text
yeah!
确实在 worker 节点的本地目录有一个 file.text
文件。因为 Pod 产生的数据已经通过 PV 存在了磁盘上,所以如果 Pod 删除后再重新创建,挂载存储卷时会依然使用这个目录,数据保持不变,也就实现了持久化存储。不过还有一点小问题,因为这个 PV 是 HostPath 类型,只在本节点存储,如果 Pod 重建时被调度到了其他节点上,那么即使加载了本地目录,也不会是之前的存储位置,持久化功能也就失效了。
HostPath 类型的 PV 一般用来做测试,或者是用于 DaemonSet 这样与节点关系比较密切的应用。下篇笔记就要学习网络共享存储了。
资料
Introducing Single Pod Access Mode for PersistentVolumes
标签:存储,PV,Kubernetes,PVC,host,PersistentVolume,Pod,K8s From: https://www.cnblogs.com/joexu01/p/16823747.html