一、Docker 管理数据的方式
默认情况下,容器内创建的文件存储在容器的可写层上,这样的话:
- 容器不存在时,文件不会持久保留。
- 容器的可写层与容器宿主机紧耦合。
- 写入容器的可写层需要存储驱动程序管理文件系统。
Docker 容器提供两种方式在宿主机上存储文件,以便容器停止后文件也可以持久存储:volumes (卷)和 bind mounts (绑定挂载) 。如果是在 Linux 上运 Docker 则还可以使用 tmpfs mounts,Windows 则可以使用 pipe 。
1.1 三者的区别
根据存储宿主机不同位置来简单区分三者:
Volumes
存储是宿主机文件系统的一部分,文件由 Docker 管理在/var/lib/docker/volumes/
非 Docker 进程不应该修改。Binds mounts
可以是宿主机文件系统的任何位置。Docker 宿主机或 Docker 容器上的非 Docker 进程可以对其修改。tmpfs mounts
仅存储在宿主机的内存中,不会写入文件系统。
Volumes
volume 是常用的方式
Bind mounts
相对卷来说功能比较少,使用 bind mount 时,宿主机上的一个文件或者目录会挂载到容器中。
该方式是可以访问敏感文件的,容器有足够的权限操作宿主机的文件系统,可能会有安全隐患。
tmpfs mounts
该方式不持久存储到文件系统。
named pipes
Windows 下可使用该方式。
1.2 使用场景
Volumes
- 不同容器之间共享数据。
- Docker 主机配置与容器解耦。
- 容器数据存储在远程服务器或者云服务商。
- 备份迁移。
Bind mounts
- 宿主机中容器共享配置文件。
- 宿主机的开发环境与容器共享源代码或构建工作。
- 当需要确保主机的文件或者目录结构要与容器保持一致时。
tmpfs mounts
- 不需要持久化数据到宿主机文件系统或者容器中时。
1.3 建议
- 创建容器指定一个不存在的空卷时,会自动创建一个空卷;如果将空卷(注意是空卷)装入存在文件或目录的容器中,这些文件或目录会复制到这个卷中。
- 使用
bind mounts
或者非空 volumes
时,如果容器的某些文件或目录(卷中存在)则会被遮盖,不是被删除掉。这些文件不能被访问,直到容器卸载mounts
或者volumes
。
1.4 常用命令
Volumes
-
--mount
可用于本地的 Docker 或者 service,推荐使用此命令,更直观。 -
-v
:只用于本地 Docker ,推荐使用--mount
# 创建 删除 docker volume create my-vol docker volume rm my-vol docker volume ls docker volume inspect my-vol # 查看卷信息 docker volume prune # 删除未使用容器,危险 # 不同命令,使用卷启动容器 $ docker run -d --name devtest --mount source=myvol2,target=/app nginx:latest $ docker run -d --name devtest -v myvol2:/app nginx:latest # 查看容器 $ docker inspect devtest "Mounts": [ { "Type": "volume", "Name": "myvol2", "Source": "/var/lib/docker/volumes/myvol2/_data", "Destination": "/app", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ] ```
-
使用只读 volumes
# 使用只读 volumes $ docker run -d --name=nginxtest --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly nginx:latest $ docker run -d --name=nginxtest -v nginx-vol:/usr/share/nginx/html:ro nginx:latest
-
备份以及备份还原(查看官网)
Bind mounts
-
基本命令
# 不同命令,使用 bind mount 启动容器 $ docker run -d -it --name devtest --mount type=bind,source="$(pwd)"/target,target=/app nginx:latest $ docker run -d -it --name devtest -v "$(pwd)"/target:/app nginx:latest # 查看容器 Mounts 部分 docker inspect devtest "Mounts": [ { "Type": "bind", "Source": "/tmp/source/target", "Destination": "/app", "Mode": "", "RW": true, "Propagation": "rprivate" } ]
-
使用只读 bind mounts
$ docker run -d -it --name devtest --mount type=bind,source="$(pwd)"/target,target=/app,readonly nginx:latest $ docker run -d -it --name devtest -v "$(pwd)"/target:/app:ro nginx:latest
-
设置传播范围 propagation
默认是
rprivate
(待完成)Propagation setting Description shared
slave
private
rshared
rslave
rprivate
tmpfs mounts
--mount
、 --tmpfs
具有一样的效果:
$ docker run -d
-it
--name tmptest
--mount type=tmpfs,destination=/app
nginx:latest
$ docker run -d
-it
--name tmptest
--tmpfs /app
nginx:latest
tmpfs mounts 的配置选项(--tmpfs 不支持)
Option | Description |
---|---|
tmpfs-size | tmpfs 挂载的大小,默认无限制。 |
tmpfs-mode | tmpfs 的文件模式。例如 700 或 0770 。默认 1777 可全局写入。 |
$ docker run -d
-it
--name tmptest
--mount type=tmpfs,destination=/app,tmpfs-mode=1770
nginx:latest
二、Docker 迁移
2.1 Docker 位置的迁移
1.停止 docker 进程
$ service docker stop
2.迁移数据,例如 /var/lib/docker 默认的路径,/data/docker 迁移的路径
$ rsync -avz /var/lib/docker/ /data/docker
3.修改配置文件 /etc/docker/daemon.json (或添加文件)
{
"data-root": "/data/docker"
}
4.启动 docker 进程
$ service docker start
2.2 涉及持久化数据的 Docker 迁移
把镜像导出为静态文件
- 使用 volumes ,迁移镜像 + 卷
- commiit 镜像,将数据打包到镜像中
2.2.1 镜像迁移
- 导出静态文件的方式
# 将镜像导出为文件
# save
$ docker save imageName > xxx.tar
# save -o Write to a file, instead of STDOUT
$ docker save imageName -o xxx.tar
# save 使用 gzip
$ docker save imageName | gzip > xxx.tar.gz
# 导入文件生成镜像
$ docker load < xxx.tar
$ docker load -I xxx.tar
删除镜像,使用备份的镜像文件还原镜像
- 通过 Repostory
略
2.2.2 容器迁移
# 导出
$ docker export containeName -o xxx.tar
# 导入
$ docker import xxx.tar test-img # import后得到的是一个镜像(镜像名 test-img)
# 测试: 创建一个镜像,挂载卷,添加文件,之后导出容器再导入
$ docker run --rm -d --name test -v test-vol:/data test-img tail -f /dev/null
$ docker exec test touch /data/proof
$ docker exec test ls -hl /data/proof
导出容器 test-container.jar
之后删除容器 test,并且使用 docker volume rm test-vol 删除卷。使用备份的 test-container.jar 导入备份的容器,生成镜像。
启动容器后,发现容器挂载的卷,我们之前保存的数据并不存在。说明容器的迁移,并不能迁移数据。
2.2.3 数据卷迁移
我们先来看一下整个数据卷迁移操作演示用到的命令:
# 「备份」(迁出机器上,通过运行一个容器,将要迁出的数据卷备份)
# 迁出机器已经运行了一个容器 wordpress_db_1,挂载的数据卷为 wordpress_db_data
$ docker run --volumes-from wordpress_db_1 -v $(pwd):/backup alpine tar cvf /backup/backup.tar /var/lib/mysql
# 「还原」(迁入机器上,通过运行一个容器,将要迁入的数据卷还原到运行的容器上)
# 迁入机器已经运行了一个容器 wordpress_db_1,挂载的数据卷为 wordpress_db_data
$ docker run --volumes-from wordpress_db_1 -v $(pwd):/backup alpine tar xvf /backup/backup.tar
在迁入机器上,运行容器 wordpress_db_1 后,通过 docker exec -it wordpress_db_1 bash ,登录数据库,发现数据库中仅有一个 wordpress 的实例,没有具体的表结构与数据。(PS. 这是使用的是 docker-compose.yml 的方式启动容器,初始化了一个数据库实例)
导入备份的文件后,再次登录数据库,可以看到迁出机器上的数据库数据已经成功还原到迁入机器的数据卷中。
欢迎留言讨论~