第六章 数据持久化
在容器层的 UnionFS(联合文件系统)中对文件/目录的任何修改,无论是手工修改还是容器在运行过程中的修改,在该容器丢失或被删除后这些修改将全部丢失。即这些修改是无法保存下来的。若要保存下来这些修改,通常有两种方式:
- 定制镜像持久化:将这个修改过的容器生成一个新的镜像,让这些修改变为只读的镜像
- 数据卷持久化:将这些修改通过数据卷同步到宿主机
1. 定制镜像持久化
1.1 需求
我们这里要实现的功能是,为 tomcat:10.0 镜像修改其 webapps 目录。原本该目录内容是空的,用户访问 tomcat 页面会报 404,而真正的内容是在 webapps.dist 中。现要将原webapps 目录删除,然后重命名 webapps.dist 目录为 webapps,以使用户可以看到 tomcat页面。
1.2 实现
运行tomcat容器
首先以分离模式启动
tomcat容器。
此时通过浏览器是无法访问到
tomcat页面的。
进入容器后删除目录
通过
docker exec命令可以进入到容器命令行。可以看到webapps目录是空的,而真正需要的内容在webapps.dist目录中。
删除
webapps目录,然后将webapps.dist目录重命名为webapps。
此时刷新浏览器就可以看到
tomcat页面了。

容器生成镜像
执行
docker commit命令,以当前运行的容器为范本生成镜像。
-m指定本次提交的日志-a指定该镜像的作者tomcat10:own为新镜像的<repository>:<tag>
此时可以看到已经生成了新的镜像。

测试新镜像
启动
tomcat10:own镜像容器,指定端口号为9000。

2. 数据卷持久化
Docker 提供了三种实时同步(宿主机与容器 FS 间数据的同步)方式:
- 数据卷
Bind mounts(绑定挂载)tmpfs(临时文件系统)
2.1 数据卷概述
2.1.1 数据卷简介
数据卷是宿主机中的一个特殊的文件/目录,这个文件/目录与容器中的另一个文件/目录进行了直接关联,在任何一端对文件/目录的写操作,在另一端都会同时发生相应变化。在宿主中的这个文件/目录就称为数据卷,而容器中的这个关联文件/目录则称为该数据卷在该容器中的挂载点。
数据卷的设计目的就是为了实现数据持久化,其完全独立于容器的生命周期,属于宿主机文件系统,但不属于 UnionFS。因此,容器被删除时,不会删除其挂载的数据卷。
2.1.2 数据卷的特性
数据卷具有如下明显特性:
- 数据卷在容器启动时初始化,如果容器启动后容器本身已经包含了数据,那么,这些数据会在容器启动后直接出现在数据卷中,反之亦然
- 可以对数据卷或挂载点中的内容直接修改,修改后对方立即可看到
- 数据卷会一直存在,即使挂载数据卷的容器已经被删除
- 数据卷可以在容器之间共享和重用
2.2 创建读写数据卷
读写数据卷指的是容器对挂载点具有读写权限。
2.2.1 命令
数据卷是在使用 docker run 启动容器时指定的,其语法格式为:docker run –it –v /宿主机目录绝对路径:/容器内目录绝对路径 镜像
注:无论是宿主机中的数据卷还是容器中的挂载点,如果指定的目录不存在,那么
docker引擎都会自动创建。即使是多级目录不存在。
2.2.2 需求
在宿主机中的/root/host_mount 目录与 ubuntu 容器的/opt/uc_mount 目录间建立关联,即宿主机中的/root/host_mount 目录作为数据卷,而 ubuntu 容器的/opt/uc_mount 目录作为挂载点。
2.2.3 创建数据卷
以交互方式启动一个 ubuntu 容器,同时指定在启动容器时创建数据卷。容器启动完毕后在容器中查看/opt 目录,可以看到新建了一个 uc_mount 子目录。这个就是容器中的挂载点目录。


再打开一个会话窗口,查看/root 目录,可以看到新建了一个 host_mount 目录。这个就是数据卷目录。

2.2.4 数据卷/挂载点互操作
宿主机数据卷目录与容器挂载点目录中进行文件修改互操作,修改完毕后,对方都可立即看到修改。
在宿主机数据卷目录中创建一个新的文件。

在容器中可以查看到该文件出现了。

在容器中对文件内容进行修改。

在宿主机中可以查看到该修改过的文件内容。

