数据卷(Volume)是 Pod 与外部存储设备进行数据传递的通道,也是 Pod 内部容器间、Pod 与Pod 间、Pod 与外部环境进行数据共享的方式。

Volume 定义了外置存储的细节,并内嵌到 Pod 中作为 Pod 的一部分。其实质是外置存储在Kubernetes 系统的一个资源映射,当负载需要使用外置存储的时候,可以从数据卷(Volume)中查到相关信息并进行存储挂载操作。

Volume 的生命周期和 Pod 一致,Pod 被删除时,Volume也会被删除,Volume 中的数据是否丢失取决于 Volume 的具体类型。

常用的Volume类型分类如下:

分类 描述
本地存储 适用于本地存储的数据卷,例如 HostPath、emptyDir等。本地存储卷的特点是数据保存在集群的特定节点上,并且不能随着应用漂移,节点停机时数据即不再可用。
网络存储 适用于网络存储的数据卷,例如Ceph、GlusterFS、NFS、iSCSI等。网络存储卷的特点是数据不在集群的某个节点上,而是在远端的存储服务上,使用存储卷时需要将存储服务挂载到本地使用。
Secret和ConfigMap Secret和ConfigMap是特殊的数据卷,其数据是集群的一些对象信息,该对象数据以卷的形式被挂载到节点上供应用使用。
PVC 一种数据卷定义方式,将数据卷抽象成一个独立于Pod的对象,这个对象定义(关联)的存储信息即存储卷对应的真正存储信息,供Kubernetes负载挂载使用。

Volume 使用原则

  • 一个 Pod 可以挂载多个 Volume
  • 一个 Pod 可以挂载多种类型的 Volume
  • 每个被 Pod 挂载的 Volume,可以被该 Pod 内不同的容器间共享。
  • K8S 环境推荐使用 PVC 和 PV 方式挂载 Volume

Volume 类型

emptyDir

emptyDir 类型的 Volume 在 Pod 分配到 Node 上时被创建,Kubernetes会在 Node 上自动分配一个目录,因此无需指定宿主机Node上对应的目录文件,该目录的初始内容为空,当 Pod 从 Node 上被删除时,emptyDir 中的数据会被永久删除。

特别的,容器崩溃会导致 Pod 被从节点上移除,因此容器崩溃期间 emptyDir 卷中的数据是安全的。

常见使用场景:

  • emptyDir 卷适合用于 Pod 中的容器共享文件。
  • 缓存空间,例如基于磁盘的归并排序算法。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

例如前后端容器,前端容器是辅助进程,不对外提供任何服务,前端文件通过 emptyDir 共享到 Web 的 wwwroot 目录中。由 Web 对外提供 8080 端口服务,用户访问 Web 时,可以访问到前端静态文件。这样前后端可以分开更新和部署,存放前端文件的辅助容器只负责提供静态文件,最终由 Web 后端程序对外提供静态页面和 API。

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: pod-demo
 5  namespace: default
 6  labels:
 7    app: myapp
 8    tier: frontend
 9spec:
10  containers:
11  - name: myapp
12    image: ikubernetes/myapp:v1
13    imagePullPolicy: IfNotPresent
14    ports:
15    - name: http
16      containerPort: 80
17    volumeMounts:    #在容器内定义挂载存储名称和挂载路径
18    - name: html
19      mountPath: /usr/share/nginx/html/
20  - name: busybox
21    image: busybox:latest
22    imagePullPolicy: IfNotPresent
23    volumeMounts:
24    - name: html
25      mountPath: /data/    #在容器内定义挂载存储名称和挂载路径
26    command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
27  volumes:  #定义存储卷
28  - name: html    #定义存储卷名称  
29    emptyDir: {}  #定义存储卷类型

hostPath

hostPath 卷将主机节点文件系统上的文件或目录挂载到 Pod 中,类似 Docker 的 -v 挂载。hostPath 卷依赖于节点上的目录或文件,不同节点的 Pod 无法共享相同的文件内容。

常见使用场景:

  • 挂载宿主机的时区文件到容器内,保持和宿主机时区一致。
1          volumeMounts:
2            - name: timezone             # 卷名称
3              mountPath: /etc/localtime  # 挂载到容器中的路径目录
4      volumes:
5        - name: timezone
6          hostPath:
7            path: /usr/share/zoneinfo/Asia/Shanghai

configmap

ConfigMap 可以用来存储非机密性的数据到键值对中,这些信息会被存储到 etcd,不会分节点,任何节点都可以使用到。使用时,将其用作环境变量、命令行参数或者存储卷中的配置文件送入到 Pod 中,主要目的是解耦应用程序和配置,这样不必维护那些 .json 等配置文件,也可以避免不小心将带有机密信息的配置文件上传到代码仓库中。

假设有配置文件 c.txt 如下:

1enemies=aliens
2lives=3
3enemies.cheat=true
4enemies.cheat.level=noGoodRotten
5secret.code.passphrase=UUDDLRLRBABAS
6secret.code.allowed=true
7secret.code.lives=30

创建 configMap:

1# 基于单个配置文件创建 ConfigMap
2kubectl create configmap my-config1 --from-file=c.txt
3
4# 基于多个配置文件创建 ConfigMap
5kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
6
7# 基于目录创建 ConfigMap:
8kubectl create configmap my-config2 --from-file=config/

在 pod 中挂载 configMap:

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: configmap-pod
 5spec:
 6  containers:
 7    - name: configmap-pod
 8      image: busybox
 9      command: ["ls"]
10      args: ["/etc/config"]
11      volumeMounts:
12        - name: config-vol
13          mountPath: /etc/config
14  volumes:
15    - name: config-vol
16      configMap:
17        name: my-config

secret

Secret 卷用来给 Pod 传递敏感信息,例如密码、密钥等。Secret卷实际上不是用于存储的,Secret 中存储的信息,会以环境变量、文件等的形式显示在 Pod 中。最常用的情况是使用 Secret 为 Ingress 增加 TLS 加密访问。

Secret 主要包括以下类型:

内置类型 用法
Opaque 用户定义的任意数据
kubernetes.io/service-account-token 服务账号令牌
kubernetes.io/dockercfg ~/.dockercfg 文件的序列化形式
kubernetes.io/dockerconfigjson ~/.docker/config.json 文件的序列化形式
kubernetes.io/basic-auth 用于基本身份认证的凭据
kubernetes.io/ssh-auth 用于 SSH 身份认证的凭据
kubernetes.io/tls 用于 TLS 客户端或者服务器端的数据
bootstrap.kubernetes.io/token 启动引导令牌数据

使用 kubectl 命令创建 Secret:

1kubectl create secret {类型} {secret名称}

通过证书创建 Secret:

1kubectl create secret tls tls-secret --cert=1_k1.whuanle.cn_bundle.crt --key=2_k1.whuanle.cn.key

使用 YAML 表示:

1apiVersion: v1
2data:
3  tls.crt: ...
4  tls.key: ...
5kind: Secret
6metadata:
7  name: tls-secret
8type: kubernetes.io/tls

Nginx 配置 Https 证书,使用的便是 crt、key 文件。

PV & PVC

详细部署方式:PV & PVC 声明样例

K8S 引入了 PV 和 PVC 两个资源对象,将存储实现的细节从其如何被使用中抽象出来,并解耦存储使用者和系统管理员的职责。

PV和PVC的概念如下:

  • PV(PersistentVolume) 在 K8S 中代表一个具体存储类型的卷,其对象中定义了具体存储类型和卷参数。
  • PVC(PersistentVolumeClaim)是在 K8S 中一种抽象的存储卷类型,代表了某个具体类型存储的数据卷表达。

PV 属于整个 K8S 集群,而 PVC 属于某个命名空间

PVC与PV是一一对应关系,不能一个PVC挂载多个PV,也不能一个PV挂载多个PVC。 PVC只有绑定了PV之后才能被Pod使用,而PVC绑定PV的过程即是消费PV的过程,这个过程是有一定规则的。为应用配置存储时,需要声明一个 PVC,而 K8S 会通过最佳匹配的方式选择一个满足PVC需求的PV,并与之绑定。

PV 有两种提供方式:

静态分配:

  1. 集群管理员预先创建一些 PV。它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。
  2. 用户创建PVC与PV绑定

动态分配: 通过存储类进行动态创建存储空间。当现有的 PV 都不匹配用户的 PVC 时,K8S 基于 StorageClasses 动态地为 PVC 配置卷。