簡介
介紹
Docker的存儲卷稱之為volume,本質上容器上的一個或者多個目錄,而這些目錄繞過了聯合文件系統,與宿主機中的目錄或者其他容器目錄進行了綁定關系,這種綁定關系可以看作Linux的mount操作,當容器中的程序對這些目錄寫入數據時,其實寫入到的是與之綁定的宿主機目錄上,這樣就實現了數據的存儲功能。特別說明:本文章所使用的docker版本基於v18.X,對於較早版本的docker並不適合,例如tmpfs類型卷是v17.06新加入的存儲卷。
作用
默認情況下,容器不使用任何 volume時,容器的數據被保存在容器之內,它只在容器的生命周期內存在,會隨着容器的刪除而被刪除,而想要持久化的存儲這些數據,就得使用存儲卷。特別的,保存容器中的數據也可以使用 docker commit 命令將容器提交為一個新的鏡像,這個鏡像中會保存容器運行時的所有數據(綁定的數據卷除外),但此種方法非常不推薦,因為這樣的鏡像通常會很大,鏡像拉取以及運行容器都會變慢。當容器使用了存儲卷,即使容器被刪除了,但是與綁定的存儲卷還在,對應目錄的數據都會保存,如果想要恢復該容器,只要新建的容器綁定該存儲卷,對應目錄的數據也會隨之恢復。
分類
Docker存儲卷可分為兩類:
- Volumes:數據卷,這類存儲卷是被Docker Daemon管理,可使用docker volume create顯示創建,被創建出來的卷位於/var/lib/docker/volumes/下,使用時候只需指定使用卷的名稱以及對應的容器的一個目錄,刪除時候只需指定刪除卷名即可,這類數據卷是存儲數據最為推薦的方式。
- Bind mounts :綁定掛載卷,從早版本docker提供,這類存儲卷可以是宿主機的任意目錄,也可以是來自其他容器的目錄,不受docker Daemon管理,刪除時候需要手動清理目錄。
- tmpfs mounts:臨時掛載卷,該類存儲卷數據存放在主機內存中,好處在於這類存儲卷由於使用的tmpfs格式文件系統,讀寫性能好,但同時也增加了主機的內存開銷,Docker早期版本不支持此類存儲卷。
以下是其示意圖:

存儲卷使用
--volume&&--mount
存儲卷的使用是在docker run命令時候使用-v或者--volume來指明使用的存儲卷,但是如果需要指明更多選項如卷類型、驅動等那就需要使用--mount來指明更多的選項。以下是兩種選擇的使用方法。
-v或--volume選項:[volume_name]:container_path:[options]
解釋:
由三個字段組成,用冒號字符(:)分隔,字段必須按正確的順序排列
volume_name:卷名,可省略,省略的時候默認會分配一個隨機目錄,在/var/lib/docker/volumes/隨機目錄/_data。還可以指定宿主機目錄。
container_path:綁定的容器中的目錄,必須。
options:其他選項,是逗號分隔的選項列表,例如讀寫模式(ro、rw),可省略。
示例:創建一個綁定掛載卷

--mount:該選項從V17.06加入,由多個鍵值對組成,用逗號分隔,每個鍵值由<key>=<value>組成。常用的key如下:
- type:指明卷的類型,三種類型之一bind、volume、tmpfs
- source:可簡寫為src,指定掛載來源通常是卷名稱,匿名卷時忽略該選項
- destination:可簡寫為dst或target,指定容器中的使用的目錄
- readonly:指定卷是否為只讀
- volume-opt:其他掛載選項可以多次使用,采用volume-opt=type=nfs
示例:將上述容器使用--mount啟動(這里換一個名稱為nginx-c2):

使用建議:兩個命令能都實現數據卷的掛載,如果是老用戶可以繼續使用-v的方式來運行容器,如果是新用戶推薦使用--mount,這樣的語法比較簡介明了,比如人性化的各種選項src、type、dest,但是如果需要使用tmpfs類型的數據卷時候必須使用--mount。
使用Volumes
volume類型的數據卷是比較推薦方式,它是能被Docker 管理的卷, 使用流程是先創建卷,在使用-v或--mount進行掛載。如果在docker run時候不指定其宿主機目錄,則默認也屬於volumes類型,也受Docker管理。
創建卷
[root@app51 ~]# docker volume create data-vol data-vol [root@app51 ~]# docker volume inspect data-vol [ { "CreatedAt": "2019-02-28T17:39:36+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/data-vol/_data", "Name": "data-vol", "Options": {}, "Scope": "local" } ] [root@app51 ~]#
掛載卷並寫入數據
[root@app51 ~]# docker run -it --name bs1 -v data-vol:/data/tmp busybox:latest /bin/sh / # ls /data/tmp/ / # echo "hello world" > /data/tmp/index.html / #
在宿主機上查看:

