昨天看了 Docker 的網路設定,今天來看一下資料管理,也就是如何利用 volume 來留存資料。
以預設而言,所有在容器中建立的檔案都儲存在容器的可寫層上,這表示:
Linux 核心提供了統一 (union) 的檔案系統。和使用直接寫進主機檔案系統的資料卷宗 (data volume) 比起來,這個額外的抽象化降低了效能。
要將容器中的檔案留存在主機上,Docker 有兩種作法:卷宗 (volume
) 和繫結掛載 (bind mount
),在 Linux 作業系統上的 Docker 還可使用 tmpfs mount
。這三種方式的差異可用下圖表示:
(圖片出處 https://docs.docker.com/storage/images/types-of-mounts.png)
/var/lib/docker/volumes/
此路徑。非 Docker 的行程不應該修改檔案系統中的這一部分。要在 Docker 中留存資料,volumes 是最好的方法。Bind mount
可存放在主機檔案系統中的任何地方,非 Docker 行程或 Docker 容器可隨時修改。tmpfs mount
只存放在主機的記憶體中,不會寫入主機的檔案系統。以下針對這三種方式作進一步的說明。
volume 是由 Docker 建立與管理的,可用 docker volume create
指令直接建立,或者在建立容器或服務時一併建立。volume 建立時存放在主機的目錄中,將 volume 掛載至容器中,就是掛載這個目錄。一個 volume 可同時掛載至多個容器中,即使沒有運行中的容器使用此 volume,它對 Docker 還是可用的,不會被自動刪除。volume 可以是具名或匿名 (anonymous) 的,Docker 會給匿名 volume 一個隨機的名字,在同一個 Docker 主機中不會重覆。接下來是操作的部分:
和 volume 相關的命令為 docker volume
$ docker volume create my-vol
create 之後如果不加參數,會建立一個匿名 volume,由 Docker 給予此 volume 一個隨機的名字。
$ docker volume
DRIVER VOLUME NAME
local cf1e8907598ee3cad807833db448cf11a1c8cbbb190dbf7de1962ef96cb10707
local my-vol
前者是匿名 volume,後者是具名 volume
$ docker volume inspect my-vol
[
{
"CreatedAt": "2018-10-26T22:08:35Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
$ docker volume rm my-vol
要在執行容器時掛載 volume,可用 -v
(--volume
) 或 --mount
旗標。以往在容器會使用 --volume
旗標,--mount
則是用於 swarm 服務,不過在 Docker 17.06 後容器也可以使用 --mount
旗標了。一般說來 -v
的參數用法較為簡潔,--mount
較為清楚。若要在 service 使用 volume,就只能用 --mount
掛載。
$ docker run -d --name devtest \
--mount source=myvol2,target=/app \
nginx:latest
以上是 --mount
的用法,請看第二行,--mount
參數採用 name=value
的形式,以逗號隔開,順序不拘。source
為 volume 的名稱,target
則是要掛載到容器中的那個路徑。若 volume 不存在,Docker 會幫忙建立。同樣的指令,改用 -v
旗標會變成
$ docker run -d --name devtest \
-v myvol2:/app \
nginx:latest
-v
的參數以冒號分隔,第一個部分是 volume 名稱,第二個部分是掛載到容器中的那個路徑。
可用 docker inspect devtest
查看 Mount 的部分,以確認 volume 是否有被正確建立及掛載。
volume 在掛載時可指定是否為唯讀,以 --mount
掛載的指定方法為加上 readonly
選項,例如,
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
nginx:latest
以 -v
掛載的話,在參數列最後加上 :ro
,例如:
$ docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html:ro \
nginx:latest
volume 的其他用法,例如使用不同的 driver 作為檔案系統的抽象化,以便使用其他儲存設備如 NFS 或 Amazon S3 等,以及資料備份、回復、遷移等操作,請參考文件 [https://docs.docker.com/storage/volumes/]
(https://docs.docker.com/storage/volumes/)的說明。
使用 bind mount
時,會將位於本機上的指定檔案或目錄讓容器掛載,掛載的方式和 volume 類似。以 --mount
旗標掛載要加上額外的參數,另外本機上的來源參數必須使用絕對路徑。
首先是 --mount
方式,注意加上 type=bind
,$(pwd)
會展開目前所在的路徑。
$ docker run -d -it --name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
nginx:latest
-v
方式的範例如下:
$ docker run -d -it --name devtest \
-v "$(pwd)"/target:/app \
nginx:latest
文件指出 -v
和 --mount
不同之處,在於 -v
可以掛載本機不存在的路徑。若掛載的路徑(目錄或檔案)不存在,-v
會以目錄方式建立該路徑,--mount
會產生錯誤。如果 bind mount
一個非空的目錄,在 container 中它原本的內容會被遮蔽 (obscured)。
tmpfs mount
只能用於在 Linux 中運行的 Docker,只是暫時性地將資料留存於主機的記憶體之中,當容器停止時,tmpfs mount
就會被移除。它通常用來存放機敏性資料,另外也無法在容器中共用。
要掛載 tmpfs mount
可以使用 --tmpfs
或 --mount
兩種旗標,和 volume 的情況類似,原本 --tmpfs
是用於容器,--mount
則是用於 swarm 服務,在 Docker 17.06 後也可以在容器使用 --mount
。掛載時不需指定來源 (source),範例如下:
$ docker run -d -it --name tmptest \
--mount type=tmpfs,destination=/app \
nginx:latest
$ docker run -d -it --name tmptest \
--tmpfs /app \
nginx:latest
今天就到這邊,明天會把 Docker Compose
和 Docker Swarm
作個最後的補充,Docker 部分就結束啦。