容器中的数据与Host相互独立,随着容器的释放(删除),这些数据也将丢失.
为了避免这个问题,Docker提供了数据卷(Volume)这个数据持久化工具.
持久化后的数据,不会随着容易删除而丢失.
概述
试想这样一个场景,几年前我创建了一个mysql5.5
的容器,几年后由于业务变动,需要升级到mysql5.6
,这个时候需要登陆到容器里面,把mysql
的表文件复制下来,再想办法迁移到新的mysql
服务中.
这个手动复制的过程很容易出现意外,万一不粗心大意,没有复制data就删除了容器,那差不多可以跑路了,否则就等着全村吃席吧.
好在Docker提供了bind mount
和volume
两种方式来做数据持久化,先准备个mysql
镜像准备演示.
docker pull mysql:5.6
bind mount
bind mount
是将host
上的一个目录mount
到容器中,类似于一个共享文件夹.
要bind mount
一个目录到容器,需要在创建容器时使用-v 本地目录:容器目录
参数指定
docker run -v /Users/zhangsan/opt:/opt ......
上述例子将本地/Users/zhangsan/opt
目录挂在到容器的/opt
目录. 登陆容器,
docker exec -it mysql_test_volume /bin/bash
echo Hello,World >> index.html
exit
此时本地的/Users/zhangsan/opt
目录就会出现刚才创建index.html
.
反之,如果在本地新增文件index2.html
,容器内也会出现这个文件.
使用bind mount
需要注意以下几点:
-
host
路径必须为全路径,否则回和volume
混淆 - 如果
host
目录不存在,docker
会自动创建该目录 - 如果容器目录不存在,
docker
会自动创建该目录 - 如果容器目录已有数据,那么
docker
会将其覆盖掉
就上面那个场景,如果使用了 bind mount
,此时只需要新起一个5.6版本的容器,将目录mount到新地址即可.
docker run -v /Users/zhangsan/opt:/opt --name mysql_test_volume -d -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:5.6
由于bind mount
本质是个共享文件夹,因而依赖于系统文件系统,不同系统间无法移植,
windows
的NTFS
文件系统就无法与linux
常用的ext3/4
兼容,windows
目录为\Users\zhangsan\...
格式,
而ext4
文件系统目录路径为/usr/...
volume
volume
是容器上的一个或者多个目录,此目录可以绕过文件系统,与宿主机上的某目录绑定.
volume
于容器化初始化之时即会创建,可以在不同host上移植,卷中的数据会在build image
期间完成复制.
- 数据卷可以在容器之间共享和重用
- 对数据卷的更改是直接进行的
- 更新镜像时,不包括对数据卷的更改
- 即使删除容器本身,数据卷也会保持
使用docker volume create volume_name
来创建一个卷
docker volume create test
将test
挂在到容器上
docker run -v test:/opt --name mysql_test_volume -d -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:5.6
查看所有卷,使用
docker volume ls
查看一个卷信息,使用
docker volume inspect volume_name
删除未使用的卷
docker volume prune
删除一个卷
docker volume rm volume_name
与bind mount
不同的是,
- 如果
volume
是空的而容器中的目录有内容,那么docker
会将container
目录中的内容拷贝到volume中 - 但是如果
volume
中已经有内容,则会将container
中的目录覆盖 - Mac系统的
docker Desktop
实际上是构建在虚拟机上的,其volume在虚拟机的var/lib/docker/volume中
,本机上不存在这个路径.
volume迁移
最2的方式,登陆host
的/var/lib/docker/volume
目录找到对应的volume
,打包带走,在新host
的volume
中解压.
上面注部分提到过volume
的特点,可以利用这点来进行迁移,假设有一个卷test
需要迁移,步骤如下
1.下载一个镜像,越小越好,比如(alpine)
2.通过这个镜像创建容器A
,挂在test
,由于容器内容为空,test
中的数据会被复制到容器目录中
3.打包这个容器A
打包成镜像image-A
,push
或者本地快照
4.新机器上新建同名volume
,然后pull
或者import
镜像image-A
5.通过镜像image-A
启动容器B
,挂载卷test
,由于test
是空的而容器目录有内容,docker
会将container
目录中的内容拷贝到volume中.
6.删除镜像image-A
,容器A
,容器B
,由于数据卷不会被删除,因而就完成了迁移,可以给新的容器使用.
这样volume
就随着容器迁移到新的host上了