創建卷是還可以指定其他,列如指定大小、uid等其他選項,這些選項都是mount命令的選項,卷的管理中會介紹:
[root@app51 ~]# docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 test-vol6 test-vol6 [root@app51 ~]# docker run -it --name bs6 -v test-vol6:/data/tmp busybox:latest /bin/sh / # ls /data tmp
上面的掛載命令使用等價--mount:
[root@app51 ~]# docker run -it --name bs7 --mount type=volume,src=test-vol6,dst=/data/tmp busybox:latest /bin/sh / #
容器內可以使用mount命令可以查看掛載點:

使用bind mounts
綁定掛載卷使用,無非指定宿主機的具體某個目錄,可以使用-v HOST_PATH:CONTAINER_PATH 也可以使用--mount type=bind,src=HOST_PATH,dst=CONTAINER_PATH。
示例:
[root@app51 ~]# docker run -it --name bind-vol -v "$(pwd)":/data busybox:latest /bin/sh / # ls /data Dockerfile a.txt anaconda-ks.cfg dr.sh nat.sh nginx-bus.tar.gz nginx.tar / #
等價於使用--mount:
[root@app51 ~]# docker run -it --name bind-vol-1 --mount type=bind,src="$(pwd)",dst=/data busybox:latest /bin/sh / # ls /data Dockerfile a.txt anaconda-ks.cfg dr.sh nat.sh nginx-bus.tar.gz nginx.tar / #
以只讀的方式掛載:
[root@app51 ~]# docker run -it --name bind-vol-2 --mount type=bind,src="$(pwd)",dst=/data,readonly busybox:latest /bin/sh / # ls /data/ Dockerfile a.txt anaconda-ks.cfg dr.sh nat.sh nginx-bus.tar.gz nginx.tar / # cd /data/ /data # touch 1.txt touch: 1.txt: Read-only file system /data #
查看卷(新開終端):
[root@app51 ~]# docker inspect bind-vol-2 "Mounts": [ { "Type": "bind", "Source": "/root", "Target": "/data", "ReadOnly": true } ],
使用tmpfs mounts
tmpfs類型的卷只適用於Linux系統,命令行中除了使用--mount指定外還可以使用--tmpfs指定其類型。特別注意的,與volume卷和綁定掛載卷相反,tmpfs掛載是臨時的,並且僅在主機內存中持久存在,當容器停止時,將刪除tmpfs掛載,並且不會保留寫在那里的文件。
示例 使用--mount:
[root@app51 ~]# docker run -it --name tmpfs-c1 --mount type=tmpfs,dst=/app busybox:latest /bin/sh / # / # mount |grep /app tmpfs on /app type tmpfs (rw,nosuid,nodev,noexec,relatime)
等價於使用--tmpfs:
[root@app51 ~]# docker run -it --name tmpfs-c2 --tmpfs /app busybox:latest /bin/sh / # mount |grep /app tmpfs on /app type tmpfs (rw,nosuid,nodev,noexec,relatime) / #
查看掛載卷:
[root@app51 ~]# docker inspect tmpfs-c1 "Mounts": [ { "Type": "tmpfs", "Source": "", "Destination": "/app", "Mode": "", "RW": true, "Propagation": "" } ],
注意--mount選項還支持指定掛載目錄的大小和權限,選項如下:
| tmpfs-size | 設置tmpfs類型卷的大小,默認無限制(即由宿主機內存決定) |
| tmpfs-mode | 設置tmpfs類型卷掛載的目錄權限,如1770。默認1777 |
指定一個大小為50m,目錄選項為1770類似為tmpfs的存儲卷:
[root@app51 ~]# docker run -it --name tmpfs-c3 --mount type=tmpfs,dst=/data/tmp,tmpfs-mode=1770,tmpfs-size=50m busybox:latest /bin/sh / # / # / # mo modinfo modprobe more mount mountpoint / # mount |grep /data/tmp tmpfs on /data/tmp type tmpfs (rw,nosuid,nodev,noexec,relatime,size=51200k,mode=1770) / # ls /data/ -l total 0 drwxrwx--T 2 root root 40 Mar 1 01:47 tmp
查看其存儲卷信息:
[root@app51 ~]# docker inspect tmpfs-c3 "Mounts": [ { "Type": "tmpfs", "Source": "", "Destination": "/data/tmp", "Mode": "", "RW": true, "Propagation": "" } ],
使用容器數據卷
除了以上數據卷外,還可以直接使用容器中已經掛載的數據卷,使用--volumes-from指定,此時兩個容器的數據卷是共享的。從本質上來講,這兩數據卷共同掛載了宿主機上的同一個目錄。
示例:創建一個容器share-c1掛載當前目錄(確保不要退出)
[root@app51 ~]# docker run -it --name share-c1 -v $(pwd):/data busybox:latest /bin/sh / # ls /data/ Dockerfile a.txt anaconda-ks.cfg backup.tar dr.sh nat.sh nginx-bus.tar.gz nginx.tar / #
在運行一個容器掛載share-c1的卷:
[root@app51 ~]# docker run -it --name share-c2 --volumes-from share-c1 busybox:latest /bin/sh / # ls /data/ Dockerfile a.txt anaconda-ks.cfg backup.tar dr.sh nat.sh nginx-bus.tar.gz nginx.tar / #
存儲卷管理
docker存儲卷管理通過docker volume命令組實現,v18.09的命令集合如下:

