5.1 卷

由于容器最初设计为临时性和无状态的,因此几乎不需要解决存储持久性问题。然而,随着越来越多需要从持久性存储读写的应用程序被容器化,对持久性存储卷的访问需求也随之出现,于是 Docker 出现了卷。Docker 中的卷,实际上就是将主机目录映射到容器中。

但是,在多节点集群中,Pod/容器 在不同的节点服务器中运行,而 Docker 中的卷只能映射一个服务器中的目录/文件,不同服务器间不能共享文件,那么不同的 Docker 是无法访问同一份文件的。

为了让散落在不同服务器中的同一类容器访问同一份文件,Kubernetes 设计了有持久化的卷。Kubernetes 的卷独特之处在于它们是集群外部的,可以将持久卷挂载到集群,而不需要将它们与特定节点、容器或 Pod 关联。

采用容器存储接口(Container Storage Interface ,CSI) 使用于容器编排的行业标准接口的目标能够允许访问任意存储系统,所以 Kubernetes 不仅支持 Docker ,还可以支持多种容器引擎。在 Kubernetes 中,支持的卷类型非常多,而且很抽象,不同的容器技术之间的实现有很大差异,但是只要支持 CSI 接口,则 Kubernetes 可以很容易为这些容器引擎建立统一的卷文件系统。

接下来笔者将介绍 Kubernetes 中一些不同类型的卷。

Docker 卷

在 Docker 中,我们可以使用以下命令管理卷。

# 创建自定义容器卷
docker volume create {卷名称}
# 查看所有容器卷
docker volume ls
# 查看指定容器卷的详细信息
docker volume inspect {卷名称}

我们可以在运行容器时,使用 -v 映射主机目录,或者映射容器卷到容器中。

docker -itd ... -v /var/tmp:/opt/app ...
docker -itd ... -v {卷名}:/opt/app    ...

例如:

docker run -v /opt/test:/opt/test -it ubuntu bash
docker run  --read-only -v /opt/test:/opt/test -it ubuntu bash

在 Docker 中,卷是一个目录,Docker 可以通过参数指定不同类型的挂载方式:

参数/命令 说明
--volume , -v 绑定挂载卷
--volume-driver 容器的可选卷驱动程序
--volumes-from 从指定的容器挂载卷,容器间可传递共享

Docker 中卷没有生命周期管理。对于纯 Docker 容器来说,只要宿主机的目录存在,那么容器创建和销毁时,不会删除宿主机的文件,但 Docker 的卷只有少量且松散的管理。如果不挂载卷,在 Docker 中,创建新版本的 容器后,旧容器的数据会丢失。

hostPath 卷

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

一般考虑 hostPath 在以下情况下使用:

  • 单个 Pod ,部署在一个节点上;
  • 多个 Pod,但是都部署在一个节点上,一般会为 Pod 加上节点选择器,确保 Pod 分配到需要的节点上。

    ... ...

一个 hostPath 卷映射主机目录的配置示例如下:

  volumes:
  - name: test-volume
    hostPath:
      # 宿主上目录位置
      path: /data
      # 此字段为可选
      type: Directory

这段 YAML 配置了一个名称为 test-volume 的卷,映射类型是目录,位置是 /data

hostPath 的 type,有以下类型:

取值 行为
空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。
DirectoryOrCreate 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。
Directory 在给定路径上必须存在的目录。
FileOrCreate 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。
File 在给定路径上必须存在的文件。
Socket 在给定路径上必须存在的 UNIX 套接字。
CharDevice 在给定路径上必须存在的字符设备。
BlockDevice 在给定路径上必须存在的块设备。

hostPath 的配置比较简单,这里就不做过多介绍。Pod 中直接定义 hostPath 的方式,其 YAML 模板如下:

apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
spec:
  containers:
  - image: nginx:latest
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # 宿主上目录位置
      path: /data
      # 此字段为可选
      type: DirectoryOrCreate

由于 hostPath 是在节点上的,因此使用单个 Pod 部署比较好。对于 Deployment 等多 Pod 的对象,Pod 分配在不同节点上,使用 hostPath ,可能会导致不能正常工作。

emptyDir 卷

emptyDir 卷是最简单的一种卷,首先,它是一个 空的卷,意味着什么都没有,并且它是临时的,其生命周期与 Pod 绑定。但是可以在同Pod的不同容器中访问同一个 emptyDir。

我们为 Pod 配置一个 emptyDir 卷并开始创建 Pod,当 Node 创建 Pod 后,会自动创建 emptyDir,并且在 Pod 运行期间这个 emptyDir 卷一直存在,但是如果 Pod 被删除,则 emptyDir 卷会丢失。

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

当 emptyDir 卷创建完成后,Pod 中的容器便可以输出文件到卷中。

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

Pod多容器

Deployment 模板示例如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-web
  name: my-web
spec:
  selector:
    matchLabels:
      app: my-web
  strategy:
  template:
    metadata:
      labels:
        app: my-web
    spec:
      containers:
      - image: web:1.e
        name: web
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /opt/web/root
          name: wwwroot-volume
      - image: frontend:1.2
        name: frontend
        volumeMounts:
        - mountPath: /opt/frontend/root
          name: wwwroot-volume
      volumes:
      - name: wwwroot-volume
        emptyDir: {}

使用 Pod 配置 单容器,其简单的示例如下:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: nginx:latest
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

emptyDir 不需要指定宿主机上对应的目录,Kubernetes 会为其指定临时目录,emptyDir 卷存储介质跟主机的存储介质有关,一般是磁盘、固态/机械硬盘、网络存储等,也可以是内存。在 Linux 中有一种 tmpfs(基于 RAM 的文件系统)文件系统,其速度比磁盘快,适合用作缓存,将 emptyDir.medium 字段设置为 "Memory" 即可,所写入的所有文件都会计入容器的内存消耗,受容器内存限制约束,如果机器重启,文件会丢失。

emptyDir 的一些用途:

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

Git 卷

Git 卷也是一种 emptyDir 卷,顾名思义,Git 卷可以帮助我们拉取 Git 中的代码到 Pod 中。在最初时,映射到 Pod 中的目录是空的,当 Pod 启动起来时,便会从 Git 中拉取源代码到 emptyDir 娟中,填充存储空间。

Git 卷适合用来做编译,启动 Pod 克隆仓库后,容器中的程序读取源代码,然后编译项目,编译后的文件可以部署运行,也可以打包发布。

很多人应该都了解过 Jenkins ,通过流水线构建自动化发布,其实 Kubernetes 中的 Git 卷也可以做到类似效果,只是定制不太灵活。

不过 Git 卷的缺点是只在 Pod 启动时拉取一次代码,之后仓库中的代码提交多少次,都不会同步到你的卷中。不过每个创建的 Pod,都会拉取最新的源代码。

Git 卷的 volumns 部分,其定义模板如下:

volumns:
- name: erp
  gitRepo: 
    repository: https://github.com/whuanle/CZGL.AOP
    revision: main
    directory: .

directory 配置拉取的源代码放到卷的什么目录中,使用 . 表示放到卷的根目录中。

以上四种卷是比较常用的,还有一些卷在后面的章节中会接着讲解。

Copyright © 痴者工良 2021 all right reserved,powered by Gitbook文档最后更新时间: 2022-07-30 09:49:42

results matching ""

    No results matching ""