容器中的數據可以存儲在容器層。但是將數據存放在容器層存在以下問題:
- 數據不是持久化。意思是如果容器刪除了,這些數據也就沒了
- 主機上的其它進程不方便訪問這些數據
- 對這些數據的I/O會經過存儲驅動,然後到達主機,引入了一層間接層,因此性能會有所下降
Docker 提供了3種持久化數據的方式:
- volumes:存於主機文件系統中的某個區域,由Docker管理(/var/lib/docker/volumes/ on linux)。非Docker進程不應該修改這些數據。卷是Docker中持久化數據的最好方式
- bind mount:存於主機文件系統中的任意位置。非Docker進程可以修改這些數據
- tmpfs mount(Linux中):存於內存中(注意,並不是持久化到磁盤)。在容器的生命週期中,它能被容器用來存放非持久化的狀態或敏感信息
volumes
如果沒有顯式創建,一個卷會在最開始掛載時被創建。當容器停止時,卷仍然存在。多個容器可以通過read-write或read-only的方式使用同一個卷。
只有在顯式刪除時,卷纔會被刪除。如果將一個空卷掛載到容器中一個存有文件或目錄的目錄中,這些文件或目錄會被拷貝到空卷中;如果將一個非空卷掛載到容器中一個存有文件或目錄的目錄中,這些文件或目錄會被隱藏。
使用
- 創建:
docker volume create
- 刪除某個卷:
docker volume rm 卷名
- 刪除所有未使用的卷:
docker volume prune
- 列出所有卷:
docker volume ls
- 查看某個卷的信息:
docker volume inspect 卷名
- 掛載到容器:
-v
或--volume
。如果是Docker17.06或更高:推薦使用--mount
。(同 bind mount)
- 掛載類型:key爲type,value爲bind、volume或tmpfs
- 掛載源:key爲source或src,對於命名卷,value爲卷名,對於匿名卷,則忽略
- 容器中的掛載點:key爲destination、dst或target,value爲容器中的路徑
- 讀寫類型:value爲readonly,沒有key
- volume-opt選項,可以出現多次。比如volume-driver=local,volume-opt=type=nfs,…
第一個域:對於命名卷,爲卷名;匿名卷,則忽略,此時會創建匿名卷
第二個域:容器中的掛載點
第三個域:可選參數,由','
隔開,如ro
-v或—volume:由3個域組成,’:’分隔
—mount:由多個’,’隔開的鍵值對
=組成:
當使用docker service create 啓動Docker服務時,只支持--mount,不支持-v和--volume。並且每個服務容器使用它們各自的本地卷,因此如果使用本地(local)卷驅動,容器無法通過卷共享數據,但是一些卷驅動支持共享存儲。Docker for AWS和Doocker for Azure都使用Cloundstor plugin支持持久存儲
場景
- 多個運行容器間共享數據
- 當Docker主機不確保具有給定的目錄或文件時。卷可以將容器運行時與Docker主機的配置解耦合
- 備份、恢復、或將數據從一個Docker主機遷移到另一個Docker主機時
bind mount
主機中的文件或目錄通過全路徑被引用。在使用綁定掛載時,這些目錄或文件不一定要已經存在。
如果使用這種方式將一個目錄掛載到容器中一個存有文件或目錄的目錄中,這些文件或目錄會被隱藏;如果主機中的文件或目錄不存在,當使用--mount
掛載時,Docker會報錯,當使用-v
或--volume
時,會在主機上創建目錄
使用
掛載到容器:-v或—volume。如果是Docker17.06或更高:推薦使用—mount。(同 volumes)
-v
或--volume
:由3個域組成,':'
分隔
- 第一個域:對於命名卷,爲卷名;匿名卷,則忽略,此時會創建匿名卷
- 第二個域:容器中的掛載點
- 第三個域:可選參數,由
','
隔開,如ro
--mount
:由多個','
隔開的鍵值對<key>=<value>
組成:
- 掛載類型:key爲type,value爲bind、volume或tmpfs
- 掛載源:key爲source或src,value爲主機中文件或目錄的路徑
- 容器中的掛載點:key爲destination、dst或target,value爲容器中的路徑
- 讀寫類型:value爲readonly,沒有key
- bind-propagation選項:key爲bind-propagation,value爲rprivate、private、rshared、shared、rslave或slave
- 一致性選項:value爲consistent、delegated、cached。這個選項僅僅適用於Docker for Mac
--mount
不支持z和Z(這個不同於-v和—volume)
場景
大體上來說,只要可能,最好使用volumes
- 主機與容器共享配置文件(Docker默認情況下通過這種方式爲容器提供DNS解析,通過將/etc/resolv.conf掛載到容器中)
- 共享源代碼或build artifacts(比如將Maven的target/目錄掛載到容器中,每次在Docker主機中build Maven工程時,容器能夠訪問到那些rebuilt artifacts)
- 當 docker主機中的文件或目錄結構和容器需要的一致時
bind propagation
對於bind mount和volumes,默認都是rprivate。只有在使用bind mount時可配置,且必須在linux下。bind propagation是個超前主題,對於大多數用戶來說,並不需要配置
對於一個掛載點/mnt
,假設它同時也被掛載到/tmp
。bind propagation控制 whether a mount on /tmp/a would also be available on /mnt/a
在設置bind propagation之前,主機文件系統需要支持bind propagation
下面的例子將主機中的target/
掛載到容器中2次:
docker run -d -it --name devtest --mount type=bind,source="$(pwd)"/target,target=/app --mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave nginx:latest
此時如果創建/app/foo/
,/app2/foo
也會存在
selinux label
你能添加z
或Z
選項來修改掛載到容器中的主機文件或目錄的selinux label:
z
選項指明bind mount的內容在多個容器間是共享的Z
選項指明bind mount的內容是私有不共享的
要特別小心的使用這兩個選項。”Bind-mounting a system directory such as /home
or /usr
with the Z
option renders your host machine inoperable and you may need to relabel the host machine files by hand”
tmpfs mount
只在linux中支持
相對於volumes和bind mount,tmpfs mount是臨時的,只在主機內存中持久化。當容器停止,tmpfs mount會被移除。對於臨時存放敏感文件很有用
不同於volumes和bind mount,多個容器無法共享tmpfs mount
使用
- 掛載到容器:—tmpfs。如果是Docker17.06或更高:推薦使用—mount
- 掛載類型:key爲type,value爲bind、volume或tmpfs
- 容器中的掛載點:key爲destination、dst或target,value爲容器中的路徑
- tmpfs-size和tmpfs-mode選項
- —tmpfs:直接指定容器中的掛載點。不允許指定任何配置選項
- —mount:由多個’,’隔開的鍵值對
=組成:
場景
- 最好的使用場景是你既不想將數據存於主機,又不想存於容器中時。這可以是出於安全的考慮,或當應用需要寫大量非持久性的狀態數據時爲了保護容器的性能
volume drivers
機器間共享數據
當構建錯誤容忍應用時,可能需要配置同一個服務的多個副本來訪問相同的文件:
有多種方法來實現這個目的:
- 爲應用添加邏輯,將文件存儲到一個雲對象存儲系統(如Amazon S3)中
- 使用一個支持將文件寫入外部存儲系統(如NFS或Amazon S3)的driver來創建卷
volume drivers可以將底層存儲系統從應用邏輯中抽象出來。比如,如果你的服務使用一個具有NFS driver的卷,你能更新你的服務使用不同的driver,作爲在雲中存儲數據的示例,而不更改應用程序邏輯
使用
在使用docker volume create
或驅動容器創建匿名卷時,可以指定一個volume drivers。下面的例子使用vieux/sshfs作爲volume drivers
假設有2個節點,第一個節點是Docker主機,它能SSH到第二個節點
1、在Docker主機中,安裝vieux/sshfs插件
docker plugin install --grant-all-permissions vieux/sshfs
2、使用卷驅動創建卷
1)創建命名卷
docker volume create --driver vieux/sshfs -o sshcmd=test@node2:/home/test -o password=testpassword sshvolume
2)啓動容器時使用卷驅動創建匿名卷
docker run -d --name sshfs-container --volume-driver vieux/sshfs --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword nginx:latest
3、備份、恢復、遷移數據卷
1)備份一個容器
docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
- 啓動一個新容器,掛載dbstore容器中的卷
- 掛載一個本地主機目錄到容器/backup
- 使用tar將dbdata卷中的數據打包成backup.tar
2)用備份恢復容器
使用剛剛創建的備份來恢復容器:
docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
然後,在新創建的容器的卷中使用tar
解包備份的數據:
docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"