Docker中的数据,比如Mysql,Redis这些,在容器重启或被删除以后,数据是不会保留的,也就是说数据没有持久化。
在Docker中实现数据持久化有两种方式:
Bind Mount:
Bind mount 方式是 docker 早期使用的容器与宿主机数据共享的方式,可以实现将宿主机上的文件或目录挂载(mount)到 docker 容器中使用。
相对于 volume 方式,bind mount 方式存在不少的局限。例如,bind mount 在 Linux 和 Windows 操作系统下不可移植。因此 docker 官方推荐使用 volume 方式。
William在这里以Mysql镜像为例子,将/home/mysql目录挂载到容器的/var/lib/mysql目录中
docker run --name mysql -it -p 3306:3306 -v /home/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql对于bind mount,有几点需要注意。
-v宿主机目录路径必须以/或~/开头,否则 docker 会将其当成是 volume 而不是bind mount- 如果宿主机上的目录不存在,
docker会自动创建该目录 - 如果容器中的目录不存在,
docker会自动创建该目录 - 如果容器中的目录已有内容,那么
docker会使用宿主机上目录的内容覆盖容器目录的内容
Volume:
与 bind mount 不同,volume 由 docker 创建和管理,docker 所有的 volume 都保存在宿主机文件系统的 /var/lib/docker/volumes 目录下(但是macOS 是以虚拟机形式运行 docker的,因此并不存在该目录,可以参考 stackoverflow)。
Docker 引入 volume 的原因有:
- 删除容器时,
volume不会被删除 - 在不同的容器之间共享
volume(存储 / 数据) - 容器与存储分离
- 将
volume存储在远程主机或云上
可以使用 docker run -v 参数为启动容器加载一个 volume,例如(最新版本镜像默认不用加tag,特定版本要加):
docker run --name mysql_test -d -p 3306:3306 -v /data -e MYSQL_ROOT_PASSWORD=123456 mysql:tag这时候就启动了一个名为mysql_test的mysql容器,使用docker exec -it mysql_test bash进入到mysql_test容器中的data目录创建一个文件 touch test.txt 然后退出容器,使用inspect命令查看刚才容器启动时做了什么:docker inspect mysql_test
可以看到一大串 JSON 格式的输出,我们重点关注 Mounts 字段的输出:
"Mounts": [
{
"Type": "volume",
"Name": "57be41568e142560aaf333beb9a4dd7b79a37c78a45a4d930a31455f24fe7d13",
"Source": "/var/lib/docker/volumes/57be41568e142560aaf333beb9a4dd7b79a37c78a45a4d930a31455f24fe7d13/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "6d826d6b7b2c00d4f78cedadf997d393b51cb79b5a65b531372274c806efc3ce",
"Source": "/var/lib/docker/volumes/6d826d6b7b2c00d4f78cedadf997d393b51cb79b5a65b531372274c806efc3ce/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]可以看到,当容器 mysql_test 加载一个 volume (/data)时,docker 在目录 /var/lib/docker/volumes/ 创建一个新的目录,用来存储容器中产生的文件。同时,我们注意到 /data 的 RW 属性为 true,即可读可写。
重新启动 container1 容器,再进入容器会发现刚才创建的test.txt还在,说明即使容器关闭,之前在 volume 存储的文件仍然会保留下来,即数据持久化没问题!
先停掉容器docker stop mysql_test,再删掉容器 docker rm mysql_test,使用命令 docker volume ls可以看到,刚才的两个volume
57be41568e142560aaf333beb9a4dd7b79a37c78a45a4d930a31455f24fe7d13
6d826d6b7b2c00d4f78cedadf997d393b51cb79b5a65b531372274c806efc3ce仍然存在。也就是说,即使容器不存在了,volume 仍可在宿主机上保存下来。
如果需要在其他容器也使用这个 volume,可以使用以下命令加载指定的 volume:
docker run -it -v 57be41568e142560aaf333beb9a4dd7b79a37c78a45a4d930a31455f24fe7d13:/data container_name挂载指定的 volume
上面的 docker run -v 命令中,我们并没有指定 volume 的名称,这样 docker 会默认给我们创建一个匿名的 volume,就是很长的那字符串。
我们也可以挂载指定名称的 volume:docker run -it -v my-volume:/data --name 自定义容器名 镜像名:tag
这样,我们在启动容器该容器时,将挂载一个名为 my-volume 的 volume,并挂载到容器的 /data 目录。对于 docker 来说,如果 my-volume 不存在,那么 docker 就会自动创建该 volume,并挂载到 /data 目录。
比如运行的是Reids:
docker run -d -it -v redis_volume:/data --name myRedis redis执行 docker volume inspect redis_volume 查看redis挂载的volume信息
可以看到 my-volume 的 JSON 输出信息:
[
{
"CreatedAt": "2020-08-24T09:33:30-04:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/redis_volume/_data",
"Name": "redis_volume",
"Options": null,
"Scope": "local"
}
]可以看到redis_volume的宿主机目录位置是:/var/lib/docker/volumes/redis_volume/_data
除了让 docker 帮我们自动创建 volume,我们也可以自行创建 volume:docker volume create my-volume
删除volume命令是:docker volume rm volume-name
然后将这个手工创建的 volume 挂载到容器:docker run -d -v redis_volume2:/data --name myRedis001 redis
评论 (0)