K8s存储
Volume: 数据卷
kubernetes Pod中多个容器访问的共享目录。volume被定义在pod上,被这个pod的多个容器
挂载到相同或不同的路径下。volume的生命周期与pod的生命周期相同,pod内的容器停止和
重启时一般不会影响volume中的数据。所以一般volume被用于持久化pod产生的数据。
volume类型:
emptyDir
hostPath
gcePersistentDisk
awsElasticBlockStore
nfs
iscsi
flocker
glusterfs
rbd
cephfs
gitRepo
secret
persistentVolumeClaim
downwardAPI
azureFileVolume
azureDisk
vsphereVolume
Quobyte
emptyDir:
emptyDir的生命周期与所属的pod相同。
pod删除时,其emptyDir中的数据也会被删除。
emptyDir类型的volume在pod分配到node上时被创建,kubernetes会在node上自动分配一个目录,因此无需指定宿主机node上对应的目录文件。
emptyDir Volume主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等。
注:一般用于容器数据卷共享,不能做持久化数据存储。
//写一个emptyDir.yaml的文件。
—yaml
kind: Pod
apiVersion: v1
metadata:
name: producer-consumer
spec:
containers:
name: producer
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts:
name: consumer
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts:
volumes:
总结:
根据上述yaml文件分析,volumes是指k8s的存储方案.容器内volumeMounts使用的是volumes内定义的存储,所以现在可以理解为,volumes定义的dockerHost上的目录或文件,分别挂载到了producer(/producer_dir)和consumer(/consumer_dir)这个两个容器的对应目录。那么安装这个方法,我们可以判断出,在consumer这个容器的/consumer_dir目录下,应该也会有一个hello.txt的文件。
//验证,查看conumer容器的日志。
[root@master volume]# kubectl logs producer-consumer consumer
hello world
//查看一个Pod运行在了那个Node节点上
[root@master volume]# kubectl get pod -o wide
//到对应Node节点上查看该容器的详细信息(Mounts)
[root@node01 ~]# docker inspect 413d5dbd0239
…
“Mounts”: [
{
“Type”: “bind”,
“Source”: “/var/lib/kubelet/pods/82a382ce-78aa-48f1-933b-685ce2ba7a3d/volumes/kubernetes.io~empty-dir/shared-volume”,
“Destination”: “/producer_dir”,
“Mode”: “”,
“RW”: true,
“Propagation”: “rprivate”
},
PS: 查看到该容器的Mounts字段,等于是运行docker容器的时候使用这么一条命令:
docker run -v /producer_dir busybox
emptyDir的使用场景:如果Pod的被删除,那么数据也会被删除,不具备持久化。Pod内的容器,需要
共享数据卷的时候,使用的临时数据卷。
HostPath:
hostPath卷将主机节点的文件系统中的文件或目录挂载到集群中。
相对于emtpyDir来说,hostPath就等于运行容器是使用的命令:
docker run -v /host/path:/container/path
除了path属性之外,用户还可以指定type:
空 空字符串(默认),挂载hostPath卷之前不会执行任何检查
DirectoryOrCreate 如果指定的位置没有目录,将创建空目录,权限755,与kubelet具有相同的所有权
Directory 指定的位置必须存在目录
FileOrCreate 如果指定的位置没有文件,将创建空文件,权限644,与kubelet具有相同的所有权
File 指定的位置必须存在文件
Socket 指定的位置必须存在Unix套接字
CharDevice 指定的位置必须存在字符设备
BlockDevice 指定的路径下必须存在块设备
//这里没有创建新的yaml文件,直接将emptyDir.yaml文件的volumes字段更改为:hostPath.
[root@node01 volume]#
…
volumes:
注:对比emptyDIR,hostPath具有持久性:即容器删除,数据卷还在
=================================
PV、PVC
PV: Persistent(持久的、稳固的)Volume
由管理员设置的存储,是集群的一部分,就像node节点一样,PV也是集群的资源。PV是volume之类的卷插件,但独立于使用PV的pod的生命周期。此api对象包含存储实现的细节,即nfs、iscsi、ceph或云存储等。
是k8s集群的外部存储系统,一般是设定好的存储空间(文件系统中的一个目录)。
PVC: PersistentvolumeClaim(声明、申请)
是用户存储的请求,它与pod相似。pod消耗节点资源,PVC消耗PV资源。pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(只读/读写)。
如果应用需要用到持久化的时候,可以直接向PV申请空间。
基于NFS服务来创建的PV:
//3台节点都安装nfs-工具包和rpc-bind服务。
[root@master ~]# yum install nfs-utils rpcbind -y
//这里准备将NFS服务部署在master节点上,需要在master节点上提前规划好共享的目录
[root@master ~]# mkdir /nfsdata
[root@master ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)
[root@master ~]# systemctl start rpcbind
[root@master ~]# systemctl enable rpcbind
[root@master ~]# systemctl start nfs-server
[root@master ~]# systemctl enable nfs-server
[root@master ~]# showmount -e
//创建pv1.yaml文件
—yaml
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfsdata
server: 192.168.8.10
PV所支持的访问模式:
ReadWriteOnce: PV能以read-write的模式mount到单个节点。(命令模式:RWO)
ReadOnlyMany: PV能以read-only 的模式mount到多个节点。(命令模式:ROX)
ReadWriteMany: PV能以read-write的模式Mount到多个节点。(命令模式:RWX)
PV状态:
Available(可用):一块空闲资源还没有被任何声明绑定
Bound(绑定):卷已经被声明绑定
Released(已释放):声明被删除,但是资源还未被集群重新声明
Failed(失败):该卷的自动回收失败
PV空间的回收策略:persistentVolumeReclaimPolicy
Recycle: 回收,会清除数据,自动回收(最新k8s版本已不支持)。
Retain: 保留,需要手动清理回收。
Delete: 删除,关联的存储资产(AWS EBS,GCE PD,Azure Disk和Openstack Cinder卷)将被删除
注:只有nfs和hostPath支持回收策略,AWS EBS,GCE PD,Azure Disk和Cinder支持删除策略
关于pv所支持的访问模式的理解:
读写方面: 如果是可以读写的,则认为,Pod可以在挂载的路径下,执行读写操作。如果是只读的,那么Pod就只能够读取PV共享目录下的数据了。
节点方面:所谓挂载到单个或者多个节点,指的是Kuberntes的工作节点(node节点)
验证结果(不完全正确):
1)kubernetes官方表示,ReadOnly是以只读的方式挂载,但实际的验证结果仍需要在挂载时指定其挂
载类型为ReadOnly: true,才可以实现只读。
2)这里所说的挂载至单节点或多节点,和官方描述不一致。具体实现方法,有待进一步验证。
官网描述: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
重要提醒!
每个卷只能同一时刻只能以一种访问模式挂载,即使该卷能够支持 多种访问模式。例如,一个 GCEPersistentDisk 卷可以被某节点以 ReadWriteOnce 模式挂载,或者被多个节点以ReadOnlyMany 模式挂载,但不可以同时以两种模式挂载。
//创建一个PVC,向刚才的PV申请使用空间,注意,这里PV与PVC的绑定,通过storageClassName和accessModes这两个字段共同决定。
—yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc1
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs
resources:
requests:
storage: 1Gi
总结:
1. 当系统中的pv被绑定之后,就不会被其他的PVC绑定了。
2. 如果系统中有多个能够满足pvc要求的pv,那么,系统会自动选择一个符合pvc申请空间大小的PV,进行绑定,尽量不浪费存储空间。
//创建一个Pod,来使用上述PVC。
kind: Pod
apiVersion: v1
metadata:
name: pod1
spec:
containers:
=======================================
PV的空间回收
当回收策略为recycle
[root@master ~]# kubectl get pv,pvc
// 验证dockerhost上PV上存放的数据
[root@master ~]# ls /nfsdata/
test.txt
//删除Pd资源,PVC
[root@master ~]# kubectl delete pod pod1
pod “pod1” deleted
[root@master ~]# kubectl delete pvc pvc1
persistentvolumeclaim “pvc1” deleted
//查看PV的过程,Released(释放)—>Available(可用)。
[root@master ~]# kubectl get pv
//验证,数据依然被删除
[root@master ~]# ls /nfsdata
无数据
PS: 在释放空间的过程中,其实K8S生成了一个新的Pod,由这个Pod执行删除数据的操作。
当回收策略为: Retain
…
persistentVolumeReclaimPolicy: Retain //更改回收策略为保留
//重新运行pvc1,pod资源,然后在Pod内,创建对应的资源,再尝试删除PVC,和Pod,验证PV目录
下,数据是否还会存在?
[root@master ~]# kubectl apply -f pvc1.yaml
[root@master ~]# kubectl apply -f pod.yaml
[root@master ~]# kubectl exec pod1 touch /data/test.txt
[root@master ~]# ls /nfsdata/
test.txt
//再次删除Pod,PVC,验证PV目录下存放的数据
[root@master ~]# kubectl delete pod pod1
[root@master ~]# kubectl delete pvc pvc1
[root@master ~]# ls /nfsdata/
test.txt
//修复状态released为 Available
[root@master ~]# kubectl edit pv pv1
删除 claimRef: 字段
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: pvc1
namespace: default
resourceVersion: “111021”
uid: d7ef17f9-ad63-4907-a277-0e172496e1ec
================================================
PV,PVC的运用
现在部署一个MySQL服务,并且将MySQL的数据进行持久化存储。
1、创建PV,PVC
vim mysql-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
name: mysql-pv
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 1Gi
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfsdata/mysql-pv
server: 192.168.8.10
vim mysql-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs
resources:
requests:
storage: 1Gi
[root@master MySQL]# mkdir /nfsdata/mysql-pv
[root@master MySQL]# kubectl apply -f mysql-pv.yaml
[root@master MySQL]# kubectl apply -f mysql-pvc.yaml
[root@master MySQL]# kubectl get pv,pvc
2、部署MySQL
vim mysql.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_ROOT_PASSWORD
value: 123.com
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
kind: Service
apiVersion: v1
metadata:
name: mysql
spec:
type: NodePort
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
nodePort: 31306
3、在MySQL数据库中添加数据
[root@master ~]# kubectl exec -it mysql-6fccccd487-5q2dt – mysql -uroot -p123.com
mysql> SHOW DATABASES; //查看当前的库。
mysql> CREATE DATABASE TEST; //创建test库。
mysql> USE TEST; //选择使用test库。
mysql> CREATE TABLE my_id(id int(4)); //创建my_id表
mysql> INSERT my_id values (9527); //往my_id表中,插入数据。
mysql> SELECT * FROM my_id; //查看my_id表中所有数据
4、模拟MySQ服务器节点故障
k8s集群会生产一个新的Pod,验证这个Pod内是否有之前数据。
//先查看运行MySQL服务的Pod,在哪个节点,然后将该节点挂起,我们知道k8s肯定会在另外一个节点重新生成一个Pod
[root@master ~]# kubectl get pod -o wide
//新生成Pod后,同样进入Pod验证数据是否会会存在,
[root@master MySQL]# kubectl exec -it mysql-5d86c64fc9-p7hv6 – mysql -u root -p123.com
mysql> show databases;
mysql> use TEST;
mysql> show tables;
mysql> select * from my_id;