1. 数据的持久化与非持久化

  • 数据是分为持久化与非持久化,简单理解就是字面意思,能不能持久保存。
  • 非持久化存储自动创建,从属于容器,故生命周期与容器同步,将会随着容器的删除而删除。
  • 若希望容器数据保留下来即持久化,需要将数据存储在卷(volume)上。卷与容器是解耦的,可以独立创建并管理卷,容器可以使用卷,但容器删除,卷仍存在。

    2. 容器与数据存储

    2.1 容器与非持久化数据

  1. Linux中,非持久化数据存在 /var/lib/docker/<storage-driver>/ 之下。

    2.2 容器与持久化数据

  • 容器中数据的持久化推荐使用卷的方式。
  1. 首先创建卷,再创建容器,再讲卷挂载到容器文件系统的某个目录,任何写到该目录下的容器都会写到卷中。

    2.2.1 创建和管理卷

  2. 创建卷: ```bash

    创建 myvol 卷

    $ docker volume create myvol

查看卷详情

$ docker volume inspect myvol

  1. 2. 默认情况下,Docker创建新卷时采用内置的local驱动,创建出来的卷称为 `本地卷` 。本地卷只能被所在节点的容器使用。使用 `-d` 可以指定不同的驱动。
  2. 2. 第三方驱动可以通过插件方式接入,为Docker卷集成外部存储系统。存在许多种卷插件,涵盖了块存储、文件存储、对象存储等:
  3. - 块存储:相对性能更高,适用于对小块数据的随机访问负载。目前支持 Docker 卷插件的块存储例子包括 HPE 3PARAmazon EBS 以及 OpenStack 块存储服务(Cinder)。
  4. - 文件存储:包括 NFS SMB 协议的系统,同样在高性能场景下表现优异。支持 Docker 卷插件的文件存储系统包括 NetApp FASAzure 文件存储以及 Amazon EFS
  5. - 对象存储:适用于较大且长期存储的、很少变更的二进制数据存储。通常对象存储是根据内容寻址,并且性能较低。支持 Docker 卷驱动的例子包括 Amazon S3Ceph 以及 Minio
  6. ![](https://cdn.nlark.com/yuque/0/2020/gif/1204927/1589642840243-c32fa7a7-ef0c-4e19-a18e-1863901cd580.gif#align=left&display=inline&height=286&margin=%5Bobject%20Object%5D&originHeight=286&originWidth=500&size=0&status=done&style=shadow&width=500)
  7. 4. 删除卷
  8. ```bash
  9. # 删除未装入容器或服务的所有卷
  10. 1. docker volume prune
  11. # 删除指定卷(不能删除正在使用中的卷)
  12. 2. docker volume rm

2.2.2 卷在容器和服务中的使用

  1. # 创建一个新的独立容器,并挂载一个名为bizvol的卷
  2. $ docker container run -dit --name voltainer \
  3. --mount source=bizvol,target=/vol \
  4. alpine
  5. # 创建一个hellcat的Docker服务,部署两个副本,将bizvol卷挂载到/vol目录
  6. $ docker service create \
  7. --name hellcat \
  8. --mount source=bizvol,target=/vol \
  9. --replics 2 \
  10. alpine sleep 1d

2.3 在集群节点间共享存储

  • Docker 能够集成外部存储系统,使得集群间节点共享外部存储数据变得简单。无论容器或者服务副本运行在哪个节点上,都可以共享该存储。(例如:独立存储 LUN 或者 NFS 共享)如下:

卷和持久化 - 图1
构建这样的环境需要外部存储系统的相关知识,并了解应用如何从共享存储读取或者写入数据。这种配置主要关注数据损坏(Data Corruption)

  • 数据损坏:设想下面的场景:Node 1 上的容器 A 在共享卷中更新了部分数据。但是为了快速返回,数据实际写入了本地缓存而不是卷中。此时,容器 A 认为数据已经更新。但是,在 Node 1 的容器 A 将缓存数据刷新并提交到卷前,Node 2 的容器 B 更新了相同部分的数据,但是值不同,并且更新方式为直接写入卷中。此时,两个容器均认为自己已经将数据写入卷中,但实际上只有容器 B 写入了。容器 A 会在稍后将自己的缓存数据写入缓存,覆盖了 Node 2 的容器 B 所做的一些变更。但是 Node 2 上的容器 B 对此一无所知。数据损坏就是这样发生的。
  • 为了避免这种情况,需要在应用程序中进行控制。