2.2.5 停止容器后的操作
即使容器停止了,在宿主机中只要修改了数据卷目录内容,在重新启动容器后,该修改过的数据仍会出现在容器中。因为容器是一个 UnionFS,是一个存在于宿主机中的文件系统,无论容器是否运行,该 FS 都是存在的。
通过 exit 退出并停止容器。

在宿主机数据卷目录修改文件。

重新启动并进入容器,查看容器中挂载点目录中的文件内容,发现已发生改变。

2.2.6 查看数据卷详情
通过 docker inspect [容器名称] 命令可以查看到当前容器中挂载点与数据卷的绑定关系。

这里给出了数据卷 Source 与挂载点 Destination 的绑定关系,且容器对挂载点的默认操作权限是 RW 读写的
2.3 创建只读数据卷
只读数据卷,指的是容器对挂载点的操作权限是只读的。宿主机对数据卷的操作权限始终是读写的。有些情况下,为了防止容器在运行过程中对文件产生修改,就需要创建只读数据卷。
2.3.1 命令
该命令仅比之前的命令仅多了:ro,具体语法如下:
docker run –it –v /宿主机目录绝对路径:/容器内目录绝对路径:ro 镜像
2.3.2 创建数据卷
以交互方式启动一个 ubuntu 容器,同时指定在启动容器时创建只读数据卷。

2.3.3 数据卷/挂载点互操作
在容器中修改挂载点中的文件,系统会给出只读文件系统的提示。说明容器对数据卷是只读的。

宿主机中对数据卷文件的修改是成功的。

在容器中同样也是可以看到宿主机中的修改的。

2.3.4 查看数据卷详情
通过 docker inspect [容器] 命令可以查看到该数据卷的只读属性。

2.4 数据卷共享
当一个容器与另一个容器使用相同的数据卷时,就称这两个容器实现了“数据卷共享”。
2.4.1 数据卷容器
数据卷容器是实现数据卷共享的一种非常有效的方案。
当一个容器 C 启动运行时创建并挂载了数据卷,若其它容器也需要共享该容器 C 挂载的数据卷,这些容器只需在 docker run 启动时通过--volumes-from[容器 C] 选项即可实现数据卷共享。此时容器 C 就称为数据卷容器。
2.4.2 需求
myubuntu2 容器要共享前面的 myubuntu 容器的数据卷,即宿主机中/root/host_mount为数据卷目录,而这两个容器的挂载点目录都是/opt/uc_mount。
2.4.3 进入 myubuntu 容器
通过 docker exec 命令进入 myubuntu 容器后,进入挂载点目录/opt/uc_mount。

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

2.4.5 数据卷共享操作
经过上述操作,myubuntu 与 myubuntu2 这两个容器实现了数据卷共享。此时,无论是在宿主机,还是 myubuntu 或 myubuntu2 任意容器中挂载点目录中的任意写操作,在另外两方均可同步看到该写操作的结果。
下面举例:首先在宿主机数据卷目录中创建一个文件 data.log。

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

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

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


3. Dockerfile 持久化
Dockerfile 持久化,其实就是通过使用 Dockerfile 的 VOLUME 指令指定数据卷方式实现的持久化。
3.1 VOLUME指令
VOLUME 指令可以在容器中创建可以挂载数据卷的挂载点。其参数可以是字符串数组,也可以是使用空格隔开的多个纯字符串。例如,VOLUME ["/var/www", "/etc/apache"] 或VOLUME /var/www /etc/apache。
3.2 持久化实现
3.2.1 创建 Dockerfile
在/root 目录中 mkdir 一个目录,例如 vols,然后在其中新建 Dockerfile,内容如下。这里指定/opt/xxx 与/opt/ooo 为容器端的挂载点。
FROM centos:7
VOLUME /opt/xxx /opt/ooo
CMD /bin/bash
3.2.2 构建镜像 build
使用 Dockerfile 构建镜像 volscon:latest。

3.2.3 运行新建镜像
以交互方式运行新建镜像。

3.2.4 查看宿主机端目录
Ctrl + P + Q 退出容器后,使用docker inspect查看当前容器中的挂载点目录到底与宿主机中的哪个数据卷对应。

3.2.5 验证
在容器端首先进入/opt/xxx 目录,并在其中新建一个文件 hello.log。

在宿主机端,从 docker inspcet 命令中找到/opt/xxx 目录对应的数据卷 Source 目录,首先进入到该目录,然后就可以查看到对应的 hello.log 文件了。说明数据卷设置成功,可以实现从容器到数据卷的持久化了。

在宿主机端修改文件内容,在容器端同样也是可以看到的。