pod中容器的销毁重建我们会发现一个问题,容器销毁时,保存在容器中的数据也会随之被清除,因此我们需要借助Volume来实现数据的持久化。
在创建pod时,可以定义Volume,它是挂载到具体的文件目录下的,这个Volume可以被多个容器所共享。kubernetes通过Volume实现了同一个Pod中不同容器之间的数据共享以及数据的持久化存储。
Kubernetes的Volume有如下几种类型:
- 简单存储:EmptyDir、HostPath、NFS
- 高级存储:PV、PVC
- 配置存储:ConfigMap、Secret
一、简单存储类型
1、EmptyDir
该类型的Volume在Pod分配到Node上时被创建,并自动分配一个目录,因此无需指定宿主机Node上对应的目录文件。当Pod销毁时,EmptyDir中的数据也会被永久删除。
其用途如下说明:
- 临时空间:例如用于某些应用程序运行时所需的临时目录,且无须永久保留
- 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)
如下我们通过busybox读取一个springboot项目中的log信息,来演示多容器共享目录:
emptydir-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-emptydir
namespace: dev
spec:
containers:
- name: boot
image: registry.cn-hangzhou.aliyuncs.com/button_dev/test:v1.4
ports:
- containerPort: 8082
volumeMounts: # 将name为:logs-volume的volume挂载到容器中,对应的目录为/var/tmp/logs
- name: logs-volume
mountPath: /var/tmp/logs
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/boot.info.log"] # 初始命令,动态读取指定文件中内容
volumeMounts: # 将logs-volume挂载到busybox容器中,对应的目录为 /logs
- name: logs-volume
mountPath: /logs
volumes: # 声明volume,name为logs-volume,类型为emptyDir
- name: logs-volume
emptyDir: {}
然后我们查看busybox容器中的log信息,可以发现读取到了我们springboot项目的启动日志:
kubectl logs -f volume-emptydir -n dev -c busybox
2、HostPath
思考一个问题,EmptyDir在销毁时数据就丢失了,如果想长期保存这些数据,EmptyDir显然不能满足了。如果想简单的将数据持久化到主机中,可以选择HostPath。HostPath是将Node主机中一个实际目录挂载到Pod中,以供容器使用,就算pod销毁了,数据依然保存在node主机上。
vim hostpath-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-hostpath
namespace: dev
spec:
containers:
- name: boot
image: registry.cn-hangzhou.aliyuncs.com/button_dev/test:v1.4
ports:
- containerPort: 8082
volumeMounts: # 将name为logs-hostpath-volume的volume挂载到容器中,对应的目录为/var/tmp/logs
- name: logs-hostpath-volume
mountPath: /var/tmp/logs
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/boot.info.log"]
volumeMounts: # 将logs-hostpath-volume挂载到busybox容器中,对应的目录为/logs
- name: logs-hostpath-volume
mountPath: /logs
volumes: # 声明volume,name为logs-hostpath-volume,类型为hostPath
- name: logs-hostpath-volume
hostPath:
path: /mnt/logs
type: DirectoryOrCreate # 目录存在就使用,不存在就先创建后使用
type值的说明:
- DirectoryOrCreate 目录存在就使用,不存在就先创建后使用
- Directory 目录必须存在
- FileOrCreate 文件存在就使用,不存在就先创建后使用
- File 文件必须存在
- Socket unix套接字必须存在
- CharDevice 字符设备必须存在
- BlockDevice 块设备必须存在
在node2中查看对应的文件目录:
3、NFS
HostPath将pod的数据保存到了调度的node节点上,一旦node节点故障,pod被调度到了别的节点,此时相应的数据也就丢失了。所以需要单独的存储系统,我们只需要将相关数据保存至存储系统,就可以解决该问题。比较常见的存储系统有NFS、CIF等。
以nfs为例,找一台机器安装nfs(我这里直接安装到了master节点上):
#安装
yum install nfs-utils -y
#创建一个共享目录
mkdir /home/data/nfs -pv
#将共享目录的读写权限暴露给指定网段中的所有主机(根据自己网段配置)
vim /etc/exports
#配置内容如下
/home/data/nfs 192.168.242.0/24(rw,no_root_squash)
#启动nfs
systemctl restart nfs
接下来在每个kubernetes集群节点上都安装nfs,不需要配置和启动(只是为了node节点可以驱动nfs设备):
yum install nfs-utils -y
将上面的案例做些改动:
vim nfs-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-nfs
namespace: dev
spec:
containers:
- name: boot
image: registry.cn-hangzhou.aliyuncs.com/button_dev/test:v1.4
ports:
- containerPort: 8082
volumeMounts:
- name: logs-nfs-volume
mountPath: /var/tmp/logs
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/boot.info.log"]
volumeMounts:
- name: logs-nfs-volume
mountPath: /logs
volumes:
- name: logs-nfs-volume
nfs:
server: 192.168.242.134 #nfs服务器地址
path: /home/data/nfs #共享文件路径
创建完成后,我们可以查看nfs的文件目录:
一、高级存储
在kubernetes集群使用数据存储,由于所支持的存储服务众多,为了能够屏蔽底层存储的实现细节,方便我们的使用,k8s引入了PV和PVC两种资源对象。
PV(Persistent Volume)是持久化卷的意思,是对底层存储设备的一种抽象。一般该部分由管理员创建和配置。
PVC(Persistent Volume Claim)是持久化卷声明的意思,简单来说就是我们对应存储的需求声明。简而言之PVC就是用户向kubernetes系统发出的一种资源需求申请。
看到这里,简单概括一下分工:存储服务一般由存储负责的工程师维护,PV由kubernetes管理员维护,PVC由用户维护。
1、PV
资源清单如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
nfs: # 存储类型,与底层真正存储对应
capacity: # 存储能力
storage: 2Gi
accessModes: # 访问模式
storageClassName: # 存储类别
persistentVolumeReclaimPolicy: # 回收策略
参数详细说明:
(1)存储类型:根据自己的需求,不同存储类型的配置都有所差异
(2)存储能力(capacity):目前支持存储空间的设置( storage=1Gi )
(3)访问模式(accessModes):底层存储类型不同,所支持的访问模式也不同
- ReadWriteOnce(RWO):读写权限,只能被单个节点挂载
- ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
- ReadWriteMany(RWX):读写权限,可以被多个节点挂载
(4)存储类别
- 具有特定类别的PV只能与请求了该类别的PVC进行绑定
- 未设定类别的PV则只能与不请求任何类别的PVC进行绑定
(5)回收策略(persistentVolumeReclaimPolicy):底层不同的存储类型可能支持的回收策略不同
当PV不再被使用了之后,对其的处理方式: - Retain (保留):保留数据,需要管理员手工清理
在这里插入代码片
数据 - Recycle(回收):清除 PV 中的数据,效果相当于执行 rm -rf /data/*
- Delete (删除):当对应PVC删除后,动态配置的volume将自动删除
PVC的生命周期有如下几个阶段:
- Available(可用): 表示可用状态,还未被任何 PVC 绑定
- Bound(已绑定): 表示 PV 已经被 PVC 绑定
- Released(已释放): 表示 PVC 被删除,但是资源还未被集群重新声明
- Failed(失败): 表示该 PV 的自动回收失败
创建PVC:
前提准备:nfs我们暴露三个目录出来:
vim /etc/exports
```.
```bash
/home/data/pv1 192.168.242.0/24(rw,async,no_root_squash)
/home/data/pv2 192.168.242.0/24(rw,async,no_root_squash)
/home/data/pv3 192.168.242.0/24(rw,async,no_root_squash)
systemctl restart nfs
创建3个PV:
vim pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1-dev
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /home/data/pv1
server: 192.168.242.134
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2-dev
spec:
capacity:
storage: 2Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /home/data/pv2
server: 192.168.242.134
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv3-dev
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /home/data/pv3
server: 192.168.242.134
2、PVC
资源清单如下:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc
namespace: dev
spec:
accessModes: # 访问模式
selector: # 采用标签对PV选择
storageClassName: # 存储类别
resources: # 请求空间
requests:
storage: 2Gi
参数说明如下:
(1)访问模式(accessModes)
描述用户应用对存储资源的访问权限
(2)选择条件(selector)
通过对Label Selector的设置,PVC可以对系统中己存在的PV进行筛选
(3)存储类别(storageClassName)
PVC在定义时可以设定需要的后端存储的类别,只有设置了该class的pv才能被系统选出
(4)资源请求(Resources)
描述对存储资源的需求
创建PVC:
vim pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc1-dev
namespace: dev
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc2-dev
namespace: dev
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1.6Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc3-dev
namespace: dev
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
创建完成PV与PVC后接着创建Pod:
vim pvc-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod1-dev
namespace: dev
spec:
containers:
- name: boot
image: registry.cn-hangzhou.aliyuncs.com/button_dev/test:v1.4
ports:
- containerPort: 8082
volumeMounts:
- name: logs-volume
mountPath: /var/tmp/logs
volumes:
- name: logs-volume
persistentVolumeClaim:
claimName: pvc1-dev
---
apiVersion: v1
kind: Pod
metadata:
name: pod2-dev
namespace: dev
spec:
containers:
- name: boot
image: registry.cn-hangzhou.aliyuncs.com/button_dev/test:v1.4
ports:
- containerPort: 8082
volumeMounts:
- name: logs-volume
mountPath: /var/tmp/logs
volumes:
- name: logs-volume
persistentVolumeClaim:
claimName: pvc2-dev
---
apiVersion: v1
kind: Pod
metadata:
name: pod3-dev
namespace: dev
spec:
containers:
- name: boot
image: registry.cn-hangzhou.aliyuncs.com/button_dev/test:v1.4
ports:
- containerPort: 8083
volumeMounts:
- name: logs-volume
mountPath: /var/tmp/logs
volumes:
- name: logs-volume
persistentVolumeClaim:
claimName: pvc3-dev
这时我们去查看nfs中不同存储文件中的内容:
一、配置存储
1、ConfigMap
如果需要存储配置信息,可以使用ConfigMap,它是一种比较特殊的存储卷。
首先定义configmap
vim configmap.yaml
只保存了“loginname”和“password”两项配置
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap-dev
namespace: dev
data:
info: |
loginname: admin
password: 123456
创建configmap
kubectl create -f configmap.yaml
查看其详情:
创建pod
vim configmap-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-configmap
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
volumeMounts: # 将configmap挂载到目录
- name: config
mountPath: /data/configmap/config
volumes: # 引用configmap
- name: config
configMap:
name: configmap-dev
创建:
kubectl create -f configmap-pod.yaml
我们进入到容器中,查看挂载目录中的信息:
kubectl exec -it pod-configmap -n dev /bin/bash
可以发现configmap中配置的key映射成文件,value是文件中内容。
这时我们修改configmap中的内容,并重新创建configmap:
这时再进入pod中查看,内容也修改过来了:
2、Secret
对于敏感信息,可以使用Secret对象进行存储。
(1)对敏感信息进行base64编码
echo -n 'admin' | base64
echo -n '987654' | base64
(2)创建secret
vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: secret-dev
namespace: dev
type: Opaque
data:
username: YWRtaW4=
password: OTg3NjU0
(3)创建pod
vim secret-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
volumeMounts: # 将secret挂载到目录
- name: config
mountPath: /data/secret/config
volumes:
- name: config
secret:
secretName: secret-dev
创建好后进入容器中,查看对应的加密信息,已经被自动解密了: