簡介
docker storage driver支援了image分層儲存和容器可寫層的儲存管理,使用掛載主機目錄的方式可以將資料儲存在主機的檔案系統上或記憶體中。
- 之前學習過映象的分層儲存,以Dockerfile構建映象每行有關資料寫入的命令會給映象增加一層,容器基於映象啟動,會在映象最上層之上再啟動一層可寫層(writable layer),如果容器被刪除,那麼該可寫層也會消失,所以容器內的可寫層不宜用來對需要持久化的資料做儲存,應當儲存一些臨時資料,這些資料不影響應用的後續使用,比如之前使用的busybox用來執行wget、ping等命令,執行期間產生的資料我們無需儲存,即使容器被刪除,後面再次使用時啟動新容器還是可以達到相同的目的。
- 可以使用volumes和bind mounts的方式將資料儲存在主機上,這樣即使容器被刪除,資料仍然在,而且很容的對資料進行遷移與共享。
- 由於容器可寫層需要storage dirver的支援,需要通過核心提供一個union filesystem,維護了額外的資料結構,相較於直接使用資料卷效能更差些,具體的實現方式在後面研究相關底層技術再記錄,先整理下儲存卷的相關知識。
掛載方式
有三種掛載方式將容器內部資料儲存到主機上,Volumes、bind mounts、tmpfs mounts
Volumes
由docker建立和管理,主機上的其他程式不可修改,將資料卷儲存在主機的一片區域上(linux路徑/var/lib/docker/volumes/
),使用某個volume其實是將該volume在主機上的目錄mount到容器內,如果該目錄下已有內容,則原有的資料會被複制到volume中。
使用場景
- 多個容器共享資料,多個容器可以同時掛載一個volume
- 允許使用volume driver,不需要更改應用程式,通過更換volume dirvier儲存容器資料到遠端主機或雲端(例如NFS or S3)
- 備份和遷移資料
# 建立volume
docker volume create volume-test1
# 檢視volume詳細資訊
docker volume inspect volume-test1
# 刪除volume,只有沒有任何容器使用時才可刪除(包括停止的容器)
docker volume rm volume-test1
啟動容器時指定volume引數
# 啟動容器nginx1,卷volume-test1掛載到nginx1內部的/app路徑下
docker run -d \
--name nginx1 \
--mount source=volume-test1,target=/app \
nginx:latest
- 如果將新建的volume掛載到容器某個目錄下,並且該目錄下已有內容,那麼會將這些內容拷貝到volume中,其他容器使用該volume時也可以看到
使用volume driver
例如,使用vieux/sshfs驅動允許容器使用sshfs掛載遠端資料夾
# 下載vieux/sshfs驅動外掛
docker plugin install --grant-all-permissions vieux/sshfs
# 使用vieux/sshfs驅動建立volume,驅動配置選項通過-o指定
docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
sshvolume1
# 啟動時建立並使用volume,volume-opt指定使用volume需要的引數
docker run -d \
--name sshfs-container \
--volume-driver vieux/sshfs \
--mount src=sshvolume2,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
nginx:latest
建立CIFS/Samba volume,可以直接使用容器掛載samba資料夾
# local是預設的driver
docker volume create \
--driver local \
--opt type=cifs \
--opt device=//uxxxxx.your-server.de/backup \
--opt o=addr=uxxxxx.your-server.de,username=uxxxxxxx,password=*****,file_mode=0777,dir_mode=0777 \
--name cif-volume
備份volume
# 建立一個容器dbstore
docker run -v /app --name dbstore ubuntu /bin/bash
# 再建立一個新容器,將主機當前目錄$(pwd)掛載到新容器/backup目錄下,新容器與容器dbstore共享其volume,之後執行新容器執行tar cvf /backup/backup.tar /app將/app目錄歸檔到/backup/backup.tar下面(即主機$(pwd)下面)
docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /app
恢復
# 建立新的容器
docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
# 共享新容器的volume卷,並將備份檔案所在目錄$(pwd)掛載到當前容器/backup下,解壓backup.tar到容器dbstore2的/dbdata
docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar"
bind mounts
-
與volume不同的是,除了可以掛載目錄,還可以掛載檔案到容器內。
-
可以提供更好的效能,具體效果依賴主機使用的檔案系統。
-
因為使用絕對路徑與主機目錄繫結,所以容器的移植性較volume更弱,隔離性差(其他程式也可以修改該路徑的內容)。
-
可以對容器設定只讀或讀寫許可權
使用場景
- 將原始碼目錄掛載到容器中,在主機修改程式碼,可以看到容器應用的變化效果
- 共享主機檔案到容器,比如將主機的
/etc/resolv.conf
掛載到容器,為容器提供DNS解析
使用bind mounts
# 使用bind mounts,將主機target目錄掛載到容器/app下,容器對該目錄有隻讀許可權
docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app,readonly \
nginx:latest
- 如果容器目錄已有內容,將主機目錄bind mounts到該目錄下時,容器該目錄下原有的內容被隱藏,只顯示主機目錄下已有的內容
tmpfs mounts
tmpfs mounts方式與上兩種不同,是將容器內該掛載點下的內容寫到主機記憶體中,容器停止時候,掛載點被移除,這些內容就會丟失。
使用場景
- 存放一些臨時的敏感資訊(不想將其存放到主機或容器中)
- 容器應用需要寫入大量的非持久化資料時提高效能
使用tmpfs mounts
# 執行容器,使用tmpfs mounts到容器的/app目錄下,設定容器內使用許可權為770,/app目錄大小為10M
docker run -d -it \
--name tmptest \
--mount type=tmpfs,destination=/app,tmpfs-mode=1770 tmpfs-size=10m\
nginx:latest
- 預設tmpfs mounts不對目錄大小做限制
小結
對於以上三種掛載方式,bind mounts與volumes的使用與功能差異較小,通過表格的方式對比下:
對比項(source:主機;dest:容器) | bind mount | volume |
---|---|---|
建立時主機路徑不在 | 報錯 | 自動建立 |
source路徑 | 使用時指定 | /var/lib/docker/volumes |
source路徑為空 | 隱藏dest,顯示source內容 | 將dest內容複製到source後顯示source內容 |
source路徑不為空 | 隱藏dest,顯示source內容 | 隱藏dest,顯示source內容 |
可移植性 | 弱(繫結主機路徑) | 強(docker完全控制,不依賴主機路徑) |
主機程式訪問 | 容易(chown修改使用者組即可訪問) | 受限(需root使用者) |
學習自:
《Docker技術入門與實戰(第3版)》Nigel,Poulton(奈吉爾·波爾頓) 著,李瑞豐,劉康 譯
《深入淺出Docker》楊保華,戴王劍,曹亞侖 著
https://docs.docker.com/