一、持久化Volumes
数据持久化:
容器部署过程中一般有以下三种数据:
• 启动时需要的初始数据,例如配置文件;
• 启动过程中产生的临时数据,该临时数据需要多个容器间共享;
• 应用运行过程中产生的持久化数据,例如MySQL的data目录;
数据卷的分类:
本地(hostPath,emptyDir等)
网络(NFS,Ceph,GlusterFS等)
公有云(阿里云OSS,NAT / AWS EBS等)
K8S资源(configmap,secret等)
二、emptyDir(临时存储卷)
- 1、emptyDir存储卷是Pod对象生命周期中的一个临时目录,在Pod对象启动时即被创建,而在Pod对象被移除时会被彻底删除;
- 2、不具有持久能力的emptyDir存储卷只能用于某些特殊场景中;
- 3、emptyDir只是一个临时挂载的文件,pod删除后,该目录也会在node节点上被删除,但是容器崩溃时,该文件还存在;
#案例一: 暂存空间,用作长时间计算崩溃恢复时的检查点;
# cat emptydir-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: emptydir-nginx
spec:
containers:
- name: emptydir-nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /data/ #添加容器内部的挂载点
name: emptydir-name
volumes:
- name: emptydir-name
emptyDir: #创建一个空目录
sizeLimit: 1G #目录容量大小为1G
## 进入容器并在容器中创建文件测试
kubectl exec -it emptydir-nginx /bin/bash
echo $(date +%Y%m%d-%H:%M:%S) >> /data/time.log
## 在对应的node节点上查找临时存储的文件位置
find / -name "emptydir-nginx"
## 查看并验证文件内容
## 在master节点上删除pod后,再次验证数据是否存在
cat: time.log: No such file or directory
#案例二: Pod内的多个容器间文件的共享,或者作为容器数据的临时存储目录用于数据缓存系统等
apiVersion: v1
kind: Pod
metadata:
name: producer-consumer
spec:
containers:
- name: producer
image: busybox
volumeMounts:
- name: shared-volume
mountPath: /producer_dir
command: [ "/bin/sh", "-c" ]
args:
- while true; do
echo $(hostname) $(date) >> /producer_dir/hello;
sleep 5;
done
- name: consumer
image: busybox
volumeMounts:
- name: shared-volume
mountPath: /consumer_dir
args:
- /bin/sh
- -c
- cat /consumer_dir/hello ; sleep 3600
volumes:
- name: shared-volume
emptyDir: {}
## 测试验证
# kubectl exec -it producer-consumer -c producer /bin/sh
/ # tail -f /producer_dir/hello
# kubectl exec -it producer-consumer -c consumer /bin/sh
/ # tail -f /consumer_dir/hello
案例流程:
这里我们模拟了一个 producer / consumer 场景。Pod 有两个容器 producer和 consumer,它们共享一个 Volume。producer 负责往 Volume 中写数据,其每隔5秒生成一行信息追加到存储卷上的hello文件中, consumer 则是从 Volume 读取数据。
- 1、文件最底部 volumes 定义了一个 emptyDir 类型的 Volume shared-volume。
- 2、producer 容器将 shared-volume mount 到 /producer_dir 目录。
- 3、producer 通过 echo 将数据写到文件 hello 里。
- 4、consumer 容器将 shared-volume mount 到 /consumer_dir 目录。
- 5、consumer 通过 cat 从文件 hello 读数据。
总结:
emptyDir 是Host上创建的临时目录;
优点:能够方便地为 Pod 中的容器提供共享存储,不需要额外的配置。
缺点:不具备持久性,如果 Pod 不存在了,emptyDir 也就没有了。
三、hostPath(节点存储卷)
hostPath卷是指将工作节点上某文件系统的目录或文件挂载于Pod中的一种存储卷,它可独立于Pod资源的生命周期,因而具有持久性。
支持的 type 值如下:
取值 |
解释 |
空字符串(默认) |
在安装 hostPath 卷之前不会执行任何检查 |
DirectoryOrCreate |
目录存在就使用,不存在就先创建,权限设置为 0755 |
Directory |
目录必须存在 |
FileOrCreate |
文件存在就使用,不存在就先创建,权限设置为 0644 |
File |
文件必须存在 |
Socket(不常用) |
在给定路径上必须存在的 UNIX 套接字 |
CharDevice(不常用) |
在给定路径上必须存在的字符设备 |
BlockDevice(不常用) |
在给定路径上必须存在的块设备 |
#案例一:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-hook-exec
spec:
replicas: 1
selector:
matchLabels:
app: pod-hook-exec
template:
metadata:
labels:
app: pod-hook-exec
spec:
terminationGracePeriodSeconds: 8 # 设置8秒宽限时间,默认是30s
initContainers:
- name: init-containers
image: busybox
command: ["sh","-c","echo init-containers...|tee -a /tmp/pod-hook-exec.log;sleep 5s"]
volumeMounts:
- name: logs
mountPath: /tmp/
containers:
- name: main-container
image: busybox
command: ["sh","-c","echo main-container...|tee -a /tmp/pod-hook-exec.log;sleep 3600s"]
volumeMounts:
- name: logs
mountPath: /tmp/
startupProbe:
exec:
command: ["sh","-c","echo startupProbe...|tee -a /tmp/pod-hook-exec.log;sleep 5s"]
timeoutSeconds: 10
livenessProbe:
exec:
command: ["sh","-c","echo livenessProbe...|tee -a /tmp/pod-hook-exec.log;sleep 5s"]
timeoutSeconds: 10
readinessProbe:
exec:
command: ["sh","-c","echo readinessProbe...|tee -a /tmp/pod-hook-exec.log;sleep 5s"]
timeoutSeconds: 10
lifecycle:
postStart:
exec: #在容器启动的时候执行一个命令
command: ["sh","-c","echo postStart...|tee -a /tmp/pod-hook-exec.log;sleep 5s"]
preStop: # 在pod停止之前执行这个命令
exec:
command: ["sh","-c","echo preStop...|tee -a /tmp/pod-hook-exec.log"]
volumes:
- name: logs #和上面保持一致 这是本地的文件路径,上面是容器内部的路径
hostPath:
path: /tmp/logs/
type: Directory
最终我们可以通过容器所在宿主机的 /tmp/logs/
去查看应用的 pod-hook-exec.log
日志;
四、StorageClass
1、StorageClass持久化存储介绍
k8s支持两种资源的供应模式:静态模式(Static)和动态模式(Dynamic)。
1、静态模式:集群管理员手工创建PV,在定义PV时需要将后端存储的特性进行设置。
2、动态模式:集群管理员无需手工创建PV,而是通过StorageClass的设置对后端存储进行描述,标记为某种类型。此时要求PVC对存储的类型进行声明,系统将自动完成PV的创建及与PVC的绑定。
1.1、PV的回收策略(persistentVolumeReclaimPolicy)
策略 |
解释 |
保持(Retain) |
删除PV后后端存储上的数据仍然存在,如需彻底删除则需要手动删除后端存储volume; |
删除(Delete) |
删除被PVC释放的PV和后端存储volume; |
回收(Recycle) |
保留PV,但清空PV上的数据 |
1.2、PV的状态
状态 |
解释 |
Available |
可用 |
Bound |
已经成功和PVC进行了绑定。 |
Released |
PVC 解绑但还未执行回收策略。 |
Failed |
发生错误 |
StorageClass依赖一个自动配置程序,比如我们的后端存储是nfs,那么就需要一个nfs-client的自动配置程序,也称为Provisione,StorageClass也是靠这个Provisione自动配置程序来实现自动创建PV持久卷;
自动创建 的PV以 {namespace}-${pvcname}-${pvname}
进行命名到服务器上创建相应的目录
当pv被回收 后会以 archieved-${namespace}-${pvcname}-${pvname}
格式存在服务器上
storageclass自动创建的pv命名规则:pvc-${PVC_UID}
五、StorageClass应用场景
- statefulset控制器下每个pod都需要使用单独的pvc
- 动态创建PVC(企业中最常用的存储方式)
2.1、原理(NFS为例):
首先管理员想storageClass声明我需要一个PVC-test的存储,这时storageclass就去找自动配置程序也就是nfs-client-provisioner,由nfs-client-provisioner去创建一个PV,并将PV的数据存储在对应的nfs设备上,然后再从PV中分出一个PVC-test,最后挂载到Pod上实现持久化存储;
2.2、NFS 部署(略)
2.3、storageclass存储资源清单文件
##定义storageclass
apiVersion: storage.k8s.io/v1 //版本号
kind: StorageClass //类型为StorageClass
metadata: //定义元数据
name: nfs-storageclass //storageclass名称
provisioner: nfs-storage-01 //指定使用哪个nfs-client-provisioner
reclaimPolicy: Retain //回收策略
创建一个pvc引用storageclass自动创建pv
1.编写yaml文件
# vim test-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
storageClassName: nfs-storageclass #指定storageclass的名称
accessModes:
- ReadWriteMany
resources:
requests:
storage: 500Mi
2.创建资源
# kubectl create -f test-pvc.yaml
persistentvolumeclaim/test-pvc created
3.查看pv和pvc的状态
# kg pv,pvc |grep test-pvc
(1)使用deployment资源引用创建的PVC资源
1.编写yaml文件
# vim nginx-deploy-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-pv
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-pv
image: nginx:1.17.1
volumeMounts:
- name: nginx-data
mountPath: /usr/share/nginx
volumes:
- name: nginx-data
persistentVolumeClaim:
claimName: test-pvc #指定如上pvc
readOnly: false
2.创建资源
# kubectl create -f nginx-deploy.yaml
3.进入容器产生数据
# kubectl exec -it nginx-pv-56646f947b-twq2m /bin/bash
root@nginx-pv-56646f947b-twq2m:/# cd /usr/share/nginx/
root@nginx-pv-56646f947b-twq2m:/usr/share/nginx# for i in {1..10};do echo "this is web${i}" >> index.html; sleep 1;done
4.查看云存储(NFS)上是否有数据产生
# ll default-test-pvc-pvc-4bd5e8d9-1b38-48a8-a04a-1261eaa0b00f/
总用量 4
-rw-r--r-- 1 root root 131 5月 18 14:05 index.html
(2)使用StatefulSet控制器引入StorageClass
#需求: 使用statfulset部署nginx,每个pod使用不同的pvc存储数据。
# vim nginx-statfuleset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-storage-stat
spec:
replicas: 3
serviceName: "nginx"
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
volumeMounts:
- name: nginx-storage-test-pvc
mountPath: /usr/share/nginx/html
volumeClaimTemplates: #在statfulset.spec下定义pvc模板,里面的配置参数和pvc的一致
- metadata: #定义元数据
name: nginx-storage-test-pvc #pvc的名称,要与volumeMounts中的名称一致
spec: #定义属性
storageClassName: nfs-storageclass #指定使用哪个storageclass
accessModes: #访问模式为多主机可读写
- ReadWriteMany
resources: #分配的资源大小
requests:
storage: 1Gi
## 查看是否为每个pod分配了pvc
# kg pvc |grep nginx-storage-test
## 在每个pod上写入数据验证持久化
# kubectl exec -it nginx-storage-stat-0 bash
# echo nginx00000000000 > /usr/share/nginx/html/nginx-storage-stat-0
# kubectl exec -it nginx-storage-stat-1 bash
# echo nginx11111111111 > /usr/share/nginx/html/nginx-storage-stat-1
# kubectl exec -it nginx-storage-stat-2 bash
# echo nginx22222222222 > /usr/share/nginx/html/nginx-storage-stat-2
## 验证底层数据是否存在
## 删除StatefulSet验证数据完整性
总结:
- statefulset创建的pvc,即使删除statefulset控制器、PVC是不会删除的;
- 下次重建statefulset控制器,重新使用StorageClass创建pvc,数据依旧是存在的;
服务器租用托管,机房租用托管,主机租用托管,https://www.e1idc.com