K8s卷存储详解(一)
- K8s 存储
- K8s卷分类
- K8s目前支持的卷类型
- 临时卷类型
- EmptyDir
- CSI 临时卷
- 通用临时卷
K8s 存储
什么是卷?为什么要用卷?
我们知道K8s是基于容器,对各个Pod进行管理的。Pod是由容器构成的,我也知道,容器(如Docker)有个特点就是,容器删除后,在容器中产生的数据也会随之销毁。K8s会监控容器的运行状态,当有容器崩溃或停止时,K8s的Controller会删除这些容器,并重新创建新的容器。如果容器被销毁,此时容器状态未保存, 因此在容器生命周期内创建或修改的所有文件都将丢失。在崩溃期间,kubelet 会以干净的状态重新启动容器。
另外一个需求就是:当多个容器在一个 Pod 中运行并且需要共享文件时, 就需要跨所有容器设置和访问共享文件系统。
K8s卷分类
根据应用场景不同,和需求不同,将卷分为不同的种类
-
临时卷
-
持久卷
-
投射卷
卷的相关参数
-
卷类型
-
卷挂载位置
卷挂载位置
卷挂载在镜像中的指定路径下。 Pod 配置中的每个容器必须独立指定各个卷的挂载位置。
注意:卷不能挂载到其他卷之上(不过存在一种使用 subPath 的相关机制),也不能与其他卷有硬链接。
K8s目前支持的卷类型
已启用的卷类型
- awsElasticBlockStore (已弃用)
- azureDisk (已弃用)
- cinder (已弃用)
- gcePersistentDisk(已弃用)
- gcePersistentDisk(已弃用)
- gitRepo (已弃用)
- glusterfs(已移除)
- portworxVolume(已弃用)
- vsphereVolume(已弃用)
- flexVolume(已弃用)
可以使用的卷类型
- cephfs
- configMap
- downwardAPI
- emptyDir
- fc (光纤通道)
- hostPath
- iscsi
- local
- nfs
- persistentVolumeClaim
- subPath
- 树外(Out-of-Tree)卷插件
常用的数据卷(Volume)有:
- 本地:如,HostPath、EmptyDir;
- 网络:如,NFS、Ceph、GlusterFS;
- 公有云:如,AWS EBS;
- K8s资源:如,Configmap、Secret。
临时卷
什么是临时卷?
临时卷的生命周期与 Pod 的生命周期相同,与 Pod 一起创建和删除,当 Pod 不再存在时,Kubernetes 也会销毁临时卷。 所以停止和重新启动 Pod 时,不会受持久卷在何处可用的限制。
应用场景1:有些应用程序需要额外的存储,但并不关心数据在重启后是否仍然可用。
示例:缓存服务经常受限于内存大小,而且可以将不常用的数据转移到比内存慢的存储中,对总体性能的影响并不大。
应用场景2:些应用程序需要以文件形式注入的只读数据
示例:比如配置数据或密钥。
临时卷类型
根据不同的用途,支持几种不同类型的临时卷
- EmptyDir: Pod 启动时为空,存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
- 见投射卷:ConfigMap、 DownwardAPI、 Secret: 将不同类型的 Kubernetes 数据注入到 Pod 中
- CSI 临时卷: 类似于前面的卷类型,但由专门支持此特性 的指定 CSI 驱动程序提供
- 通用临时卷: 它可以由所有支持持久卷的存储驱动程序提供
emptyDir
、configMap
、downwardAPI
、secret
是作为 本地临时存储 提供的。它们由各个节点上的 kubelet 管理。
"本地"意味着存储介质不能是网络上的。
EmptyDir
EmptyDir是在当 Pod 分派到某个Node节点上时创建的,它的初始内容为空,k8s自动分配一个目录,而无需指定宿主机上对应的目录文件。当Pod销毁时, EmptyDir中的数据也会被永久删除。
无论Pod 中的容器挂载 emptyDir
卷的路径是否相同,这些容器都可以读写 emptyDir
卷中相同的文件。
说明:容器崩溃并不会导致 Pod 被从节点上移除,因此容器崩溃期间 emptyDir
卷中的数据是安全的
emptyDir
的一些用途:
- 缓存空间,例如基于磁盘的归并排序。
- 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
- 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
设置卷挂载位置:
使用emptyDir.medium
字段用来控制 emptyDir
卷的存储位置。
挂载位置可以是基于存储介质的,也可以是基于内存的:
emptyDir
卷存储在该节点所使用的介质上; 此处的介质可以是磁盘、SSD 或网络存储,这取决于你的环境
如果是挂载 tmpfs,将 emptyDir.medium
字段设置为 "Memory"
, 它与磁盘不同:tmpfs 在节点重启时会被清除, 并且你所写入的所有文件都会计入容器的内存消耗,受容器内存限制约束。
示例:
emptyDir 官方配置示例
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 500Mi
容器共享示例:
apiVersion: v1
kind: Pod
metadata:
name: volume-emptydir
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
volumeMounts: # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件中内容
volumeMounts: # 将logs-volume 挂在到busybox容器中,对应的目录为 /logs
- name: logs-volume
mountPath: /logs
volumes: # 声明volume, name为logs-volume,类型为emptyDir
- name: logs-volume
emptyDir: {}
创建Pod
[root@k8s-master01 ~]# kubectl create -f volume-emptydir.yaml
# 查看pod
[root@k8s-master01 ~]# kubectl get pods volume-emptydir -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ......
volume-emptydir 2/2 Running 0 97s x.x.x.x node1 ......
# 通过podIp访问nginx
[root@k8s-master01 ~]# curl <IP>
# 通过kubectl logs命令查看指定容器的标准输出
[root@k8s-master01 ~]# kubectl logs -f volume-emptydir -n dev -c busybox
卷限制:
基于介质:通过为默认介质指定大小限制,来限制 emptyDir
卷的存储容量。
基于内存:当启用 SizeMemoryBackedVolumes
特性门控时, 你可以为基于内存提供的卷指定大小。 如果未指定大小,则基于内存的卷的大小为 Linux 主机上内存的 50%。
为本地临时性存储设置请求和限制
以指定 ephemeral-storage
来管理本地临时性存储。 Pod 中的每个容器可以设置以下属性:
spec.containers[].resources.limits.ephemeral-storage
spec.containers[].resources.requests.ephemeral-storage
表示存储容量的 方式有2种
- 加后缀表达式(可加的后缀:E、P、T、G、M、k)
- 2 的幂级数表达式(Ei、Pi、Ti、Gi、Mi、Ki)
官方示例:
假如,Pod 包含两个容器。每个容器请求 2 GiB 大小的本地临时性存储。 每个容器都设置了 4 GiB 作为其本地临时性存储的限制。 因此,整个 Pod 的本地临时性存储请求是 4 GiB,且其本地临时性存储的限制为 8 GiB。 该限制值中有 500Mi 可供 emptyDir
卷使用。
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
ephemeral-storage: "2Gi"
limits:
ephemeral-storage: "4Gi"
volumeMounts:
- name: ephemeral
mountPath: "/tmp"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
ephemeral-storage: "2Gi" # 关键配置,注意单位
limits:
ephemeral-storage: "4Gi" # 关键配置,注意单位
volumeMounts:
- name: ephemeral
mountPath: "/tmp"
volumes: # 挂载的卷
- name: ephemeral
emptyDir:
sizeLimit: 500Mi
CSI 临时卷
使用 CSI 临时存储的 Pod 的示例清单:
kind: Pod
apiVersion: v1
metadata:
name: my-csi-app
spec:
containers:
- name: my-frontend
image: busybox:1.28
volumeMounts:
- mountPath: "/data"
name: my-csi-inline-vol
command: [ "sleep", "1000000" ]
volumes:
- name: my-csi-inline-vol
csi:
driver: inline.storage.kubernetes.io
volumeAttributes:
foo: bar
通用临时卷
特性状态: Kubernetes v1.23 [stable]
临时存放Pod数据目录,创建初始为空。
通用临时卷与EmptyDir不同的功能特性:
-
存储可以是本地的,也可以是网络连接的。
-
卷可以有固定的大小,Pod 不能超量使用。
-
卷可能有一些初始数据,这取决于驱动程序和参数。
-
支持典型的卷操作,前提是相关的驱动程序也支持该操作,包括 快照、 克隆、 调整大小和 存储容量跟踪)。
官方示例:
kind: Pod
apiVersion: v1
metadata:
name: my-app
spec:
containers:
- name: my-frontend
image: busybox:1.28
volumeMounts:
- mountPath: "/scratch"
name: scratch-volume
command: [ "sleep", "1000000" ]
volumes:
- name: scratch-volume
ephemeral:
volumeClaimTemplate:
metadata:
labels:
type: my-frontend-volume
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "scratch-storage-class"
resources:
requests:
storage: 1Gi
参阅:
k8s存储:卷、持久卷、存储类
k8s数据存储详解
存储
K8S系列之存储