操作系統與存儲
操作系統中將存儲定義為 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)來去解決對網絡存儲的讀寫問題。