数据持久化

在容器层的 UnionFS(联合文件系统)中对文件/目录的任何修改,无论是手工修改还是

容器在运行过程中的修改,在该容器丢失或被删除后这些修改将全部丢失。即这些修改是无

法保存下来的。若要保存下来这些修改,通常有两种方式:

  • 定制镜像持久化:将这个修改过的容器生成一个新的镜像,让这些修改变为只读的镜像

  • 数据卷持久化:将这些修改通过数据卷同步到宿主机

数据持久化主要解决的问题如下:

  1. 数据丢失:在默认情况下,Docker容器内部产生的数据存储在其自身的存储层上。当容器停止运行或被删除时,与该容器关联的存储层也会被清理,这意味着所有在容器运行期间生成或修改的数据都将永久丢失。
  2. 迁移和备份困难:由于容器存储层与容器生命周期紧密相连,如果需要将数据从一个容器移动到另一个容器,或者需要对数据进行备份和恢复操作,会非常复杂且不可靠。
  3. 多容器共享数据:在实际应用中,可能需要多个容器之间共享某些数据,例如数据库服务和Web服务器之间。但是,容器间的直接文件系统交互并不方便,也不利于容器的独立性和可移植性。
  4. 性能考量:容器存储层通常是通过联合文件系统(如AUFS、OverlayFS等)实现的,频繁写入这类文件系统的性能可能不如直接写入宿主机的磁盘。

假如我拉取一个tomcat:10.0

docker pull tomcat:10.0

然后运行

docker run --name mytom -dp 8081:8080 tomcat:10.0

删除webapps,然后把webapps.dist改名为webapps

保存镜像

docker commit -m"modify webapps" -a="Hayaizo" mytom tomcat10:own

docker run --name mytom11 -dp 8081:8080 tomcat10:own

运行镜像:

数据卷

Docker 提供了三种实时同步(宿主机与容器 FS 间数据的同步)方式:

  • 数据卷

  • Bind mounts(绑定挂载)

  • tmpfs(临时文件系统)

数据卷简介

数据卷是宿主机中的一个特殊的文件/目录,这个文件/目录与容器中的另一个文件/目录进行了直接关联,在任何一端对文件/目录的写操作,在另一端都会同时发生相应变化。

在宿主中的这个文件/目录就称为数据卷,而容器中的这个关联文件/目录则称为该数据卷在该容器中的挂载点。

数据卷的设计目的就是为了实现数据持久化,其完全独立于容器的生命周期,属于宿主机文件系统,但不属于 UnionFS。因此,容器被删除时,不会删除其挂载的数据卷。

数据卷的特性

数据卷具有如下明显特性:

  • 数据卷在容器启动时初始化,如果容器启动后容器本身已经包含了数据,那么,这些数

  • 据会在容器启动后直接出现在数据卷中,反之亦然

  • 可以对数据卷或挂载点中的内容直接修改,修改后对方立即可看到

  • 数据卷会一直存在,即使挂载数据卷的容器已经被删除

  • 数据卷可以在容器之间共享和重用

其实底层就是通过Linux硬链接实现的(ln)。

数据卷的创建

读写数据卷指的是容器对挂载点具有读写权限。

命令

数据卷是在使用 docker run 启动容器时指定的,其语法格式为:

docker run –it –v /宿主机目录绝对路径:/容器内目录绝对路径 镜像

注:无论是宿主机中的数据卷还是容器中的挂载点,如果指定的目录不存在,那么 docker引擎都会自动创建。即使是多级目录不存在。

docker run --name mycent -v /root/xxx/aaa:/opt/ooo/bbb -it centos:7

可以看到会自动创建目录,即使是一个多级目录。

在宿主机中同样会创建目录。

我在宿主机创建一个hello.cc

只读数据卷的创建

只读数据卷,指的是容器对挂载点的操作权限是只读的。宿主机对数据卷的操作权限始终是读写的。

有些情况下,为了防止容器在运行过程中对文件产生修改,就需要创建只读数据卷。

命令

该命令仅比之前的命令仅多了:ro,具体语法如下:

docker run –it –v /宿主机目录绝对路径:/容器内目录绝对路径:ro 镜像

创建数据卷

以交互方式启动一个 ubuntu 容器,同时指定在启动容器时创建只读数据卷。

docker run --name myu -it -v /root/host_mount:/opt/ddd:ro ubuntu:latest /bin/bash

数据卷共享

当一个容器与另一个容器使用相同的数据卷时,就称这两个容器实现了“数据卷共享”。

当一个容器 C 启动运行时创建并挂载了数据卷,若其它容器也需要共享该容器 C 挂载的数据卷,这些容器只需在 docker run 启动时通过–volumes-from[容器 C] 选项即可实现数据卷共享。此时容器 C 就称为数据卷容器。

docker run --name mycent2 --volumes-from mycent centos:7 

docker run --name myunbuntu --volumes-from mycent -it ubuntu /bin/bash

需求:myubuntu2 容器要共享前面的 myubuntu 容器的数据卷,即宿主机中/root/host_mount

为数据卷目录,而这两个容器的挂载点目录都是/opt/uc_mount。

通过 docker exec 命令进入 myubuntu 容器后,进入挂载点目录/opt/uc_mount。

这里在创建并运行 myubuntu2 容器时,使用–volumes-from 指定该容器要共享 myubuntu的数据卷,即指定 myubuntu 容器为数据卷容器。此时可以发现,myubuntu2 容器中也同样出现了挂载点目录/opt/uc_mount。

经过上述操作,myubuntu 与 myubuntu2 这两个容器实现了数据卷共享。此时,无论是在宿主机,还是 myubuntu 或 myubuntu2 任意容器中挂载点目录中的任意写操作,在另外两方均可同步看到该写操作的结果。

下面举例:

首先在宿主机数据卷目录中创建一个文件 data.log。

在 myubuntu 容器中可以查看到 data.log 文件。然后,myubuntu 容器也修改该文件。

在 myubuntu2 容器中可以查看到 data.log 文件。然后,myubuntu2 容器也修改该文件。

myubuntu2 容器对文件的修改,在 myubuntu 容器与宿主机中均可看到。

Dockerfile持久化

Dockerfile 持久化,其实就是通过使用 Dockerfile 的 VOLUME 指令指定数据卷方式实现的持久化。

VOLUME指令

VOLUME 指令可以在容器中创建可以挂载数据卷的挂载点。其参数可以是字符串数组,也可以是使用空格隔开的多个纯字符串。例如:

VOLUME [“/var/www”,“/etc/apache”] 或

VOLUME /var/www /etc/apache。

FROM centos:7VOLUME /opt/xxx /opt/oooCMD /bin/bash

挂载点有了,那么我的源在哪呢?

docker inspect

在这可以看到Source,这是docker daemon自动分配的。