前言
Docker系列文章:
此篇是Docker系列的第四篇,大家一定要按照我做的Demo都手敲一遍,印象會更加深刻的,加油!
為什么需要容器數據卷
- 數據的持久化,假設MySQL的數據存儲在自身的鏡像當中,如果將鏡像刪除的話,存儲的數據就會丟失,這樣真的就是刪庫跑路了,因此需要將容器中的數據持久化到磁盤上去;
- 如果將數據存儲於鏡像中,主機上的其他進程不方便訪問這些數據;
數據卷持久化的三種方式比較

bind mount
存在於主機系統中的任意位置,非 Docker 的進程或者 Docker 容器可能隨時對其進行修改,存在潛在的安全風險。bind mount在不同的宿主機系統時不可移植的,比如Windows和Linux的目錄結構是不一樣的,bind mount所指向的host目錄也不能一樣。
volume
存於主機文件系統中的某個區域,由Docker管理文件目錄(/var/lib/docker/volumes/)。非Docker進程不應該修改這些數據。卷是Docker中持久化數據的最好方式;
tmpfs mount
存於內存中,並不是持久化到磁盤。在容器的生命周期中,可以被容器用來存放非持久化的狀態或敏感信息;
數據卷使用
bind mount
在使用bind mount可以使用-v或者--volume,這個參數在單容器的情況下使用,在swarm集群中使用--mount,從 Docker 17.06 之后,可以統一使用參數--mount。對於新接觸 Docker的來說建議使用--mount,老司機可以繼續使用-v,但是還是建議使用--mount。
語法
-v語法
分為三部分,使用冒號進行分割,排列的順序不能發生變化,每個字段所表達的含是不同的;
- 映射到宿主機文件的目錄的地址;
- 掛載到容器上的文件目錄的地址;
- 可選字段,用來增加附加項目,比如ro,rw等等;
--mount語法
由一組鍵值對組成,用逗號進行分割;

兩者差別:
使用-v的時候,如果在 Docker Host 不存在要掛載的文件或者目錄,Docker 將會自動進行創建,通常是一個目錄;
使用--mount的時候,如果在 Docker Host 不存在要掛載的文件或者目錄,Docker 不會自動創建目錄,並生成一個錯誤;
使用案例
我們使用Nginx來講解該案例;
- 后台方式啟動一個版本為nginx:latest名字叫nginxvolumetest的容器,將容器內端口映射到宿主機9999端口,將宿主機~/Documents/app/docker映射到容器的/usr/share/nginx/html/下面;
docker run -d -it --name nginxvolumetest -p 9999:80 -v ~/Documents/app/docker:/usr/share/nginx/html/ nginx:latest

- 檢查掛載目錄;
docker inspect nginxvolumetest

- 進入宿主機對應的目錄,在宿主機對應的目錄下創建index.html,編輯文件,寫入hello,dcoker bind mount!;
#進入宿主機對應的目錄
~/Documents/app/docker
#宿主機在docker目錄下創建index.html
touch index.html
#編輯文件
vim index.html
#插入
hello,dcoker bind mount!
- 進入容器內部,創建test.java文件,檢查是否同步過來index.html;
#查看鏡像ID
dcoker ps
#進入容器內部
docker exec -it e240f6b77437 /bin/bash
#進入對應的目錄
cd /usr/share/nginx/html/
#在對應目錄下創建test.java文件
touch test.java
#查看對應目錄下的文件
ls

- 查看宿主機對應下的目錄文件;
- 在瀏覽器中訪問http://localhost:9999/;
- 刪除對應的docker容器;
docker stop e240f6b77437
docker rm e240f6b77437
-mount使用
#后台方式啟動一個名字叫nginxmounttest的容器
#將容器內端口映射到宿主機9999端口
#將宿主機~/Documents/app/docker映射到/usr/share/nginx/html/
#版本為nginx:latest
docker run -d -it --name nginxmounttest -p 9999:80 --mount type=bind,source=/Users/wangtongzhou/Documents/app/docker,target=/usr/share/nginx/html/ nginx:latest
#進入容器內部
docker exec -it 7053db43219f /bin/bash
#查看文件內容
ls

從整個案例中我們看出本地的宿主機文件和docker內部文件是可以相互同步的,刪除掉容器以后也不會影響到本地宿主機文件的內容。
只讀掛載
- 刪除之前容器;
docker stop 7053db43219f
docker rm 7053db43219f
- 后台方式啟動版本為nginx:latest一個名字叫nginxmounttest的容器,將容器內端口映射到宿主機9999端口,將宿主機~/Documents/app/docker映射到容器的/usr/share/nginx/html/目錄下,並且設置為只讀;
docker run -d -it --name nginxmounttest -p 9999:80 --mount type=bind,source=/Users/wangtongzhou/Documents/app/docker,target=/usr/share/nginx/html/,readonly nginx:latest
#或者-v
docker run -d -it --name nginxvolumetest -p 9999:80 -v ~/Documents/app/docker:/usr/share/nginx/html/:ro nginx:latest
- 查詢掛載詳情;
docker inspect nginxmounttest

- 進入容器,創建aaa.java文件
touch aaa.java

