镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
按照Docker最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
(1).卷(volumes):是宿主机器的文件系统的一部分,由Docker进行管理(在Linux,存储于/var/lib/docker/volumes/)。非Docker程序不应该去修改这些文件。Docker推荐使用卷进行持久化数据。卷可支持卷驱动(volume drivers),该驱动允许用户将数据存储到远程主机或云服务商(cloud provider)或其它。没有名字的卷叫匿名卷(anonymous volume),有名字的卷叫命名卷(named volume)。匿名卷没有明确的名字,当被初始化时,会被赋予一个随机名字。
卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:A.卷可以在容器之间共享和重用;B.对卷的修改会立马生效;C.对卷的更新,不会影响镜像;D.卷默认会一直存在,即使容器被删除。
卷的使用,类似于Linux下对目录或文件进行mount,镜像中的被指定为挂载点的目录中的文件会复制到卷中(仅卷为空时会复制)。卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的卷。
(2).挂载宿主目录(bind mounts, 绑定挂载):通过将宿主机器的路径挂载到容器里的这种方式,从而数据持久化,因此绑定挂载可将数据存储在宿主机器的文件系统的任何地方。非Docker程序可修改这些文件。绑定挂载是Docker早期就存在的,相比起卷,绑定挂载十分简单明了。在开发Docker应用时,应使用命名卷(named volume)代替绑定挂载,因为用户不能对绑定挂载进行Docker CLI(command line interface, 命令行界面)命令操作。
绑定挂载常用于:A.同步配置文件,如:将宿主主机的DNS配置文件(/etc/resolv.conf)同步至容器中;B.在开发程序时,将源代码或Artifact同步至容器中。这种用法与Vagrant类似。
卷相关操作命令如下:
docker volume create vol1 # 创建一个卷,如卷名为vol1
docker volume ls # 查看所有的卷
docker volume inspect vol1 # 查看指定卷的信息,如卷vol1
# 启动一个挂载卷的容器,如将卷名为"vol1"挂载到容器的/home/fengbingchun目录;新建的容器名为"yyyy"; -P,随机端口映射,容器内部端口随机映射到主机的端口
docker run -it -P --name yyyy --mount source=vol1,target=/home/fengbingchun fengbingchun/ubuntu:16.04 /bin/bash
docker inspect yyyy # 查看容器中卷的具体信息,卷的信息在"Mounts"字段内,"yyyy"为容器名
docker volume rm vol1 # 删除卷,如卷名为"vol1",需要卷"vol1"没有被任何容器使用时才能删除
docker volume prune # 删除所有没有被使用的卷
挂载主机目录相关操作命令如下:
# 挂载一个本地主机的目录到容器中去,新建的容器名为"test"; -P,随机端口映射,容器内部端口随机映射到主机的端口;
# "/home/GitHub"为本地主机目录,本地目录的路径必须是绝对路径;"/home/fengbingchun"为挂载到容器此目录;Docker挂载主机目录的默认权限是读写
docker run -it -P --name test --mount type=bind,source=/home/GitHub,target=/home/fengbingchun fengbingchun/ubuntu:16.04 /bin/bash # linux
docker run -it -P --name test --mount type=bind,source=e:\GitCode,target=/home/fengbingchun fengbingchun/ubuntu:16.04 /bin/bash # windows
docker inspect yyyy # 查看容器中挂载主机目录的具体信息,挂载主机目录的配置信息在"Mounts"字段内,"yyyy"为容器名