1.創建存儲卷
docker volume create [OPTIONS] [VOLUME_NAME]
通常這樣創建的卷會保存在宿主機目錄/var/lib/docker/volumes/VOLUME_NAME/_data如果不指名 VOLUME則會創建匿名卷,方式等同於在docker run -v不指定宿主機目錄。
常用選項:
-o, --opt :指定存儲卷掛載選項。常用選項如下:
- type: 掛載文件系統類型,可以是tmpfs、brtfs、甚至是nfs。
- device:掛載的設備,
- o:mount命令掛載選項,其選項可參考這里
示例一:創建一個普通的卷名稱為test-vol-1。
[root@app51 test-vol-1]# docker volume create test-vol-1 test-vol-1 [root@app51 test-vol-1]# ls /var/ adm/ crash/ empty/ gopher/ lib/ lock/ mail/ opt/ run/ tmp/ yp/ cache/ db/ games/ kerberos/ local/ log/ nis/ preserve/ spool/ .updated [root@app51 test-vol-1]# ls /var/lib/docker/volumes/test-vol-1/ -l 總用量 0 drwxr-xr-x 2 root root 6 3月 1 11:08 _data [root@app51 test-vol-1]#
示例二:創建一個tmpfs類型的存儲卷,名稱為test-vol-2
[root@app51 test-vol-1]# docker volume create --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 test-vol-2 test-vol-2 ###掛載test-vol-2 [root@app51 test-vol-1]# docker run -it --name bs-c10 -v test-vol-2:/data busybox:latest /bin/sh / # mount |grep /data tmpfs on /data type tmpfs (rw,relatime,size=102400k,uid=1000) / #
示例三:創建一個nfs類型的存儲卷,服務器地址為10.1.210.52,權限讀寫,目錄為/data/tmp,名稱為test-vol-3
[root@app51 test-vol-1]# docker volume create --opt type=nfs --opt o=addr=10.1.210.52,rw --opt device=:/data/tmp test-vol-3 test-vol-3
需要注意的是:創建的卷即使創建成功了但是掛載的時候很可能出錯,docker不會在創建卷時候檢查掛載選項是否符合要求。
2.查看存儲卷詳情
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
常用選項:
-f, --format :輸出格式,基於go模版
示例:
[root@app51 ~]# docker inspect test-vol-1 [ { "CreatedAt": "2019-03-01T11:08:00+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/test-vol-1/_data", "Name": "test-vol-1", "Options": {}, "Scope": "local" } ]
使用-f:.代表以根開頭,Name是一級字段。
[root@app51 ~]# docker inspect test-vol-1 -f {{.Name}} test-vol-1 [root@app51 ~]#
3.查看所有存儲卷
docker volume ls [OPTIONS]
常用選項:
-f, --filter 過濾具體存儲卷
示例:
[root@app51 ~]# docker volume ls DRIVER VOLUME NAME local test-vol-1 local test-vol-2 local test-vol-3 [root@app51 ~]#
過濾某個卷:
[root@app51 ~]# docker volume ls -f name=test-vol-1 DRIVER VOLUME NAME local test-vol-1
4.刪除一個或多個卷
docker volume rm [OPTIONS] VOLUME [VOLUME...]
常用選項:
-f, --force 強制刪除存儲卷,即使它還在被使用
[root@app51 ~]# docker volume ls DRIVER VOLUME NAME local test-vol-1 local test-vol-2 local test-vol-3 [root@app51 ~]# docker volume rm test-vol-3 test-vol-3 [root@app51 ~]# docker volume ls DRIVER VOLUME NAME local test-vol-1 local test-vol-2 [root@app51 ~]#
5.移除本地未使用的卷
docker volume prune [OPTIONS]
[root@app51 ~]# docker volume prune WARNING! This will remove all local volumes not used by at least one container. Are you sure you want to continue? [y/N] y Deleted Volumes: test-vol-1 Total reclaimed space: 0B [root@app51 ~]#
數據卷的備份與恢復
數據備份
容器中的數據卷備份有兩種方式,一是你可以直接備份與之對應的宿主機目錄,二則運行一個容器掛載有數據的容器將其備份到與之對應的宿主機目錄。這里演示下第二種數據備份方法。
方法:
1.創建備份容器並掛載需要備份的目錄,同時掛載宿主機目錄進行備份任務。
2.運行備份指令並將備份數據放到掛載的宿主機目錄,以下示例為/backup,將數據備份在來/backup就等於備份在了宿主機的$(pwd)目錄下,也就是當前目錄。
新建一個數據容器並寫入數據:
[root@app51 ~]# docker run -it --name data-c1 -v /data busybox:latest /bin/sh / # cd /data/ /data # touch 1.txt /data # echo "hello world" > index.html /data # ls -l total 4 -rw-r--r-- 1 root root 0 Mar 1 07:40 1.txt -rw-r--r-- 1 root root 12 Mar 1 07:40 index.html /data #
創建備份容器同時掛載兩個目錄進行數據備份:
[root@app51 ~]# docker run --rm --volumes-from data-c1 -v $(pwd):/backup centos tar cvf /backup/backup.tar /data /data/ /data/1.txt /data/index.html tar: Removing leading `/' from member names
查看備份數據:
[root@app51 ~]# ls -l 總用量 220332 -rw-------. 1 root root 1258 1月 16 00:15 anaconda-ks.cfg -rw-r--r-- 1 root root 7 2月 27 10:25 a.txt -rw-r--r-- 1 root root 10240 3月 1 15:42 backup.tar -rw-r--r-- 1 root root 76 2月 27 19:14 Dockerfile -rw-r--r-- 1 root root 578 1月 16 10:41 dr.sh -rw-r--r-- 1 root root 559 1月 16 14:53 nat.sh -rw------- 1 root root 114356736 2月 24 10:56 nginx-bus.tar.gz -rw------- 1 root root 111224320 2月 23 19:18 nginx.tar [root@app51 ~]# tar tvf backup.tar drwxr-xr-x root/root 0 2019-03-01 15:40 data/ -rw-r--r-- root/root 0 2019-03-01 15:40 data/1.txt -rw-r--r-- root/root 12 2019-03-01 15:40 data/index.html
數據恢復
恢復數據的原理與備份類似,也是啟動一個容器共享需要備份的目錄,同時掛載宿主機的備份目錄,最后解壓數據到備份目錄中。為了演示數據恢復,我將上述容器 data-c1中的data目錄中文件全部刪除:
[root@app51 ~]# docker run -it --name data-c1 -v /data busybox:latest /bin/sh / # cd /data/ /data # rm -rf * /data #
創建一個恢復容器:
[root@app51 ~]# docker run --rm --volumes-from data-c1 -v $(pwd):/backup centos bash -c "cd / && tar xvf /backup/backup.tar" data/ data/1.txt data/index.html [root@app51 ~]#
再次查看data-c1容器數據:
/data # rm -rf data /data # /data # /data # /data # /data # ls -l total 4 -rw-r--r-- 1 root root 0 Mar 1 07:40 1.txt -rw-r--r-- 1 root root 12 Mar 1 07:40 index.html /data #
