容器数据持久化的三种方式

由于容器的镜像分层机制,我们在容器里面创建文件或者修改文件,结果都会保存在容器的可读写层中,一旦容器被销毁,那么这个读写层也会随着容器销毁而消失。而且当一个容器需要和其他容器的读写层进行数据交互时,也会显得非常困难。于是在将容器数据持久化到宿主机方面,Docker 为我们提供了三种持久化的方式

volumes 持久化方式

volumes 由 Docker 负责创建、管理。用户可以显式的调用命令 docker volume create 创建 volume,也可以通过 container、service 的启动隐式创建。Docker 创建的 volumes 本质上还是宿主机文件系统中的一个目录,一个 volumes 可以供多个容器使用,即使没有容器使用此 volumes,它也不会自动删除,除非用户明确删除它。如果用户显式创建 volumes 则需要给它一个名称,如果是隐式创建 volumes 则 Docker 会为它分配一个在宿主机范围内唯一的名字。通过使用第三方提供的 volume driver,用户可以将数据持久到远程主机或者云存储中,也就是说存储空间可以不由宿主机提供

# 创建volumes
docker volume create nginx_volumes

# 查看volumes
docker volume ls

# 查看卷详细信息
docker volume inspect nginx_volumes 
[
    {
        "CreatedAt": "2020-06-19T18:47:49+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/nginx_volumes/_data",    # 这是volumes在宿主机上的真实路径
        "Name": "nginx_volumes",
        "Options": {},
        "Scope": "local"
    }
]

# 清理volumes
docker volume rm nginx_volumes

将 Nginx 容器的 html 目录映射到宿主机的 nginx_volumes 目录

# 创建数据持久化的容器,如果卷不存在则自动创建
docker container run -itd --name "nginx1" -p 80:80 -v nginx_volumes:/usr/share/nginx/html nginx:1.17    # -v方式
docker container run -itd --name "nginx1" -p 80:80 --mount src=nginx_volumes,dst=/usr/share/nginx/html nginx:1.17 # --mount方式

# 查看nginx_volumes在宿主机的真实目录
ll /var/lib/docker/volumes/nginx_volumes/_data
total 8
-rw-r--r-- 1 root root 494 Apr 14 22:19 50x.html    # 这时候nginx容器内部的文件已经被映射到宿主机上了
-rw-r--r-- 1 root root 612 Apr 14 22:19 index.html

# 修改宿主机上的index.html文件
echo "nginx_volumes test" > /var/lib/docker/volumes/nginx_volumes/_data/index.html

# 访问宿主机的80端口(前面启动容器时将容器的80端口绑定到宿主机的80端了)
curl 10.10.110.150
nginx_volumes test    # nginx容器内的文件确实被修改成功

bind mounts 持久化方式

bind mounts 本质上是容器共享宿主机文件系统,比如 Docker 将宿主机的 /etc/resov.conf 文件 bind mount 到容器里,两者会使用相同的 dns 服务器

# 创建容器,将宿主机的/nginx/app绑定到容器的/usr/share/nginx/html目录 
docker container run -itd --name "nginx1" --mount type=bind,src=/nginx/app,dst=/usr/share/nginx/html nginx:1.17
docker container run -itd --name "nginx1" -v /nginx/app:/usr/share/nginx/html nginx:1.17
# 查看宿主机和容器的目录
ls /nginx/app
docker exec -it nginx1 ls /usr/share/nginx/html        
# 两个目录都为空,这是因为bind mounts是将宿主机的目录绑定到容器的目录,容器目录已有的内容会被隐藏(bind mounts以宿主机目录为主)

注意:如果源文件或源目录不存在,则不会自动创建。如果容器目录为非空目录,则容器目录现有内容会被宿主机目录内容所隐藏

tmpfs 持久化方式

出于安全原因,或者容器性能优化的原因有时候不需要容器的数据长久保存时可以使用这种方式。将容器数据挂载存储在宿主机的内存中,避免写入容器可写层,提高容器性能

volumes 和 bind mounts 的使用场景和区别

volumes 适合多个容器需要共享数据、将数据保存到远程主机或云上等场景。bind mounts 适合将宿主机的系统配置文件共享给容器。volumes 是将容器内部的数据映射到宿主机对应的 volumes 目录,如果容器内部是一个非空目录,volumes 目录也是一个非空目录,那么两个目录的文件会合并。而 bind mounts 是将宿主机上任意位置的目录或文件挂载到容器中,如果宿主机的目录非空,那么容器目录的数据将会被宿主机目录的数据隐藏,容器内的数据要卸除挂载后才会恢复

bind mounts 和volumes 都可以通过使用标志 “-v” 或 “–volume” 来挂载到容器中,只是格式有些许不同。然而,在 Docker17.06 及其以上版本中,我们推荐使用 “–mount” 来对容器或服务进行这三种方式的挂载,因为这种格式更加清晰