前面(哪个前面我也忘了)有说过,如果我们需要对数据进行持久化保存,不应使其存储在容器中,因为容器中的数据会随着容器的删除而丢失,而因通过将数据存储于宿主机文件系统的形式来持久化。在Docker容器中管理数据主要有数据卷、宿主机目录挂载两种方式。

1. 数据卷的方式

数据卷是一个特殊的文件目录(或文件),具备如下特性:

  1. 可以在容器之间共享和重用

  2. 对数据卷的修改会立马生效
  3. 数据卷的更新,不会影响到镜像
  4. 数据卷默认会一直存在,不会随容器的删除而消亡

1.1 创建数据卷

可以使用docker volume create 数据卷名称的命令来创建一个数据卷,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker volume create volume1
volume1

1.2 查看数据卷

创建完后,这个数据卷具体对应宿主机哪个文件目录在上面是没法得知的,可以通过 docker volume inspect 数据卷名称来查看,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker volume inspect volume1
[
{
"CreatedAt": "2019-08-12T19:43:47+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/volume1/_data",
"Name": "volume1",
"Options": {},
"Scope": "local"
}
]
可以看到数据卷volume1对应的文件目录是“/var/lib/docker/volumes/volume1/_data”。

docker inspect xxx这个命令挺有用的,不论是查看镜像相关信息(docker image inspect 镜像名/镜像ID),还是查看容器相关信息(docker container inspect 容器名/容器ID),都可以使用,其中的image,container,volume是可以省略的,只要xxx部分不冲突就行。
可以通过docker volume ls 命令来查看所有数据卷,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker volume ls
DRIVER VOLUME NAME
local volume1

1.3 使用数据卷

可以在启动容器时通过 -v 或 –mount 的方式将一个数据卷挂载到容器的某个目录

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu1 -v volume1:/vol1 ubuntu:18.04
b060e793d44de2ca871da257b47598334658952943a13d1c478df5c3ae91a01c

按照 -v 数据卷名:容器目录 的格式,也可以使用 –mount 按照 --mount source=数据卷名,target=容器目录 的格式,如我们再启动一个挂载相同数据卷的容器 ubuntu2,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu2 --mount source=volume1,target=/vol2 ubuntu:18.04
b30971f8a4bbadee10774fce0b4568b5b7b1c9cde36f4bf84ac911a4cdaf6c8d

可以在数据卷所在目录中创建一个文件来看看效果,先创建文件 hello.txt

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# cd /var/lib/docker/volumes/volume1/_data
[root@iZwz9dbodbaqxj1gxhpnjxZ _data]# touch hello.txt
[root@iZwz9dbodbaqxj1gxhpnjxZ _data]# ls
hello.txt

然后通过docker exec来查看容器ubuntu1目录/vol1,及容器ubuntu2目录/vol2的内容

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu1 ls /vol1
hello.txt
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu2 ls /vol2
hello.txt

可以看到通过挂载目录 /vol1, /vol2 都可以访问到数据卷volume1对应目录下的内容。这就像linux的软链接一样,将容器目录链接到了数据卷目录。并且上述示例也说明,同一个数据卷是可以在被多个容器共享的。

数据卷的共享也可以通过 volumes-from 容器名称/容器ID 参数来实现,如

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu3 --volumes-from ubuntu2 ubuntu:18.04
bb5c6d61a1e6eeb18ba8c889e471b2f3215f97efca79b311eeca5968b2700df8
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu3 ls /vol2
hello.txt

通过--volumes-from ubuntu2来直接使用ubuntu2挂载的容器配置。

1.4 删除数据卷

数据卷不会随着容器的删除而自动删除。如果一个数据卷还被某个容器使用,则不能删除;如果一个数据卷只被一个容器使用,则可在删除容器时通过指定 -v 参数同时删除其挂载的数据卷;

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker rm -v ubuntu3
ubuntu3

可以通过 docker volume rm 数据卷名称 来删除某个数据卷;

可以通过 docker volume prune 清理掉所有未被任何容器使用的数据卷。

2. 宿主机目录挂载方式

在容器启动时,使用 -v 宿主机目录:容器目录 或 --mount type=bind,source=宿主机目录,target=容器目录的参数格式指定将宿主机目录挂载到容器目录上。宿主机目录必须是绝对路径。两者之间的区别是 -v 如果在宿主机目录不存在时会自动创建目录,而--mount不会。如,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu1 -v /root/v1:/vol1 ubuntu:18.04
25c91911709eebc9290b47b483666f7b7be840df947117f7cad323583905b9f1
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu2 --mount type=bind,source=/root/v2,target=/vol1 ubuntu:18.04
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /root/v2.
See 'docker run --help'.
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# mkdir /root/v2
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu2 --mount type=bind,source=/root/v2,target=/vol1 ubuntu:18.04
5a57285e9261d048dc71cf0476055a290f80538afff2cefd2a24f8b4468b5171

