iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 21
0
Cloud Native

30 天準備 LPI DevOps Tools Engineer 證照系列 第 21

[Day 21] Docker (7)

昨天看了 Docker 的網路設定,今天來看一下資料管理,也就是如何利用 volume 來留存資料。

應用程式資料管理

以預設而言,所有在容器中建立的檔案都儲存在容器的可寫層上,這表示:

  1. 當容器不再執行時,資料無法被留存下來;當另一個行程需要,也很難將資料由容器取出。
  2. 容器的可寫層和執行容器的主機是緊密耦合的,無法輕易地搬移資料。
  3. 寫入容器的可寫層需要儲存驅動器 (storage driver) 來管理檔案系統 (filesystem)。儲存驅動器使用

Linux 核心提供了統一 (union) 的檔案系統。和使用直接寫進主機檔案系統的資料卷宗 (data volume) 比起來,這個額外的抽象化降低了效能。
要將容器中的檔案留存在主機上,Docker 有兩種作法:卷宗 (volume) 和繫結掛載 (bind mount),在 Linux 作業系統上的 Docker 還可使用 tmpfs mount。這三種方式的差異可用下圖表示:
https://docs.docker.com/storage/images/types-of-mounts.png
(圖片出處 https://docs.docker.com/storage/images/types-of-mounts.png)

  1. Volume 存放在主機檔案系統中由 Docker 管理的地方,在 Linux 作業系統是 /var/lib/docker/volumes/ 此路徑。非 Docker 的行程不應該修改檔案系統中的這一部分。要在 Docker 中留存資料,volumes 是最好的方法。
  2. Bind mount 可存放在主機檔案系統中的任何地方,非 Docker 行程或 Docker 容器可隨時修改。
  3. tmpfs mount 只存放在主機的記憶體中,不會寫入主機的檔案系統。

以下針對這三種方式作進一步的說明。

Volume

volume 是由 Docker 建立與管理的,可用 docker volume create 指令直接建立,或者在建立容器或服務時一併建立。volume 建立時存放在主機的目錄中,將 volume 掛載至容器中,就是掛載這個目錄。一個 volume 可同時掛載至多個容器中,即使沒有運行中的容器使用此 volume,它對 Docker 還是可用的,不會被自動刪除。volume 可以是具名或匿名 (anonymous) 的,Docker 會給匿名 volume 一個隨機的名字,在同一個 Docker 主機中不會重覆。接下來是操作的部分:
和 volume 相關的命令為 docker volume

建立一個 volume

$ docker volume create my-vol

create 之後如果不加參數,會建立一個匿名 volume,由 Docker 給予此 volume 一個隨機的名字。

列出 volume

$ docker volume
DRIVER              VOLUME NAME
local               cf1e8907598ee3cad807833db448cf11a1c8cbbb190dbf7de1962ef96cb10707
local               my-vol

前者是匿名 volume,後者是具名 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"
    }
]

移除 volume

$ 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

使用 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

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 ComposeDocker Swarm 作個最後的補充,Docker 部分就結束啦。


上一篇
[Day 20] Docker (6)
下一篇
[Day 22] Docker (8)
系列文
30 天準備 LPI DevOps Tools Engineer 證照30

尚未有邦友留言

立即登入留言