数据持久化
在容器层的 UnionFS(联合文件系统)中对文件/目录的任何修改,无论是手工修改还是
容器在运行过程中的修改,在该容器丢失或被删除后这些修改将全部丢失。即这些修改是无
法保存下来的。若要保存下来这些修改,通常有两种方式:
定制镜像持久化:将这个修改过的容器生成一个新的镜像,让这些修改变为只读的镜像
数据卷持久化:将这些修改通过数据卷同步到宿主机
数据持久化主要解决的问题如下:
- 数据丢失:在默认情况下,Docker容器内部产生的数据存储在其自身的存储层上。当容器停止运行或被删除时,与该容器关联的存储层也会被清理,这意味着所有在容器运行期间生成或修改的数据都将永久丢失。
- 迁移和备份困难:由于容器存储层与容器生命周期紧密相连,如果需要将数据从一个容器移动到另一个容器,或者需要对数据进行备份和恢复操作,会非常复杂且不可靠。
- 多容器共享数据:在实际应用中,可能需要多个容器之间共享某些数据,例如数据库服务和Web服务器之间。但是,容器间的直接文件系统交互并不方便,也不利于容器的独立性和可移植性。
- 性能考量:容器存储层通常是通过联合文件系统(如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自动分配的。