readonly設置了只讀權限,在容器中是無法對bind mount數據進行修改的。只有宿主機可以進行數據修改。
volume
volume由Docker來進行管理,比如volume的創建,可以使用命令 docker volume create 來創建一個 volume,當容器或者服務創建的時候,Docker 也可以自動的創建一個 volume。
當我們創建了一個volume,它存儲在Docker宿主機的存儲目錄上。當把volume掛載入容器時,此目錄就會同步掛載到容器中的目錄。與bind mount同步方式一樣,不同的是volume是由Docker來管理並且和Docker Host的核心功能進行隔離。
一個給定的volume可以同時掛載到多個容器中。我們在掛載volume時,可以進行命名,叫做具名掛載,也可以是默認隨機生成的名字,叫做匿名掛載。當不指定名稱的時候,Docker會用一個隨機字符串對其進行命名,這樣可以保證 volume的唯一性。
此外volume支持使用 volume drivers,允許將數據存儲掛載到遠程主機上。
語法
-v語法
與bind mount語法類似,在不指定主機地址的時候,就是采用volume的方式進行掛載,分為三部分:
- 指定卷的名稱;
- 容器指定的掛載卷的地址;
- 可選字段,用來增加附加項目,比如ro,rw等等;
--mount語法
與bind mount語法類似,使用逗號分隔:

使用案例
- 創建名叫test卷;
docker volume test
- 進入test卷的_data目錄該目錄下無文件內容;
cd /var/lib/docker/volumes/test/_data
- 后台方式啟動一個版本為nginx:latest名字叫nginxvolumetest的容器,將容器內端口映射到宿主機9999端口,source指定本地卷名稱,target指定容器中的掛載的地址;
docker run -d -it -p 9999:80 --name nginxvolumetest --mount source=test,target=/usr/share/nginx/html nginx:latest
#或者-v命令
docker run -d -it -p 9999:80 --name nginxvolumetest -v test:/usr/share/nginx/html nginx:latest

- 查看容器的掛載詳情;
docker inspect nginxvolumetest

- 訪問localhost:9999;
- 再次進入進入test卷的_data目錄 會發現文件內容;
cd /var/lib/docker/volumes/test/_data
- 在volume的文件中創建a.html;
touch a.html
- 進入到容器中 查看掛載目錄中的文件;
docker ps
docker exec -it f24efa9063bc bash
ls

- 刪除容器 會發現卷中的內容還存在;
docker stop f24efa9063bc
docker rm f24efa9063bc
tmpfs
tmpfs不在磁盤上持久存儲,也不在 Docker Host 容器里面存儲,他存儲在host的內存中,它可以在容器的整個生命周期內被容器所使用。
語法
在單容器的情況下使用--tmpfs,並且不能指定參數,在集群的情況下使用--mount,可以指定一些參數;

使用
后台方式啟動一個版本為nginx:latest名字叫nginxtmptest的容器,將容器內端口映射到宿主機9999端口,采用tmpfs使用卷,target指定容器中的掛載的地址;
docker run -d -it -p 9999:80 --name nginxtmptest --mount type=tmpfs,target=/usr/share/nginx/html nginx:latest
使用場景
bind mount
- 宿主機中的配置文件、開發環境、代碼需要共享給宿主機上面的容器;
volume
- 多個正在運行的容器之間共享數據場景;
- 容器的數據永久存儲在一個遠程主機或者一個雲服務器上;
- 當我們需要備份數據,或者恢復數據,或者需要把數據從一個宿主機遷移到另外一個宿主機的時候,我們可以將正在使用volume的容器停止下來,然后把volume的目錄備份下來就可以了;
tmpfs
不需要將持久化的數據保留在宿主機或容器內使用tmpfs;
數據卷容器
如果用戶需要在多個容器之間共享一些持續更新的數據,最簡單的方式是使用數據卷容器。數據卷容器也是一個容器,但是它的目的是專門提供數據卷給其他容器掛載。復制卷始終具有相同的掛載點,數據卷的生命周期一直持續到沒有容器使用它為止,類似於繼承關系。
- 守護進程方式啟動一個名字叫centos01共享目錄為/data1版本為centos最近一個版本的容器;
docker run -d -it --name centos01 -v /data1 centos:latest
- 進入centos01容器內部;
#查看下容器id
docker ps
#進入容器內部
docker exec -it ec09d368858f /bin/bash
- 進入目錄data1,創建文件;
#查看文件目錄
ls
#進入目錄data1
cd data1
#創建文件
touch data01.txt
- 守護進程的方式啟動一個名字為centos02共享容器數據卷centos01版本為centos最近一個版本的容器;
docker run -d -it --name centos02 --volumes-from centos01 centos:latest
- 進入centos02容器內部,檢查文件目錄是否存在data01.txt文件;
#進入容器內部
docker exec -it ec09d368858f /bin/bash
#進入data1
cd data1
#ls查看文件目錄發現存在data01.txt文件
ls
- 進入centos02容器內部data1目錄,在對應目錄下創建data02.txt;
#在對應目錄下創建data02.txt
touch data02.txt
- 再次進入centos01的容器進入data1目錄,會發現data02.txt文件已經同步過來了;
cd data1
ls

總結
Docker將數據持久化的方式:
- docker cp命令將容器中的數據拷貝到宿主機上;
- 數據卷技術docker volume將容器內的數據映射到宿主機上;
- 數據卷容器docker --vlolumes-from使用特定的容器的數據卷,多個容器之間進行容器數據同步;
結束
歡迎大家點點關注,點點贊 !
