操作系统与存储
操作系统中将存储定义为 Volume(卷) ,这是对物理存储的逻辑抽象,以达到对物理存储提供有弹性的分割方式。另外,将外部存储关联到操作系统的动作定义为 Mount(挂载)。
Docker 中的三种挂载方式
- Bind
把宿主机的某个目录(或文件)挂载到指容器的指定目录(后文件)下,比如下面的命令就表示通过 Bind 方式将外部的 HTML 文档挂载到 Nginx 容器的模式网站根目录下:
$ docker run -v ~/zioyi/html:/usr/share/nginx/html -p 81:80 -d --name nginx_bind nginx:latest
来验证一下
$ curl localhost:81
<html>
<title>Hi, Docker</title>
<h1>You mount me by Bind mode</h1>V
</html>
这种方式的缺点就是被挂载的宿主机目录(或文件)不收保护,任何容器都可以去随意修改。
- Volume
Volume 模式下,我们需要通过docker volume
命令来创建一个 Volume。实际上,是在 Docker 的/var/lib/docker/volumes/
文件夹内创建一个相同名字的文件夹来保存数据。因为这个文件夹在 Docker 管控范围里,Docker 可以根据挂载的设定来控制容器对 Volume 的读写权限。
# 创建 volume
$ docker volume create nginx-volume
nginx-volume
$ docker run --mount type=volume,source=nginx-volume,destination=/usr/share/nginx/html -p 82:80 -d --name nginx_volume nginx:latest
此时,nginx_volume 容器已经挂载了 nginx-volume 卷,通过 inpsect 命令可以看到:
$ docker inspect nginx_volume
{...
"Mounts": [
{
"Type": "volume",
"Name": "nginx-volume",
"Source": "/var/lib/docker/volumes/nginx-volume/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
...}
我们进入容器中修改/usr/share/nginx/html
中的 HTML 文档
$ docker exec -it nginx_volume bash
root@d0df9a0eb3e5:/# echo "<html>
<title>Hi, Docker</title>
<h1> You mount me by Volume mode</h1>
</html>" > /usr/share/nginx/html/index.html
root@d0df9a0eb3e5:/# exit
exit
# 在宿主机中验证
$ curl localhost:82
<html>
<title>Hi, Docker</title>
<h1> You mount me by Volume mode</h1>
</html>
当我们删除容器 nginx_volum 时,volume 也不会删除
$ docker stop nginx_volume && docker rm nginx_volume
$ docker run --mount type=volume,source=nginx-volume,destination=/usr/share/nginx/html -p 82:80 -d --name nginx_volume nginx:latest
$ curl localhost:81
<html>
<title>Hi, Docker</title>
<h1>You mount me by Volume mode</h1>
</html>
此外,我们还可以在挂载时设定容器只能读取卷,无法进行写操作,这种方式多用于容器读取配置文件的场景:
$ docker run --mount type=volume,source=nginx-volume,destination=/usr/share/nginx/html,readonly -p 82:80 -d --name nginx_volume nginx:latest
$ docker exec -it nginx_volume bash
root@782b11b3cc43:/#
# 当我们再次修改时报错
root@782b11b3cc43:/# echo "hello" > /usr/share/nginx/html/index.html
bash: /usr/share/nginx/html/index.html: Read-only file system
- tmpfs
tmpfs 挂载是临时的,仅保留在主机内存中。当容器停止时,tmpfs 挂载被移除,写入的文件不会被持久化
$ docker run --mount type=tmpfs,destination=/usr/share/nginx/html -p 83:80 -d --name nginx_tmpfs nginx:latest
$ docker inspect nginx_tmpfs
{...
"Mounts": [
{
"Type": "tmpfs",
"Source": "",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
...}
进入容器 nginx_tmpfs 修改数据
$ docker exec -it nginx_tmpfs bash
root@68b03d8d3ec4:/# echo "<html>
<title>Hi, Docker</title>
<h1> You mount me by tmpfs mode</h1>
</html>" > /usr/share/nginx/html/index.html
root@68b03d8d3ec4: exit
exit
# 验证
$ curl localhost:83
<html>
<title>Hi, Docker</title>
<h1> You mount me by tmpfs mode</h1>
</html>
tmpfs 无法对容器内产生的数据持久化,一般不使用。
总结
- 对比 Docker 三种挂载方式:
Bind | Volume | tmpfs | |
---|---|---|---|
volume 位置 | 可指定任意位置 | /var/lib/docker/volumes/... | 宿主机内存中 |
对已有mount point 影响 | 隐藏并替换为 volume | 原有数据复制到 volume | - |
是否支持单个文件 | 支持 | 不支持,只能是目录 | - |
权限控制 | 可设置为只读,默认为读写权限 | 可设置为只读,默认为读写权限 | - |
移植性 | 移植性弱,与 host path 绑定 | 移植性强,无需指定 host 目录 | - |
是否支持持久化 | 支持 | 支持 | 不支持 |
- 关于 Volume
Volume 模式并不是 Docker 一开始就有的,Docker 最初认为 Volume 就只是一种“外部宿主机的磁盘存储到内部容器的映射关系”,但后来发现事情并没有那么简单:存储的位置并不局限于外部宿主机,存储的介质并不局限于物理磁盘,存储的管理也并不局限于映射关系。Bind 模式无法很好地解决多跨宿主机共享存储的问题、Bind 模式的管理问题等。
提出 Volume 的最核心的目的是提升Docker对不同存储介质的支撑能力,这同时也可以减轻Docker本身的工作量。存储不仅有挂载在宿主机上的物理存储,还有网络存储,Docker 抽象出了存储启动(Sotroage Driver)来去解决对网络存储的读写问题。