/root/v1,/root/v2都没有事先创建,用 -v 不会报错,会自动创建; --mount则会报错,目录必须先存在。docker不仅支持目录的挂载,也支持文件的挂载,如,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run --rm -it -v $HOME/.bash_history:/root/.bash_history ubuntu:18.04 bash
root@3ae4ed4e687d:/# history
ll webapps/
ll confluence/images/

通过将宿主机当前用户的历史操作文件挂载到容器的root用户下的历史操作文件,可在容器中通过history命令查看到宿主机的操作历史。可通过 docker inspect来查看容器的挂载情况

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker inspect ubuntu1
--省略了其它信息--
"Mounts": [
{
"Type": "bind",
"Source": "/root/v1",
"Destination": "/vol1",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
--省略了其它信息--
可在“Mounts”部分看到挂载信息。

3. 只读控制

有时候,为了数据安全,我们不允许容器对挂载目录的内容进行修改,即对容器来说,挂载目录是只读的,这可以通过在挂载参数后面加限制实现。

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu3 -v /root/v1:/vol1:ro ubuntu:18.04
25eca348ed307afcbef92bc03f0a1304b31b52e6db1fa07772b5dbd1040ff7b6
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu3 bash
root@25eca348ed30:/# touch /vol1/hello.txt
touch: cannot touch '/vol1/hello.txt': Read-only file system
-v是在后面加ro(read-only),--mount则是形如--mount type=bind,source=宿主机目录,target=容器目录,read only的格式,可自行试验。

加了read only的挂载我们再通过docker inspect命令查看,可看到两者之间的差异 —— Mode与RW的值。

"Mounts": [
{
"Type": "bind",
"Source": "/root/v1",
"Destination": "/vol1",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
}
],

4. 总结

如果要对数据进行持久化管理或在容器之间共享数据,则需要将数据通过数据卷或宿主机目录(或文件)挂载的方式来将数据存储于宿主机上,使得数据的生命周期独立于容器的生命周期。这类似于我们不要把重要文件放在系统盘,而应放在其它数据盘一样,因为系统盘会由于重装系统或系统故障导致文件丢失。本文对Docker的数据管理进行了整理,后续对Docker的网络配置管理部分进行整理,欢迎持续关注。

相关阅读

Docker笔记(一):什么是DockerDocker笔记(二):Docker管理的对象Docker笔记(三):Docker安装与配置Docker笔记(四):Docker镜像管理Docker笔记(五):整一个自己的镜像Docker笔记(六):容器管理Docker笔记(七):常用服务安装——Nginx、MySql、Redis

本文发表于微信公众号:“空山新雨的技术空间”

作者:空山新雨
欢迎关注,转发,推荐,你的支持是我持续创作的动力

最新文章

  1. 湖南省第十二届大学生计算机程序设计竞赛 B 有向无环图 拓扑DP
  2. 巧用在线html编辑器,保存文章到数据库(带html标签)
  3. hdu 1561 The more, The Better(树形dp,基础)
  4. poj: 1003
  5. Ubuntu14.04上安装tftpd服务
  6. 专题合集:深入Android媒体存储服务
  7. iOS Quartz2D画图
  8. 去除MyEclipse频繁弹出的Update Progress窗口
  9. [51nod1676]无向图同构
  10. vue 使用微信JSSDK,在IOS端会授权出错
  11. 一篇 SpringData+JPA 总结
  12. 同步方法、同步代码块、volidate变量的使用
  13. Linux-485收发切换延迟的解决方法
  14. xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH
  15. React Natived打包报错java.io.IOException: Could not delete path '...\android\support\v7'解决
  16. 轮询、中断、DMA和通道
  17. BZOJ3578:GTY的人类基因组计划2(集合hash,STL)
  18. 修复 Tween.JS 的 onStop 设置无效
  19. light oj 1007 Mathematically Hard (欧拉函数)
  20. vmware tool安装

热门文章

  1. AWS S3 上传文件
  2. Learning the Depths of Moving People by Watching Frozen
  3. 洛谷P2001 硬币的面值 题解
  4. Linux中的保护机制
  5. python 中_init_函数以及参数self
  6. 题解 P5367 【【模板】康托展开】
  7. MyBatis从入门到精通(十四):在MyBatis中使用类型处理器
  8. MyBatis-Plus 使用说明介绍
  9. 用python输出菱形
  10. @GetMapping、@PostMapping和@RequestMapping的区别