k8s_day04_04
k8s_day04_04容器外部存储空间docker文件系统具有和 docker容器具有相同的生命周期, 在多节点运行的容器就有可能因为各种原因删除或者终止 ,为了避免数据与 容器这种存在短暂生命周期、或者不确定生命周期的对象产生直接绑定关系, 应该将其存储的数据(应用数据、状态数据)存储在容器的文件系统之外, 方式就是为容器引入外部的存储空间外部的存储空间大体分为两类:Host:存在宿主机,如
k8s_day04_04
容器外部存储空间
docker 文件系统具有和 docker 容器具有相同的生命周期, 在多节点运行的容器就有可能因为各种原因删除或者终止 ,为了避免数据与 容器这种存在短暂生命周期、或者不确定生命周期的对象产生直接绑定关系, 应该将其存储的数据(应用数据、状态数据) 存储在容器的文件系统之外, 方式就是为容器引入外部的存储空间
外部的存储空间大体分为两类:
Host:
存在宿主机,如果一个容器发生崩溃了,想得到之前的数据必须有一个条件,只能在同一个节点上把容器复活,但是对于拥有调度功能的集群k8s , 这是不常见的 ,很可能一调度就运行在其他节点上了。因此更多节点可达的网络存储更好一点
Network Stroage:
可以跨宿主机存在的, 网络存储
一般说来,我们可以使用宿主机节点的存储卷,就是在节点本地的某一磁盘存储设备上,为抗硬件损毁,只能做raid的冗余机制, 即便是做了raid , 但是节点宕机级别的故障也无法解决。第二种方式就是做 smaba 或者NFS 这样的外部存储服务 ,得保证NFS 是有较高可用性的, 在每个节点上安装NFS的客户端,一旦某个pod 被调度至某一节点上时:
借助宿主机NFS客户端程序 与nfs server上的某一存储空间建立关联关系。 随后容器的数据会存储在容器的目录内【挂载点】,这个目录是位于外部的访问入口而不是容器的文件系统上, 挂载点下的目录 数据被通过nfs 驱动 借助于网络 传输给nfs-server.
每个节点要想访问网络服务, 必须要适配给 sever 端。 这个适配是是宿主机做的,而这个适配通常是需要安装指定协议的客户端。而不是由容器适配的
说了这么多 ,就是容器直接挂载nfs 而不是宿主机 ,但是宿主机要安装nfs 驱动
在docker 上 ,这个适配 被叫做存储驱动。
[root@node01 ~]# docker info |grep Storage
Storage Driver: overlay2
这个 Storage Driver 并不是指容器内部的 Driver 而是 docker 引擎 所在的宿主机应该具备的driver
pod 内多容器 与存储卷的关系
一个pod 内有多个容器 ,那么存储卷属于哪个容器呢?
一个pod 内的多个容器都是共享了 一个叫 pause 容器的名称空间, pause 容器处于暂停状态。 pause 容器 可以理解为这里面运行的程序什么都不做,也不消耗cpu. pod 内的其他容器 可以加入 pause 容器的 网路名称空间、ipc名称空间。 具有一定的共享功能
一旦创建了存储卷 , 存储卷是与pause 容器建立关联关系的。
学dockers 的时候知道 ,docker 的存储卷 既可以直接指定一个存储卷 ,也可以从另外一个容器 复制和共享存储卷。
所以pod 内的其他容器 是可以直接复制 共享 pause 底端的同一个存储卷的
容器1 写入的数据是可以被容器2 所访问的,容器2也能写也能读 。但是 这要取决于底层的存储系统支不支持同时读写 ,比如 nfs 支持2客户端同时挂上去读写, 但 nfs server 端 会有一个锁机制 ,使得在某一个时刻内只能有一个写 ,但是对于客户端来说 它看上去 像是在同时读写 。 这种被称为多路读写
共享式存储设备的特点
- 多路并行读写
- 多路只读
- 单路读写: 同一个空间 ,不能被多个容器 同时写,只有某个容器卸载了存储卷 ,其他容器才能写
pod 存储卷
在pod 内使用存储卷分为2步
1、在Pod上定义存储卷,并关联至目标存储服务上; (pod 级别定义)
2、在需要用到存储卷的容器上,挂载其所属的Pod的存储卷; (容器级别挂载)
volumes 资源格式定义
spec:
volumes:
- name <string> # 存储卷名称标识,仅可使用DNS标签格式的字符,在当前Pod中必须唯一
VOL_TYPE <Object> # 存储卷插件及具体的目标存储供给方的相关配置
containers:
- name: …
image: …
volumeMounts:
- name <string> # 要挂载的存储卷的名称,必须匹配存储卷列表中某项的定义
mountPath <string> # 容器文件系统上的挂载点路径
readOnly <boolean> # 是否挂载为只读模式,默认为“否”
subPath <string> # 挂载存储卷上的一个子目录至指定的挂载点
subPathExpr <string> # 挂载由指定的模式匹配到的存储卷的文件或目录至挂载点
volumeMounts 中 只有name、 mountPath 是必填值
voulmes 类型
存储卷本身指的的pod外部的某个空间,要想访问这个存储空间, 需要在这个节点上适配到这个空间。需要驱动程序。 就算你访问的是本地的nfs 系统 也要驱动程序 , 只不过哪个驱动程序称为xfs 内核驱动模块而已。
之所以是 是节点需要。 是因为 在节点上有kubelet 程序 ,创建和启动程序的是kubelet. 由kubelet调用 容器引擎(contaier Engine) .因此 管理存储卷的功能 也是kubelet实现的 。
在kubelet 中 实现这个功能的位置 叫做 卷插件 Volume Plugin 卷插件 就是卷类型
每一种卷类型就有对应的卷插件,比如要想支持 NFS 存储卷, kubelet 需要有支持 NFS 的卷插件,同时kubelet 所在的节点还要能驱动nfs 。插件代表了 k8s 支持的卷类型, 真正的设备驱动还要在 节点级别
来完成。
卷插件 有以下几种类型:
[root@node01 ~]# kubectl explain pods.spec.volumes.nfs
-
Host级别:hostPath, Local 节点级别
-
网络级别:NFS、GlusterFS、rbd(块设备)、CephFS(文件系统)、… 网络级别
临时存储:emptyDir
emptyDir 空目录 ,可以认为就是把内存拿一部分当硬盘给pod用 ,为高性能的应用提供缓存空间, 如何是用在pod 级别, pod 没了也可以把它也删除了,期望用外部高性能的设备来存储,比如nvme 固态盘
扩展接口的存储卷
对于任何类型的支持,我们一定是通过kubelet volume plugin 支持这种存储卷类型。不被kubelet 支持却也能用的存储卷 也有 ,但是要借助CSI 【容器存储接口】 ,一旦借助csi 实现 ,意味着存储服务商可以开发专门的外部存储插件 通过csi 对接kubelet之上 比如rancher 研发的 Longhorn ,它可以不借助外部存储服务 ,而只是借助 节点上富余的存储空间就能通过存储服务 ,而且拥有用户自定义级别的冗余能力的服务. 因为存储和网络同样是一个非常复杂的东西 ,需要交给专业的人来做
这样一来存储服务 又分为 内置和外置的
In-Tree kuelet 原生支持的
Out-of-Tree: 通过csi 接入的, 其实内置的接口不止csi 一个 ,还有叫 FlexVolume, 但是这种方式不规范,有很多设计上的缺陷,后来被 csi 所取代 ,现在是二者并存的. FlexVolume 都是 csi 树内的
,但是通过它们扩展的就不是
k8s 到底支持哪些种存储?
[root@node01 ~]# kubectl explain pods.spec.volumes
命令列出的都是树内的. 树内的存储插件
cinder 是 openstack 的存储服务
ephemeral 也是临时存储 ,但是目前仍然处于Alpha feature
gcePersistentDisk 谷歌公有云的上的磁盘 pd
gitRepo DEPRECATED 废弃了
pvc 的引入
直接在pod中 使用插件是 不好的(po.spec.volumes.nfs) 这种设计仍然存在设计缺陷 .因为 违背了k8s的 消费模型 理念. 要想使用存储卷, 除了需要节点能驱动存储服务外 , 所有服务的配置 同过卷插件来设置 , 比如你要设置 nfs插件的地址 是否只读 等等字段, 如果插件类型是Ceph , 更难了. 普通用户还不会用. 因此k8s 在存储卷之上 引入 2个中间层 ,方便用户使用
引入2个概念 一个叫 pv 另一个叫 pvc
pv 叫持久存储卷
pvc 叫 持久存储卷 申请 ,请求 claim.
这样用户在使用存储卷时就不关心 背后使用的 哪种类型的存储卷, 不关心实现 ,而是只要告诉我需要声明请求多大的空间 ,存储性能 快,慢 即可。 这些要求如何达成的就是靠pv 实现。
让 pv 与pvc 建立绑定关系 , 因此用户存储在存储卷上的数据都会由 pvc 到达pv 来。
pv 不是由pod 编写者管理 ,而是由 集群管理员管理 。 pvc 是用户管理的 ,比如开发人员
Storageclass 的引入
这样在使用看起来 更复杂起来了?
首先 ,在pod 上 使用一种特殊的插件 叫做 pvc插件. 还要在pod的同一名称空间当中使用一种资源 叫 pvc资源 来创建需求 ,需求不是在pod 上定义的 ,但是你可以 说 我调用哪个pvc , pvc 只是一个申请 ,要与真正空间绑定起来 。这个空间 就抽象为pv 格式。
如果没有这2层 ,需要把 nfs 定义在图中的第一层 volume上,加了这这2层之后 ,就定义在了图中的第二层pv上。这种pv/pvc 的好处 就是把存储的创建和消费 隔离起来, 创建admin ,消费 user . 这种方式带来的缺点就是创建pvc 时 ,无法确定就已经有了pv . 用户是不会(如开发)创建pv的 , 只能通过行政手段解决。 让用户创建pvc时 先联系k8s 管理员 让它帮忙创建pv. 因此 为了解决这种问题 ,引入了新的资源 存储类 Strogae Class
可以理解为 就是 pv 创建模板 , 用于 pv的供给。
Strogae Class 可以按用户需求 动态创建 pv
因此有了 Strogae Class 之后, nfs 定义 插件也不定义图中的pv 上了 ,而是 定义在Strogae Class 上。创建pvc 时, 不是向pv 申请 。而是 Strogae Class 模板
最终, 再需要创建存储卷时 , 先在创建pvc资源 , 向模板关联一个pv ,然后创建一个pod . 通过pvc 插件 调用这个pv资源。
如果删除pod 时 , pvc 会不会删除? 不会 因为 pvc 是名称空间级别资源 ,如果 pod 删除了再重建, 只要 pvc 和pod 在同一个名称空间下 ,会自动关联。
直接在pod 中使用 存储卷插件 示例
示例 :
emptyDir
emptyDir 是卷插件类型 ,可以借助外部高速存储 或者内存 临时存储 一些数据 为应用提供高速缓存 ,当然也能为同一个pod内多个不同容器提供 共享的数据。 不能持久
2字段: medium 表示的是存储介质,默认的是磁盘Memory 是内存
eg:
借助初始化容器 ,下载配置文件到共享存储卷, 让主容器加下载的配置文件生效。
这里需要注意的是 ,只要挂载了 就是把 存储卷的根目录挂载到 mountPath。
只要名字volumeMounts.name 相同 , 不管mountPath的值是否一样 ,mountPath看到的内容都是一样的 是存储卷的根目录
[root@node01 chapter5]# cat volumes-emptydir-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: volumes-emptydir-demo
namespace: default
spec:
initContainers:
- name: config-file-downloader
image: ikubernetes/admin-box
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c','wget -O /data/envoy.yaml http://ilinux.io/envoy.yaml']
volumeMounts:
- name: config-file-store
mountPath: /data
containers:
- name: envoy
image: envoyproxy/envoy-alpine:v1.13.1
command: ['/bin/sh','-c']
args: ['envoy -c /etc/envoy/envoy.yaml']
volumeMounts:
- name: config-file-store
mountPath: /etc/envoy
readOnly: true
volumes:
- name: config-file-store
emptyDir:
medium: Memory
sizeLimit: 16Mi
[root@node01 chapter5]# kubectl describe po/volumes-emptydir-demo
验证存储卷类型
volumes:
config-file-store:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
SizeLimit: 16Mi
hostPath
docker 默认用的存储卷 就是 hostPath 类型 ,用的是本地的存储空间(如果没有对接外部设备的话)
[root@node01 chapter5]# kubectl explain pods.spec.volumes.hostPath
FIELDS:
path <string> -required-
Path of the directory on the host. If the path is a symlink, it will follow
the link to the real path.
type <string>
Type for HostPath Volume Defaults to "" More info:
https://kubernetes.io/docs/concepts/storage/volumes#hostpath
一个2字段
- path: 宿主机字段,如果是软连接,会跟踪到真正目录
- type:
- File:事先必须存在的文件路径; 如果不存在启动pod就报错
- Directory:事先必须存在的目录路径;
- DirectoryOrCreate:指定的路径不存时自动将其创建为0755权限的空目录,属主属组均为kubelet;
- FileOrCreate:指定的路径不存时自动将其创建为0644权限的空文件,属主和属组同为kubelet
- Socket:事先必须存在的Socket文件路径;
- CharDevice:事先必须存在的字符设备文件路径;
- BlockDevice:事先必须存在的块设备文件路径;
- “”:空字符串,默认配置,在关联hostPath存储卷之前不进行任何检查。 意味着虽然定义了 ,但是我可能会用它,也可能不用它
eg: 收集宿主机日志
[root@node01 chapter5]# cat volumes-hostpath-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: volumes-hostpath-demo
spec:
containers:
- name: filebeat
image: ikubernetes/filebeat:5.6.7-alpine
env:
- name: REDIS_HOST
value: redis.ilinux.io:6379
- name: LOG_LEVEL
value: info
volumeMounts:
- name: varlog
mountPath: /var/log
- name: socket
mountPath: /var/run/docker.sock
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: socket
hostPath:
path: /var/run/docker.sock
[root@node01 chapter5]#
验证结果 kubectl describe po/volumes-hostpath-demo
bare host directory volume 表示的是未检查,任何type 的 hostpath存储卷都行
Volumes:
varlog:
Type: HostPath (bare host directory volume)
Path: /var/log
HostPathType:
挂载点 除了varlibdockercontainers 自定义为readyonly ,其他的默认值为rw
Mounts:
/var/lib/docker/containers from varlibdockercontainers (ro)
/var/log from varlog (rw)
/var/run/docker.sock from socket (rw)
发现pod 中 /var/log 目录下的日志 就是宿主机 的
[root@node01 chapter5]# kubectl exec po/volumes-hostpath-demo -- /bin/ls -l /var/log
nfs
eg:
[root@node01 chapter5]# cat volumes-nfs-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: volumes-nfs-demo
labels:
app: redis
spec:
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
name: redisport
securityContext:
runAsUser: 1099
volumeMounts:
- mountPath: /data
name: redisdata
volumes:
- name: redisdata
nfs:
server: 192.168.2.5
path: /data/redis
readOnly: false
[root@node01 chapter5]#
在创建之前 ,每个节点都要按照 nfs-utils 驱动 。且要验证能读写 nfs 远程目录
nfs 服务配置
[root@N5 ~]# useradd -u 1099 redis [root@N5 ~]# chown 1099.1099 /data/redis [root@N5 ~]# cat /etc/exports /data/redis 192.168.0.0/16(rw) [root@N5 ~]# yum -y install nfs-utils [root@N5 ~]# systemctl enable nfs --now
node节点 安装驱动
[root@node01 ~]# yum install nfs-utils -y [root@node02 ~]# yum install nfs-utils -y
可以在一个节点先验证nfs 服务是否正常
[root@node02 ~]# yum install nfs-utils -y [root@node02 ~]# mount -t nfs 192.168.2.5:/data/redis /mnt [root@node02 ~]# useradd -u 1099 redis [root@node02 ~]# su - redis -c 'ls -l' total 0 [root@node02 ~]# su - redis -c ' > a' [root@node02 ~]# su - redis -c 'ls -l' total 0 -rw-rw-r-- 1 redis redis 0 Dec 11 14:09 a [root@node02 ~]# su - redis -c 'rm a' [root@node02 ~]# su - redis -c 'ls -l' total 0
验证 redis 使用nfs 存储卷的持久性
创建容器 ,发现它调度在node01 上
[root@node01 chapter5]# kubectl apply -f volumes-nfs-demo.yaml
[root@node01 chapter5]# kubectl get po/volumes-nfs-demo -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volumes-nfs-demo 1/1 Running 0 88s 10.244.5.38 node01 <none> <none>
在redis 创建数据, bgsave 生成快照
[root@node01 chapter5]# kubectl exec -it volumes-nfs-demo -- /bin/sh
/data $ redis-cli -h 127.0.0.1
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379>
/data $ ls /data/
dump.rdb
/data $
删除pod ,重新创建后验证, 新pod 在node02 上
[root@node01 chapter5]# kubectl get po/volumes-nfs-demo -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volumes-nfs-demo 1/1 Running 0 19s 10.244.4.44 node02 <none> <none>
验证之前存的redis数据
[root@node01 chapter5]# kubectl exec -it volumes-nfs-demo -- /bin/sh
/data $ redis-cli
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379>
/data $
pv_pvc_pvp
管理员会创建多个pv . claim 如何关联pv 呢? 所以在claim 中需要定义需求,比如 期望的存储开机是多大,期望是 单路读写还是多路读写的特性,再比如期望到哪个存储类上申请。
存储类 可以理解为是创建pv 的模板 ,也是 pv/pvc的名称空间。 意味着,我们一旦创建一个存储类叫 StorageClass ,任何pvc 绑定的目标 只能同一个StorageClass 中找pv. pv与pvc的关系叫bound 是一对一的。 一个pvc 只能绑定一个pv . 一个pv 只能被一个pvc 绑定。
pvc 有什么用?
pvc 是可以被 当成pod 的 hostpath 、emptydir 、nfs 类型的存储卷一样使用
pod 中请求pvc 格式:
[root@node01 ~]# kubectl explain pods.spec.volumes.persistentVolumeClaim
claimName <string> -required-
ClaimName is the name of a PersistentVolumeClaim in the same namespace as
the pod using this volume. More info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
readOnly <boolean>
Will force the ReadOnly setting in VolumeMounts. Default false.
claimName : 指定pod 使用的pvc
readonly: 使用的时候是只读 还是非只读 ,默认非只读
pv、pvc、pvp 调用关系
1、admin 设置一个pv 的供给方PVP: 比如 nfs 、ceph 集群。
在这个pvp 上 可以创建多个 PV , 以 nfs为例,pv1 关联至 nfs-ip:/data/redis1 pv2 关联至 nfs-ip:/data/redis2 .
而 pv 要与真正存储数据的空间Actual storage关联起来才行 (就是nfs-server真正存数据的目录),这个关联的过程是有 管理员来做的 。既可以手动来做,也可以借助存储类(图第2步)
3、用户使用存储空间时,要2步。第一先建立pvc , 让pvc 与 pv 建立关联关系。 第二步,创建pod 。在pod 中 ,创建使用pvc类型的存储卷。
PVC和PV
PVC: Persistent Volume Claim,持久卷申请,简称PVC;k8s上标准的资源类型之一; 由用户使用;名称空间级别;
PV: Persistent Volume,持久卷,可被PVC绑定;而PV一定要与某个真正的存储空间(一般是网络存储服务上的存储空间)对应起来,才能真正存储数据。由集群管理员负责管理。集群级别。
PVC创建完成后,需要找到最为匹配的PV,并与之绑定。
在哪儿找:
二者要么都不属于任何StorageClass资源,要么属于同一个StorageClass资源;
怎么找:
需要适配一大堆条件
pv资源的格式
除了存储卷插件之外,PersistentVolume资源规范Spec字段主要支持嵌套以下几个通用字段,它们用于定义PV的容量、访问模式和回收策略等属性。
[root@node01 ~]# kubectl explain pv.spec
-
capacity <map[string]string>:
指定PV的容量;目前,Capacity仅支持存储容量设定,将来还应该可以指定IOPS和吞吐量(throughput)。
-
accessModes <[]string>:
指定当前PV支持访问模式;存储系统支持存取能力大体可分为ReadWriteOnce(单路读写)、ReadOnlyMany(多路只读)和ReadWriteMany(多路读写)三种类型,某个特定的存储系统可能会支持其中的部分或全部的能力。ReadWriteOnce 在命令行中可以简写 RWO ,
ReadOnlyMany : ROX ,x 表示多路 ,o是单路
ReadWriteMany: RWX
-
persistentVolumeReclaimPolicy <string>:
PV空间被释放时的处理机制;可用类型仅为Retain(默认)、Recycle或Delete。目前,仅nfs和hostPath支持Recycle策略,也仅有部分存储系统支持Delete策略。
pv 和pvc 是一 一对应的, 如果pvc 删除了 ,pv怎么办呢?
- Retain:保留不动 ,下次创建pvc 时还能找回 。 在非strorageclass是默认的
- Recycle:把pv 上的数据统统清空 ,这时的pv又可以被其他pvc 绑定了.retain 是不能重用的,只能被同一个pvc重用 , 现在已经废弃
- Delete:删除pvc 的同时 ,把pv 也删除了。 数据也就没了。 在strorageclass是默认的
-
volumeMode <string>:
存储卷接口类型 ,有可能是文件系统 ,也有可能是块设备
该PV的卷模型,用于指定此存储卷被格式化为文件系统使用还是直接使用裸格式的块设备;默认值为Filesystem,仅块设备接口的存储系统支持该功能。
-
storageClassName <string>:
当前PV所属的StorageClass资源的名称,指定的存储类需要事先存在;默认为空值,即不属于任何存储类。 -
mountOptions <string>:
挂载选项组成的列表,例如ro、soft和hard等。 -
nodeAffinity <Object>:
节点亲和性,用于限制能够访问该PV的节点,进而会影响到使用与该PV关联的PVC的Pod的调度结果。
pv 示例: 创建pv
[root@node01 chapter5]# cat pv-nfs-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: "/data/redis001"
server: 192.168.2.5
为了 后面演示pvc ,可以创建几个 pv
[root@node01 chapter5]# cat pv-nfs-002.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-002
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: "/data/redis002"
server: 192.168.2.5
[root@node01 chapter5]# cat pv-nfs-003.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-003
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: "/data/redis003"
server: 192.168.2.5
查看创建的pv . 注意pv是全局级别的
[root@node01 chapter5]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-002 10Gi RWX Retain Available 50s
pv-nfs-003 1Gi RWO Retain Available 46s
pv-nfs-demo 5Gi RWX Retain Available 34m
available 表示现在 可以被pvc 绑定 ,但是现在还没有人绑定
pvc 资源清单格式
[root@node01 ~]# kubectl explain PersistentVolumeClaim
定义PVC时,用户可通过访问模式(accessModes)、数据源(dataSource)、存储资源空间需求和限制(resources)、存储类、标签选择器、卷模型和卷名称等匹配标准来筛选集群上的PV资源,其中,resources和accessModes是最重的筛选标准。PVC的Spec字段的可嵌套字段有如下几个。
-
accessModes <[]string>:
PVC的访问模式;它同样支持RWO、RWX和ROX三种模式;
-
dataSources <Object>:
用于从指定的数据源恢复该PVC卷,它目前支持的数据源包括一个现在卷快照对象(snapshot.storage.k8s.io/VolumeSnapshot)、一个既有PVC对象(PersistentVolumeClaim)或一个既有的用于数据转存的自定义资源对象(resource/object);
先不用管
-
resources <Object>:
声明使用的存储空间的最小值和最大值;目前,PVC的资源限定仅支持空间大小一个维度;
-
selector <Object>:
筛选PV时额外使用的标签选择器(matchLabels)或匹配条件表达式(matchExpressions);一般用的不多
-
storageClassName <string>:
该PVC资源隶属的存储类资源名称;指定了存储类资源的PVC仅能在同一个存储类下筛选PV资源,否则,就只能从所有不具有存储类的PV中进行筛选;
-
volumeMode <string>:
卷模型,用于指定此卷可被用作文件系统还是裸格式的块设备;默认值为Filesystem;
-
volumeName <string>:
直接指定要绑定的PV资源的名称。
一般不指定, 让pvc 可以动态选择
pvc 使用示例: 创建pvc
[root@node01 chapter5]# kubectl apply -f pvc-demo-0001.yaml
persistentvolumeclaim/pvc-demo-0001 created
[root@node01 chapter5]# cat pvc-demo-0001.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-demo-0001
namespace: default
spec:
accessModes: ["ReadWriteMany"]
volumeMode: Filesystem
resources:
requests:
storage: 3Gi
limits:
storage: 10Gi
验证效果: 发现 default/pvc-demo-0001 绑定 pv-nfs-demo ,而不是pv-nfs-002 。是因为 pv-nfs-demo 不仅满足 它的 卷的接口类型、访问模式,容量限制。 而且改pv 容量为5G ,更接近requests 而不是limits
查看pvc
[root@node01 chapter5]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-demo-0001 Bound pv-nfs-demo 5Gi RWX 46s
[root@node01 chapter5]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-002 10Gi RWX Retain Available 4m26s
pv-nfs-003 1Gi RWO Retain Available 4m22s
pv-nfs-demo 5Gi RWX Retain Bound default/pvc-demo-0001 37m
[root@node01 chapter5]#
pvc 使用示例:创建使用pvc 插件的pod
[root@node01 chapter5]# cat volumes-pvc-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: volumes-pvc-demo
namespace: default
spec:
containers:
- name: redis
image: redis:alpine
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1099
ports:
- containerPort: 6379
name: redisport
volumeMounts:
- mountPath: /data
name: redis-rbd-vol
volumes:
- name: redis-rbd-vol
persistentVolumeClaim:
claimName: pvc-demo-0001
直接调用 claimName 就可以指定用的pvc
[root@node01 chapter5]# cat volumes-pvc-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: volumes-pvc-demo
namespace: default
spec:
containers:
- name: redis
image: redis:alpine
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1099
ports:
- containerPort: 6379
name: redisport
volumeMounts:
- mountPath: /data
name: redis-rbd-vol
volumes:
- name: redis-rbd-vol
persistentVolumeClaim:
claimName: pvc-demo-0001
[root@node01 chapter5]#
验证结果
[root@node01 chapter5]# kubectl get po/volumes-pvc-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volumes-pvc-demo 1/1 Running 0 56s 10.244.5.41 node01 <none> <none>
验证pvc持久性
在pod中 redis容器
[root@node01 chapter5]# kubectl exec -it volumes-pvc-demo -- /bin/sh
/data $ redis-cli
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379>
/data $
[root@node01 chapter5]# kubectl delete po/volumes-pvc-demo
pod "volumes-pvc-demo" deleted
[root@node01 chapter5]# kubectl apply -f volumes-pvc-demo.yaml
pod/volumes-pvc-demo created
[root@node01 chapter5]# kubectl exec -it volumes-pvc-demo -- /bin/sh
/data $ redis-cli
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379>
/data $
[root@node01 chapter5]#
删除容器后 ,pvc 也删除了。 pv 的状态会由bound 变成 released. pv 不会被同时删除 ,因为RECLAIM POLICY使用的策略是 retain
[root@node01 chapter5]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-002 10Gi RWX Retain Available 3m42s
pv-nfs-003 1Gi RWO Retain Available 4h4m
pv-nfs-demo 5Gi RWX Retain Bound default/pvc-demo-0001 4m4s
[root@node01 chapter5]# kubectl delete po/volumes-pvc-demo
pod "volumes-pvc-demo" deleted
[root@node01 chapter5]# kubectl delete pvc/pvc-demo-0001
persistentvolumeclaim "pvc-demo-0001" deleted
[root@node01 chapter5]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-002 10Gi RWX Retain Available 4m59s
pv-nfs-003 1Gi RWO Retain Available 4h6m
pv-nfs-demo 5Gi RWX Retain Released default/pvc-demo-0001 5m21s
[root@node01 chapter5]#
如果pv 也不用了可以删除
[root@node01 chapter5]# kubectl delete pv/pv-nfs-demo
persistentvolume "pv-nfs-demo" deleted
注意 k8s 只是删除了pv ,pv存放的数据在 nfs不会被删除
因为删除pv ,只是删除了 pv 与actual storage 对应的关系
更多推荐
所有评论(0)