一、数据存储概述
背景
容器中的文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题。 首先,当容器崩溃时,kubelet 将重新启动容器,容器中的文件将会丢失——因为容器会以干净的状态重建。 其次,当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。 Kubernetes 抽象出 Volume 对象来解决这两个问题。
所以,为了持久化保存容器的数据和容器之间数据共享,kubernetes引入了Volume的概念。
概念
Volume是k8s抽象出来的对象,用于解决Pod中的容器运行时,文件存放的问题以及多容器数据共享的问题。Kubernetes 卷具有明确的生命周期——与包裹它的 Pod 相同。卷比 Pod 中运行的任何容器的存活期都长,在容器重新启动时数据也会得到保留。
Volume是Pod中能够被多个容器访问的共享目录,它被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。
更重要的是,Kubernetes 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。卷的核心是包含一些数据的目录,Pod 中的容器可以访问该目录。 特定的卷类型可以决定这个目录如何形成的,并能决定它支持何种介质,以及目录中存放什么内容。
使用卷时, Pod 声明中需要提供卷的类型(.spec.volumes 字段)和卷挂载的位置 (.spec.containers.volumeMounts 字段)。
Volume的生命容器不与Pod中单个容器的生命周期相关。
kubelet创建Pod时,会先创建一个基础容器pause,Pod里面所有的容器共享一个网络名称空间和文件系统。挂载卷的工作就是由基础容器pause来完成的。
卷的类型
Kubernetes 支持下列类型的卷:
- awsElasticBlockStore、azureDisk、azureFile、cephfs、cinder、configMap、csi
- downwardAPI、emptyDir、fc (fibre channel)、flexVolume、flocker、
- gcePersistentDisk、gitRepo (deprecated)、glusterfs、hostPath、iscsi
- local、nfs、persistentVolumeClaim、projected、secret、storageos、vsphereVolume
kubernetes的Volume支持多种类型,比较常见的有下面几个:
- 简单存储: EmptyDir、HostPath、NFS
- 高级存储: PV、PVC
- 配置存储: ConfigMap、 Secret
二、基本存储
(一)EmptyDir
EmptyDir是最基础的Volume类型,一个EmptyDir就是Host上的一 个空目录。
EmptyDir是在Pod分配到Node时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为kubernetes会自动分配一个目录, 当Pod销毁时,EmptyDir中的数据也会被永久删除(EmptyDir与Pod生命周期一致,不适合做数据持久化存储)。
EmptyDir用途如下:
- 临时存储空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留
- 多容器共享目录,同一个Pod中的不同容器之间共享数据
EmptyDir的使用
通过EmptyDir实现容器之间文件共享
在一个Pod中准备两个容器nginx和busybox,然后声明一个Volume分别挂载到两个容器的目录中,然后nginx容器负责向Volume中写日志,busybox中通过命令将日志内容读到控制台。
# 示例一:挂载存在的目录
# 将nginx容器的/var/log/nginx目录与busybox容器的/logs目录挂载到同一volume实现共享。通过访问nginx页面,nginx容器会将访问记录写入到/var/log/nginx/access.log文件中,那么可以通过busybox容器的/logs/access.log文件读出访问记录
[root@k8s-master ~]# vim volume-emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-emptydir
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
volumeMounts: # 将下面声明的logs-volume挂载到nginx容器中的/var/log/nginx目录上(只要有访问请求,那么便会有内容写入到该目录下的access.log文件中)
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","while true; do if test -f /logs/access.log; then tail -f /logs/access.log; else echo no such file named access.log; sleep 3;fi; done"] # 初始命令,动态读取 access.log 文件中内容
volumeMounts: # 将下面声明的logs-volume挂载到busybox容器中的/logs目录上(所以相当于nginx容器中的/var/log/nginx目录与busybox的/logs目录属于共享目录,下面的文件将会进行同步,当有请求访问nginx时,便会向nginx容器中的/var/log/nginx目录下的accsee.log日志文件追加访问记录,同时在busybox容器中也会看到该文件的内容,因为这两个容器的这两个目录都挂载在同一volume上,所以这两个目录下的文件及内容会实时保持一致)
- name: logs-volume
mountPath: /logs
volumes: #声明volume,name为logs-volume, 类型为emptyDir
- name: logs-volume
emptyDir: {
}
# 创建
[root@k8s-master ~]# kubectl create -f volume-emptydir.yaml
pod/volume-emptydir created
# 查看
[root@k8s-master ~]# kubectl get pod -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-emptydir 2/2 Running 0 7s 10.244.2.195 k8s-node02 <none> <none>
# 因为nginx容器的/var/log/nginx/与busybox容器中的/logs目录挂载在同一volume,所以这两个目录下的文件会是一致的并实时同步
[root@k8s-master ~]# kubectl exec -it volume-emptydir -c nginx -n test -- ls /var/log/nginx/
access.log error.log
[root@k8s-master ~]# kubectl exec -it volume-emptydir -c busybox -n test -- ls /logs
access.log error.log
# 此时对nginx进行访问,相当与向nginx容器中的/var/log/nginx/access.log文件中写入访问记录。
[root@k8s-node01 ~]# while true ;do curl 10.244.2.195 ;sleep 2 ;done
# 因为向每访问一次便会在/var/log/nginx/access.log文件写入记录数据,而且会同时同步更新busybox容器/logs目录下的access.log文件
# 资源清单文件在配置时,对于busybox容器会实时输出/logs/access.log文件中的新访问记录到标准输出
# 所以,流程为:在访问nginx时,会将访问记录记录到nginx容器的/var/log/nginx/access.log文件中,同时也会将访问记录数据实时更新到busybox容器的/logs/access.log文件中,于此同时busybox容器又会将/logs/access.log中的访问记录数据信息输出到控制台
# 那么,在访问nginx页面时,只要在busybox容器的控制台能够看到访问记录的标准输出就说明volume挂载成功
# 查看busybox容器的标准输出
[root@k8s-master ~]# kubectl logs volume-emptydir -c busybox -n test
10.244.1.0 - - [04/Jun/2021:02:30:10 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
10.244.1.0 - - [04/Jun/2021:02:30:12 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
10.244.1.0 - - [04/Jun/2021:02:30:14 +0000] "GET / HTTP/1.1"