14-K8S Basic-volume(持久卷)应用进阶(PV和PVC)
PS : PV官方文档 https://kubernetes.io/docs/concepts/storage/persistent-volumes/#
一、存储卷的概念和类型进阶
- 为了保证数据的持久性,必须保证数据在外部存储在docker容器中,为了实现数据的持久性存储,在宿主机和容器内做映射,可以保证在容器的生命周期结束,数据依旧可以实现持久性存储。但是在k8s中,由于pod分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共享,并且,在节点故障时,可能会导致数据的永久性丢失。为此,k8s就引入了外部存储卷的功能。
- k8s的存储卷类型:
[root@k8s-master ~]# kubectl explain pod.spec.volumes #查看k8s支持的存储类型
KIND: Pod
VERSION: v1
常用分类:
emptyDir(临时目录):Pod删除,数据也会被清除,这种存储成为emptyDir,用于数据的临时存储。
hostPath(宿主机目录映射):
本地的SAN(iSCSI,FC)、NAS(nfs,cifs,http)存储
分布式存储(glusterfs,rbd,cephfs)
云存储(EBS,Azure Disk)
persistentVolumeClaim →PVC(存储卷创建申请)
- 当你需要创建一个存储卷时,只需要进行申请对应的存储空间即可使用,这就是PVC。其关联关系如图:
- 上图解析:在Pod上定义一个PVC,该PVC要关联到当前名称空间的PVC资源,该PVC只是一个申请,PVC需要和PV进行关联。PV属于存储上的一部分存储空间。但是该方案存在的问题是,我们无法知道用户是什么时候去创建Pod,也不知道创建Pod时定义多大的PVC,那么如何实现按需创建呢???
- 不需要PV层,把所有存储空间抽象出来,这一个抽象层称为存储类,当用户创建PVC需要用到PV时,可以向存储类申请对应的存储空间,存储类会按照需求创建对应的存储空间,这就是PV的动态供给,如图:
- 那么PV的动态供给,其重点是在存储类的定义,其分类大概是对存储的性能进行分类的,如图:金存储类、银存储类、铜存储类等。
- 总结:
- k8s要使用存储卷,需要2步:
- 1、在pod定义volume,并指明关联到哪个存储设备
- 2、在容器使用volume mount进行挂载
- k8s要使用存储卷,需要2步:
二、PVC和PV的概念
- 我们前面提到kubernetes提供那么多存储接口,但是首先kubernetes的各个Node节点能管理这些存储,但是各种存储参数也需要专业的存储工程师才能了解,由此我们的kubernetes管理变的更加复杂的。由此kubernetes提出了PV和PVC的概念,这样开发人员和使用者就不需要关注后端存储是什么,使用什么参数等问题。如下图:
2.1、PersistentVolume(PV)
- PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。 集群中的资源就像一个节点是一个集群资源。 PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期。 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统。
2.2、PersistentVolumeClaim(PVC)
- PersistentVolumeClaim(PVC)是用户存储的请求。PVC的使用逻辑:在pod中定义一个存储卷(该存储卷类型为PVC),定义的时候直接指定大小,pvc必须与对应的pv建立关系,pvc会根据定义去pv申请,而pv是由存储空间创建出来的。pv和pvc是kubernetes抽象出来的一种存储资源。
- 虽然PersistentVolumeClaims允许用户使用抽象存储资源,但是常见的需求是,用户需要根据不同的需求去创建PV,用于不同的场景。而此时需要集群管理员提供不同需求的PV,而不仅仅是PV的大小和访问模式,但又不需要用户了解这些卷的实现细节。 对于这样的需求,此时可以采用StorageClass资源。这个在前面就已经提到过此方案。
- PV是集群中的资源。 PVC是对这些资源的请求,也是对资源的索赔检查。 PV和PVC之间的相互作用遵循这个生命周期:
Provisioning(配置)---> Binding(绑定)--->Using(使用)---> Releasing(释放) ---> Recycling(回收)
# 使用explain查看pvc
~]# kubectl explain pods.spec.volumes.persistentVolumeClaim
KIND: Pod
VERSION: v1
RESOURCE: persistentVolumeClaim <Object>
DESCRIPTION:
PersistentVolumeClaimVolumeSource represents a reference to a
PersistentVolumeClaim in the same namespace. More info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
PersistentVolumeClaimVolumeSource references the user's PVC in the same
namespace. This volume finds the bound PV and mounts that volume for the
pod. A PersistentVolumeClaimVolumeSource is, essentially, a wrapper around
another type of volume that is owned by someone else (the system).
FIELDS:
claimName <string> -required- # 指定使用的pvc名称
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.
2.3、PV是集群中的资源。 PVC是对这些资源的请求,也是对资源的索赔检查。 PV和PVC之间的相互作用遵循这个生命周期(LifeCycle)
Provisioning(配置)---> Binding(绑定)--->Using(使用)---> Releasing(释放) ---> Recycling(回收)
2.3.1、Provisioning(配置)
- 这里有两种PV的提供方式:静态或者动态:
- 静态-->直接固定存储空间:
- 集群管理员创建一些 PV。它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。
- 动态-->通过存储类进行动态创建存储空间:
- 当管理员创建的静态 PV 都不匹配用户的 PVC 时,集群可能会尝试动态地为 PVC 配置卷。此配置基于 StorageClasses:PVC 必须请求存储类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。
- 静态-->直接固定存储空间:
2.3.2、Binging(绑定)
- 在动态配置的情况下,用户创建或已经创建了具有特定数量的存储请求和特定访问模式的PersistentVolumeClaim。 主机中的控制回路监视新的PVC,找到匹配的PV(如果可能),并将 PVC 和 PV 绑定在一起。 如果为新的PVC动态配置PV,则循环将始终将该PV绑定到PVC。 否则,用户总是至少得到他们要求的内容,但是卷可能超出了要求。 一旦绑定,PersistentVolumeClaim绑定是排他的,不管用于绑定它们的模式。
- 如果匹配的卷不存在,PVC将保持无限期。 随着匹配卷变得可用,PVC将被绑定。 例如,提供许多50Gi PV的集群将不匹配要求100Gi的PVC。 当集群中添加100Gi PV时,可以绑定PVC。
2.3.3、Using(使用)
- Pod使用PVC作为卷。 集群检查声明以找到绑定的卷并挂载该卷的卷。 对于支持多种访问模式的卷,用户在将其声明用作pod中的卷时指定所需的模式。
- 一旦用户有声明并且该声明被绑定,绑定的PV属于用户,只要他们需要它。 用户通过在其Pod的卷块中包含PersistentVolumeClaim来安排Pods并访问其声明的PV。
2.3.4、Releasing(释放)
- 当用户完成卷时,他们可以从允许资源回收的API中删除PVC对象。 当声明被删除时,卷被认为是“释放的”,但是它还不能用于另一个声明。 以前的索赔人的数据仍然保留在必须根据政策处理的卷上.
2.3.5、PV的回收策略 → Recycling(回收)
- 1、Delete : 删除即删除pvc是也将对应的pv删除
- 2、Recyc : 删除pvc时仅把pv上的数据删除 # 已经被废除
- 3、Retain : pvc也不删除。pv也不删除即保留
三、PV和PVC持久卷创建介绍
3.1、PV介绍(集群资源)
- 官方手册 :https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistent-volumes
- PV为标准的K8S资源
- kubectl explain pv
- apiVersion
- v1 (pv属于k8s核心资源)
- kind
- metadata
- name (pv不属于名称空间级别资源不能定义namespace)
- spec (与volumes相像)
- accessModes : 访问模型
- ReadWriteOnce : 单路读写 ,可以简写为RWO
- ReadOnlyMany : 多路只读, 可以简写为ROX
- ReadWriteMany : 多路读写, 可以简写为RWX
- //并非以下资源都可以成为PC,以下仅为持久卷类型
- awsElasticBlockStore
- azureDisk
- azureFile
- capacity : 存储空间即存储容量(此PV打算用户存进数据的最大容量)
- storage : 定义存储空间大小
- cephfs
- cinder
- claimRef
- csi
- fc
- flexVolume
- flocker
- gcePersistentDisk
- glusterfs
- hostPath
- iscsi
- local
- mountOptions : 自定义的挂载选项(pvc想要关联此pv并被某一pod上的容易所挂载时需要添加自定义的挂载选项)
- nfs : 指定使用NFS文件系统作为PV
- path
- server
- readOnly
- nodeAffinity
- persistentVolumeReclaimPolicy : 定义PV的回收策略
- Recyc
- Delete
- Retain
- photonPersistentDisk
- portworxVolume
- quobyte
- rbd
- scaleIO
- storageClassName : 所使用的存储类
- storageos
- volumeMode :存储设备访问接口
- Filesystem : 文件系统接口
- block state : 块接口
- vsphereVolume
- accessModes : 访问模型
- status
- apiVersion
支持称为PC的设备有如下图(官网连接:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes)
支持动态供给创建的PC类型有
# explain查看定义的字段
~]# kubectl explain pv
KIND: PersistentVolume
VERSION: v1 # 也是属于K8S核心资源
DESCRIPTION:
PersistentVolume (PV) is a storage resource provisioned by an
administrator. It is analogous to a node. More info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata <Object> # PV不属于名称空间级资源所以不能定义namespace
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
spec <Object>
Spec defines a specification of a persistent volume owned by the cluster.
Provisioned by an administrator. More info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes
status <Object>
Status represents the current information/status for the persistent volume.
Populated by the system. Read-only. More info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes
-----------------------------------------------------------------------------------------------------
# 官方PV创建示例
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
3.2、PVC介绍(名称空间级别资源)
- PVC创建无非就是要指定绑定哪个PV的
- 官方手册 :https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims
- PVC为标准的K8S资源
- kubectl explain pvc
- apiVersion
- kind
- metadata
- spec
- accessModes : pvc访问模型(一定是pv所支持并定义的子集)
- dataSource
- resources :定义pvc去请求使用pv的空间(最佳选择即资源需求)
- requests :
- storage : 定义pvc请求pv存储空间大小
- requests :
- selector : 标签选择器(pvc去选择哪个pv标签符合定义的去查找,如果不设置则在所有的pv中查找)
- storageClassName
- volumeMode :存储设备访问接口
- Filesystem : 文件系统接口
- block state : 块接口
- volumeName
- status
# explain查看定义的字段
volumes]# kubectl explain pvc.spec
KIND: PersistentVolumeClaim
VERSION: v1
RESOURCE: spec <Object>
DESCRIPTION:
Spec defines the desired characteristics of a volume requested by a pod
author. More info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
PersistentVolumeClaimSpec describes the common attributes of storage
devices and allows a Source for provider-specific attributes
FIELDS:
accessModes <[]string>
AccessModes contains the desired access modes the volume should have. More
info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1
dataSource <Object>
This field can be used to specify either: * An existing VolumeSnapshot
object (snapshot.storage.k8s.io/VolumeSnapshot - Beta) * An existing PVC
(PersistentVolumeClaim) * An existing custom resource/object that
implements data population (Alpha) In order to use VolumeSnapshot object
types, the appropriate feature gate must be enabled
(VolumeSnapshotDataSource or AnyVolumeDataSource) If the provisioner or an
external controller can support the specified data source, it will create a
new volume based on the contents of the specified data source. If the
specified data source is not supported, the volume will not be created and
the failure will be reported as an event. In the future, we plan to support
more data source types and the behavior of the provisioner may change.
resources <Object>
Resources represents the minimum resources the volume should have. More
info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
selector <Object>
A label query over volumes to consider for binding.
storageClassName <string>
Name of the StorageClass required by the claim. More info:
https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1
volumeMode <string>
volumeMode defines what type of volume is required by the claim. Value of
Filesystem is implied when not included in claim spec.
volumeName <string>
VolumeName is the binding reference to the PersistentVolume backing this
claim.
-----------------------------------------------------------------------------------------------------
# 官方PV创建示例
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]}
四、持久卷使用示例
4.1、NFS类型持久卷
4.1.1、NFS持久卷使用PV和PVC图示
- 实验图如下: (NFS是PV静态提供方式需要管理员事先创建及固定存储空间)
4.1.2、配置NFS存储
~]# mkdir /volumes/{v1,v2,v3,v4,v5}
~]# vim /etc/exports
/volumes/v1 192.168.20.0/24(rw,async,no_root_squash)
/volumes/v2 192.168.20.0/24(rw,async,no_root_squash)
/volumes/v3 192.168.20.0/24(rw,async,no_root_squash)
/volumes/v4 192.168.20.0/24(rw,async,no_root_squash)
/volumes/v5 192.168.20.0/24(rw,async,no_root_squash)
~]# exportfs -avf
exporting 192.168.20.0/24:/volumes/v5
exporting 192.168.20.0/24:/volumes/v4
exporting 192.168.20.0/24:/volumes/v3
exporting 192.168.20.0/24:/volumes/v2
exporting 192.168.20.0/24:/volumes/v1
~]# showmount -e
Export list for swarm_manager1.com:
/volumes/v5 192.168.20.0/24
/volumes/v4 192.168.20.0/24
/volumes/v3 192.168.20.0/24
/volumes/v2 192.168.20.0/24
/volumes/v1 192.168.20.0/24
4.1.3、定义PV(将NFS共享定义为PV)
- kubectl explain pv.spec.nfs
- path : nfs-server端导出的真实目录(nfs服务端真实共享的目录)
- server : nfs-server的地址及端口,端口默认
- readOnly :nfs数据持久化是否为只读
- true
- false
volumes]# kubectl explain pv
volumes]# kubectl explain pv.spec.nfs
KIND: PersistentVolume
VERSION: v1
RESOURCE: nfs <Object>
DESCRIPTION:
NFS represents an NFS mount on the host. Provisioned by an admin. More
info: https://kubernetes.io/docs/concepts/storage/volumes#nfs
Represents an NFS mount that lasts the lifetime of a pod. NFS volumes do
not support ownership management or SELinux relabeling.
FIELDS:
path <string> -required-
Path that is exported by the NFS server. More info:
https://kubernetes.io/docs/concepts/storage/volumes#nfs
readOnly <boolean>
ReadOnly here will force the NFS export to be mounted with read-only
permissions. Defaults to false. More info:
https://kubernetes.io/docs/concepts/storage/volumes#nfs
server <string> -required-
Server is the hostname or IP address of the NFS server. More info:
https://kubernetes.io/docs/concepts/storage/volumes#nfs
1、编写pv资源配置清单
volumes]# cat pv.demo.yaml
# 定义pv所属的api版本群组v1即核心群组
apiVersion: v1
# 定义资源类型为pv
kind: PersistentVolume
# 定义元数据(pv为集群资源不能设置namespace字段)
metadata:
# 定义pv名称
name: pv-nfs-v2
# 定义此pc标签
labels:
storsys: nfs
# 定义pv规格
spec:
# 定义此pv提供的访问模型(访问模型一定是底层存储系统支持的,不能超出底层文件系统支持的访问模型)
# NFS服务支持:单路读写、多路只读、多路读写
accessModes: ["ReadWriteOnce","ReadOnlyMany","ReadWriteMany"]
# 存储空间即存储容量(此PV打算用户存进数据的最大容量即限制)如果不定义则默认取底层文件系统的最大值
capacity:
# 定义PV最大NFS服务存储空间使用容量为5GB
storage: 5Gi
# 定义存储设备访问接口,nfs服务提供的是文件系统接口
volumeMode: Filesystem
# 定义pv回收策略
# Delete : 删除pvc也将pv删除
# Recyc : 已经废除
# Retain : 数据保留,pvc也不删除,pv也不删除
persistentVolumeReclaimPolicy: Retain
# 指定使用nfs服务作为持久卷pv
nfs:
# nfs-server端导出的真实目录(nfs服务端真实共享的目录)
path: /volumes/v2
# nfs-server的地址及端口,端口默认
server: 192.168.20.172
2、使用声明式接口创建资源
volumes]# kubectl apply -f pv.demo.yaml
persistentvolume/pv-nfs-v2 created
3、查看创建的pv及信息
[root@k8s volumes]# kubectl get pv
# 状态可用 # 已经被哪个pvc绑定 # 存储类:这里未定义
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-v2 5Gi RWO,ROX,RWX Retain Available 42s
[root@k8s volumes]# kubectl get pv -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
pv-nfs-v2 5Gi RWO,ROX,RWX Retain Available 46s Filesystem
[root@k8s volumes]# kubectl get pv -o wide --show-labels
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE LABELS
pv-nfs-v2 5Gi RWO,ROX,RWX Retain Available 56s Filesystem storsys=nfs
4.1.4、定义PVC(PVC定义就是指定要绑定哪个PV)
- 这里定义了pvc的访问模式为多路读写,该访问模式必须在前面pv定义的访问模式之中。定义PVC申请的大小为2Gi,此时PVC会自动去匹配多路读写且大小为3Gi的PV,匹配成功获取PVC的状态即为Bound
- kubectl explain pvc.spec
1、编写pvc资源配置清单
volumes]# cat pvc-demo.yaml
# 定义pvc所属的api版本群组v1即核心群组
apiVersion: v1
# 定义资源类型为pvc
kind: PersistentVolumeClaim
# 定义元数据
metadata:
# 定义pvc名称
name: redis-data
# 定义pvc所属的名称空间(需要和要使用此pvc的pod在同一名称空间下)
namespace: vol
# 定义pvc规格
spec:
# 定义此pvc提供访问模型(pvc访问模型一定是所匹配的pv的访问模型的子集)
accessModes:
# 单路读写
- ReadWriteOnce
# 存储设备访问接口
volumeMode: Filesystem
# 定义pvc去请求使用pv的空间(最佳选择即资源需求)
resources:
requests:
# 定义pvc去使用pv使用的资源需求限定,之前定义的pv为5G,这里按需求设置
storage: 3Gi
# 定义pvc根据标签选择器去匹配定义的pv标签
selector:
matchLabels:
storsys: nfs
2、使用声明式接口创建资源
volumes]# kubectl apply -f pvc-demo.yaml
persistentvolumeclaim/redis-data created
3、查看创建的pvc信息
[root@k8s volumes]# kubectl get pvc -n vol
# 此pvc绑定的pv名称
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
redis-data Bound pv-nfs-v2 5Gi RWO,ROX,RWX 52s
[root@k8s volumes]# kubectl get pvc -n vol -o wide
# 可查看到pv的容量
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
redis-data Bound pv-nfs-v2 5Gi RWO,ROX,RWX 55s Filesystem
[root@k8s volumes]# kubectl get pvc -n vol -o wide --show-labels
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE LABELS
redis-data Bound pv-nfs-v2 5Gi RWO,ROX,RWX 64s Filesystem <none>
4、查看上面创建的pv信息
volumes]# kubectl get pv -o wide --show-labels
# 此pv装态为bind # 被哪个名称空间下的pvc bind
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE LABELS
pv-nfs-v2 5Gi RWO,ROX,RWX Retain Bound vol/redis-data 40m Filesystem storsys=nfs
4.1.5、创建自主式pod挂载pvc(创建→ 生成数据→ 删除→ 其他节点创建验证跨界点持久)
1、创建pod资源的配置清单
volumes]# cat vol-pvc-redis-daemon.yaml
# pod所属的标准资源api版本定义群组
apiVersion: v1
# 定义资源类型
kind: Pod
# 定义pod资源的元数据
metadata:
# 定义pod名称
name: redis-pvc-demo
# 定义pod所属的名称空间
namespace: vol
# 定义pod附加的标签
labels:
app: reids-pvc-demo
# 定义pod规格
spec:
# 定义pod中运行的容器
containers:
# 定义pod中运行的容器的名称
- name: redis
# 定义容器运行使用的镜像
image: redis:alpine
# 定义pod的挂在卷kubectl explain pods.spec.containers.volumentMounts
volumeMounts:
# name :指定要挂载哪一个名称的存储卷(PVC名称)(指定下面定义的volumes.-name名称)
- name: data-pvc
# mountPath :(挂载点) 挂载在容器内部的哪个路径下
mountPath: /data
# readOnly :是否以只读挂载(默认读写)
# readOnly : true/false
# 定义pod存储卷
volumes:
# 定义存储卷名称
- name: data-pvc
# 定义存储卷类型为pvc(kubectl explain pod.spec.volumes.persistentVolumeClaim)
persistentVolumeClaim:
# 定义已经创建好的PVC名称
claimName: redis-data
# readOnly :是否以只读挂载(默认读写)
# readOnly : true/false
2、使用声明式接口创建pod资源
volumes]# kubectl apply -f vol-pvc-redis-daemon.yaml
pod/redis-pvc-demo created
3、查看pod资源详情
volumes]# kubectl get pod -n vol -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp 1/1 Running 0 24h 10.244.2.27 k8s.node2 <none> <none> app=myapp
redis-pvc-demo 1/1 Running 0 66s 10.244.2.31 k8s.node2 <none> <none> app=reids-pvc-demo # 在名称为k8s.node2的node节点上运行
# 详细信息
volumes]# kubectl describe pods redis-pvc-demo -n vol
Name: redis-pvc-demo
Namespace: vol
Priority: 0
Node: k8s.node2/192.168.20.214
Start Time: Sun, 17 May 2020 16:20:22 +0800
Labels: app=reids-pvc-demo
Annotations: Status: Running
IP: 10.244.2.31
IPs:
IP: 10.244.2.31
Containers:
redis:
Container ID: docker://61d2c9741ec1e8aac1c59db5c84d09d45ddd5fd734ff1fd8588c144faad3eb05
Image: redis:alpine
Image ID: docker-pullable://redis@sha256:5f7869cb705fc567053e9ff2fac25d6bca2a680c2528dc8f224873758f17c248
Port: <none>
Host Port: <none>
State: Running
Started: Sun, 17 May 2020 16:20:23 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts: # pod中容器挂载
/data from data-pvc (rw) # pod-contaner挂载目录 from PVC名称
/var/run/secrets/kubernetes.io/serviceaccount from default-token-cmgrj (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
data-pvc: # 存储卷名称
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) # 类型为pvc
ClaimName: redis-data # 请求绑定的pvc
ReadOnly: false
default-token-cmgrj:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-cmgrj
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 115s default-scheduler Successfully assigned vol/redis-pvc-demo to k8s.node2
Normal Pulled 113s kubelet, k8s.node2 Container image "redis:alpine" already present on machine
Normal Created 113s kubelet, k8s.node2 Created container redis
Normal Started 113s kubelet, k8s.node2 Started container redis
4、master节点连入pod生成redis数据
volumes]# kubectl exec -it redis-pvc-demo -n vol -- /bin/sh
/data # redis-cli
127.0.0.1:6379> SET KEY1 "top.toptops.top"
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
/data # ls
dump.rdb
5、验证nfs-server目录(此目录做成了PV)中是否存在redis持久化文件
~]# ls /volumes/v2/
dump.rdb
6、模拟pod删除,并验证redis持久化文件是否存在
# 模拟pod删除
volumes]# kubectl delete -f vol-pvc-redis-daemon.yaml
pod "redis-pvc-demo" deleted
# 验证nfs-server是否存在redis持久化文件
~]# ls /volumes/v2/
dump.rdb
7、(跨界点持久)重建pod并手动指定运行其他node节点,模拟测试运行其他节点是否可以读取到持久化文件
volumes]# cat vol-pvc-redis-daemon.yaml
# pod所属的标准资源api版本定义群组
apiVersion: v1
# 定义资源类型
kind: Pod
# 定义pod资源的元数据
metadata:
# 定义pod名称
name: redis-pvc-demo
# 定义pod所属的名称空间
namespace: vol
# 定义pod附加的标签
labels:
app: reids-pvc-demo
# 定义pod规格
spec:
# 为了演示指定此pod运行的node节点 《----
nodeName: k8s.node1
# 定义pod中运行的容器
containers:
# 定义pod中运行的容器的名称
- name: redis
# 定义容器运行使用的镜像
image: redis:alpine
# 定义pod的挂在卷kubectl explain pods.spec.containers.volumentMounts
volumeMounts:
# name :指定要挂载哪一个名称的存储卷(指定下面定义的volumes.-name名称)
- name: data-pvc
# mountPath :(挂载点) 挂载在容器内部的哪个路径下
mountPath: /data
# readOnly :是否以只读挂载(默认读写)
# readOnly : true/false
# 定义pod存储卷
volumes:
# 定义存储卷名称
- name: data-pvc
# 定义存储卷类型为pvc(kubectl explain pod.spec.volumes.persistentVolumeClaim)
persistentVolumeClaim:
# 定义已经创建好的PVC名称
claimName: redis-data
# readOnly :是否以只读挂载(默认读写)
# readOnly : true/false
8、再次创建此pod并查看运行节点及连入pod查看redis持久化文件,键值数据是否存在
volumes]# kubectl apply -f vol-pvc-redis-daemon.yaml
pod/redis-pvc-demo created
volumes]# kubectl get pods -n vol -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp 1/1 Running 0 24h 10.244.2.27 k8s.node2 <none> <none> app=myapp
redis-pvc-demo 1/1 Running 0 37s 10.244.1.43 k8s.node1 <none> <none> app=reids-pvc-demo # 运行在k8s.node1节点上
volumes]# kubectl exec -it redis-pvc-demo -n vol -- /bin/sh
/data # ls
dump.rdb
/data # redis-cli
127.0.0.1:6379> keys * # 此前pod上创建的key是存在的
1) "KEY1"
127.0.0.1:6379>
127.0.0.1:6379> GET KEY1
"top.toptops.top"
4.1.6、验证PV回收策略
4.1.6.1、Storage Object in Use Protection (PV状态保护)
# k8s的1.11版本之后,PV保护功能,PV删除延迟,意思就是PV想要删除一个正在使用的PV时,即PV正在某PVC使用着,它是不会被删掉的。
官方手册 :https://kubernetes.io/docs/concepts/storage/persistent-volumes/#storage-object-in-use-protection
# 正在被Pod使用的PVC,被删除时会延迟删除,使用此PVC的Pod被删除后,此PVC才被删除
1、测试删除一个正在被pod使用的pvc
volumes]# kubectl get pvc -n vol
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
redis-data Bound pv-nfs-v2 5Gi RWO,ROX,RWX 52m
volumes]# kubectl delete pvc redis-data -n vol
persistentvolumeclaim "redis-data" deleted # 卡住不动
^C
volumes]# kubectl get pvc -n vol # 也未被删除
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
redis-data Terminating pv-nfs-v2 5Gi RWO,ROX,RWX 55m
2、删除pod查看pvc状态
volumes]# kubectl delete pods redis-pvc-demo -n vol
pod "redis-pvc-demo" deleted
# 删除完使用此pvc的pod后pvc要被删除
volumes]# kubectl get pvc -n vol
No resources found in vol namespace.
4.1.6.2、persistentVolumeReclaimPolicy(PV回收策略)
- 此前定义的PV的回收策略为 persistentVolumeReclaimPolicy: Retain :表示数据保留,pvc也不删除,pv也不删除,即使删除了PVC但是PV依然保留着。
- 但是没办法再次被别人使用,因为里面存在之前绑定的PVC的数据,避免被其他PVC再次绑定的
1、上面已经将使用创建的pvc的pod删除,随之pvc也被删除,查看pv状态
volumes]# kubectl get pv
# 回收机制 # 状态为释放,但是不能绑定新的pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-v2 5Gi RWO,ROX,RWX Retain Released vol/redis-data 96m
# 解决方案(手动)
# 1、删除pv
# 2、清空pv挂载服务的目录中的数据(清空有效数据),pv状态就会编程就绪状态
2、手动删除pv
volumes]# kubectl delete pv pv-nfs-v2
persistentvolume "pv-nfs-v2" deleted
3、前往nfs服务的共享真实目录下查看到数据还是存在的
~]# ls /volumes/v2/
dump.rdb
~]# rm -rf /volumes/v2/dump.rdb
4.2、NFS使用PV和PVC博客鉴赏
- 实验图如下:
[root@k8s-master ~]# kubectl explain pv #查看pv的定义方式
FIELDS:
apiVersion
kind
metadata
spec
[root@k8s-master ~]# kubectl explain pv.spec #查看pv定义的规格
spec:
nfs(定义存储类型)
path(定义挂载卷路径)
server(定义服务器名称)
accessModes(定义访问模型,有以下三种访问模型,以列表的方式存在,也就是说可以定义多个访问模式)
ReadWriteOnce(RWO) 单节点读写
ReadOnlyMany(ROX) 多节点只读
ReadWriteMany(RWX) 多节点读写
capacity(定义PV空间的大小)
storage(指定大小)
[root@k8s-master volumes]# kubectl explain pvc #查看PVC的定义方式
KIND: PersistentVolumeClaim
VERSION: v1
FIELDS:
apiVersion <string>
kind <string>
metadata <Object>
spec <Object>
[root@k8s-master volumes]# kubectl explain pvc.spec
spec:
accessModes(定义访问模式,必须是PV的访问模式的子集)
resources(定义申请资源的大小)
requests:
storage:
4.2.1、配置nfs存储
[root@stor01 volumes]# mkdir v{1,2,3,4,5}
[root@stor01 volumes]# vim /etc/exports
/data/volumes/v1 192.168.56.0/24(rw,no_root_squash)
/data/volumes/v2 192.168.56.0/24(rw,no_root_squash)
/data/volumes/v3 192.168.56.0/24(rw,no_root_squash)
/data/volumes/v4 192.168.56.0/24(rw,no_root_squash)
/data/volumes/v5 192.168.56.0/24(rw,no_root_squash)
[root@stor01 volumes]# exportfs -arv
exporting 192.168.56.0/24:/data/volumes/v5
exporting 192.168.56.0/24:/data/volumes/v4
exporting 192.168.56.0/24:/data/volumes/v3
exporting 192.168.56.0/24:/data/volumes/v2
exporting 192.168.56.0/24:/data/volumes/v1
[root@stor01 volumes]# showmount -e
Export list for stor01:
/data/volumes/v5 192.168.56.0/24
/data/volumes/v4 192.168.56.0/24
/data/volumes/v3 192.168.56.0/24
/data/volumes/v2 192.168.56.0/24
/data/volumes/v1 192.168.56.0/24
4.2.2、定义PV
- 这里定义5个PV,并且定义挂载的路径以及访问模式,还有PV划分的大小。
[root@k8s-master volumes]# kubectl explain pv
[root@k8s-master volumes]# kubectl explain pv.spec.nfs
[root@k8s-master volumes]# vim pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
name: pv001
spec:
nfs:
path: /data/volumes/v1
server: stor01
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/volumes/v2
server: stor01
accessModes: ["ReadWriteOnce"]
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/volumes/v3
server: stor01
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv004
labels:
name: pv004
spec:
nfs:
path: /data/volumes/v4
server: stor01
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 4Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels:
name: pv005
spec:
nfs:
path: /data/volumes/v5
server: stor01
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 5Gi
[root@k8s-master volumes]# kubectl apply -f pv-demo.yaml
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
[root@k8s-master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 1Gi RWO,RWX Retain Available 7s
pv002 2Gi RWO Retain Available 7s
pv003 2Gi RWO,RWX Retain Available 7s
pv004 4Gi RWO,RWX Retain Available 7s
pv005 5Gi RWO,RWX Retain Available 7s
4.2.3、定义PVC
- 这里定义了pvc的访问模式为多路读写,该访问模式必须在前面pv定义的访问模式之中。定义PVC申请的大小为2Gi,此时PVC会自动去匹配多路读写且大小为2Gi的PV,匹配成功获取PVC的状态即为Bound
[root@k8s-master volumes ~]# vim pod-vol-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-pvc
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: mypvc
[root@k8s-master volumes]# kubectl apply -f pod-vol-pvc.yaml
persistentvolumeclaim/mypvc created
pod/pod-vol-pvc created
[root@k8s-master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 1Gi RWO,RWX Retain Available 19m
pv002 2Gi RWO Retain Available 19m
pv003 2Gi RWO,RWX Retain Bound default/mypvc 19m
pv004 4Gi RWO,RWX Retain Available 19m
pv005 5Gi RWO,RWX Retain Available 19m
[root@k8s-master volumes]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound pv003 2Gi RWO,RWX 22s
4.2.4、测试访问
- 在存储服务器上创建index.html,并写入数据,通过访问Pod进行查看,可以获取到相应的页面。
[root@stor01 volumes]# cd v3/
[root@stor01 v3]# echo "welcome to use pv3" > index.html
[root@k8s-master volumes]# kubectl get pods -o wide
pod-vol-pvc 1/1 Running 0 3m 10.244.2.39 k8s-node02
[root@k8s-master volumes]# curl 10.244.2.39
welcome to use pv3
五、StorageClass(存储类)
5.1、StorageClass(存储类)介绍
- 官方参考手册 :https://kubernetes.io/zh/docs/concepts/storage/storage-classes/
- 在pv和pvc使用过程中存在的问题,在pvc申请存储空间时,未必就有现成的pv符合pvc申请的需求,上面nfs在做pvc可以成功的因素是因为我们做了指定的需求处理。那么当PVC申请的存储空间不一定有满足PVC要求的PV事,又该如何处理呢???为此,Kubernetes为管理员提供了描述存储"class(类)"的方法(StorageClass)。举个例子,在存储系统中划分一个1TB的存储空间提供给Kubernetes使用,当用户需要一个10G的PVC时,会立即通过restful发送请求,从而让存储空间创建一个10G的image,之后在我们的集群中定义成10G的PV供给给当前的PVC作为挂载使用。在此之前我们的存储系统必须支持restful接口,比如ceph分布式存储,而glusterfs则需要借助第三方接口完成这样的请求。如图:
[root@k8s-master ~]# kubectl explain storageclass #storageclass也是k8s上的标准资源(简称为sc)
KIND: StorageClass
VERSION: storage.k8s.io/v1
FIELDS:
allowVolumeExpansion <boolean>
allowedTopologies <[]Object>
apiVersion <string>
kind <string>
metadata <Object>
mountOptions <[]string> # 挂载选项
parameters <map[string]string> # 参数,取决于分配器,可以接受不同的参数。 例如,参数 type 的值 io1 和参数 iopsPerGB 特定于 EBS PV。当参数被省略时,会使用默认值。
provisioner <string> -required- # 存储分配器,用来决定使用哪个卷插件分配 PV。该字段必须指定。
reclaimPolicy <string> # 回收策略,可以是 Delete 或者 Retain。如果 StorageClass 对象被创建时没有指定 reclaimPolicy ,它将默认为 Delete。
5.2、StorageClass(存储类)示例
- StorageClass 中包含 provisioner、parameters 和 reclaimPolicy 字段,当 class 需要动态分配 PersistentVolume 时会使用到。由于StorageClass需要一个独立的存储系统,此处就不再演示。从其他资料查看定义StorageClass的方式如下:
chapter7]# cat glusterfs-storageclass.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1beta1
metadata:
name: gluster-dynamic
provisioner: kubernetes.io/glusterfs
parameters:
resturl: "http://172.16.2.36:8080"
restauthenabled: "false"
------------------------------------------
chapter7]# cat ceph-secret-storageclass.yaml
apiVersion: v1
kind: Secret
metadata:
name: ceph-secret
namespace: kube-system
type: kubernetes.io/rbd
data:
key: QVFBTEhLRmF0MDdxQ2hBQWY4RFF6N3VFYVJlTFZUQTBJSndQeWc9PQo=
5.3、NFS可借助第三方完成动态供给
向往的地方很远,喜欢的东西很贵,这就是我努力的目标。