Docker筆記 - 讓資料遠離Container,使用 Volume、Bind Mount 與 Tmpfs Mount

Albert Hg
alberthg-docker-notes
14 min readFeb 3, 2021
https://hackernoon.com/docker-data-containers-cb250048d162

在上一篇 更改Container的Configuration 的文章中有提到,為了想要讓 Container 保持輕量化,所以會盡可能的不將資料放在 Container 中,同時也因為若將資料放在 Container 中,再重新建立時資料就會被抹除。

為了想要資料能夠持久化 (白話文:存起來不會消失的意思),Docker 提供我們幾種能將資料存放在 Container 外的方法。因此本篇將會針對這個部分進行介紹。

這篇文章將會幫助你了解幾種 Docker 資料持久化的方式,也就是 Volume 與 Mount 的使用。

文章架構

  • 1. 概述
  • 2. --mount 與 -v/--volume
  • 3. 使用 Volume
    - 建立 Volume
    - 綁定 Volume
    - 移除 Volume
  • 4. 使用 Bind Mount
    - 綁定至 Filesystem
  • 5. 使用 Tmpfs Mount
    - 綁定至 Memory Disk
  • 6. 使用綁定的不同時機比較
    - 使用 Volume 的時機
    - 使用 Bind Mount 的時機
    - 使用 Tmpfs Mount 的時機

1. 概述

再一次的老生常談,如果資料放在 Container 內會有甚麼下場:

  1. 資料無法持久化,同時在 Container 內的資料也沒辦法提供其他程序使用
  2. 若資料與 Container 放在一起則耦合過緊,導致搬移資料困難
  3. 若資料必須掛載在 Container 中,則 Container 會需要 storage driver 來管理文件系統,每個文件系統都是一個 Linux Kernel,比起直接把資料存在原生作業系統的文件系統中,來的更浪費效能。

基於種種理由,所以我們要來認識有哪些方法可以讓資料遠離 Container。看到下面這張圖,這代表使用不同的方法,可以將資料存放在不同地方。

例如如果使用 Bind Mount,則會讓資料存在 Filesystem 中。使用 Volume 則會讓資料存在 Filesystem 內的 Docker Area 中。而如果使用 Tmpfs Mount 則會將資料存放在記憶體中。

另外如果想要查看 Container 綁定 Volume 或 Bind Mount 的狀態,則可以使用 docker inspect 檢查,會有一個 "Mount" 的區塊,就是描述了資料綁定的細節。

那麼接下來就來介紹這些方法的細節吧~!

2. --mount 與 -v/ --volume

當在使用 docker create 或是 docker run 的指令時,會有兩個選項可以使用,個別是 --mount 以及 -v (或是 --volume)。

注意,千萬不要誤以為使用 -v 就是用 Volume 的方式或者是 --mount 就是使用 Bind Mount 的方式,不是這樣的!!我們先來看看這兩個在 docker createdocker run 中的說明是甚麼:

-v, --volume list      Bind mount a volume
--mount mount Attach a filesystem mount to the container

但其實是可以用 --mount-v 來綁定資料到 Volume,也可以用 --mount-v 來綁定資料到 Filesystem。既然都可以,那為什麼要分兩種呢?

這是因為 --mount 其實出現的比較早,但他設定綁定資料的方式比較完整卻麻煩,因此在後續又出現了 -v 的選項來簡化綁定的設定過程。

3. 使用 Volume

使用 Volume,其實就是讓 Docker 幫我們管理資料的部分,Docker 有一個空間專門放持久化的資料,而這個空間就叫做 Volume。

- 建立 Volume

我們可以使用下面的語法來建立 Volume 空間:

$ docker volume create [OPTIONS] [VOLUME]

能夠使用的選項有:

-d, --driver string   Specify volume driver name (default "local")
--label list Set metadata for a volume
-o, --opt map Set driver specific options (default map[])

例如你可以這樣做:

docker volume create my-vol

這樣 Docker 就會建立一個 my-vol 的資料夾在 Docker VM 中,路徑如下,裏頭的 _data 會是一個空的資料夾:

/var/lib/docker/volumes/my-vol/_data

接著在 docker create 或是 docker run 時就可以透過 --mount-v 將 Container 綁定至 Volume 了。

- 綁定 Volume

我們以 httpd 的 Image 所建立的 Container 為例。

使用 -v
$ docker run -d --name my-http -v my-vol:/usr/local/apache2 -p 8080:80 httpd
使用 --mount
$ docker run -d --name my-http --mount source=my-vol,target=/usr/local/apache2 -p 8080:80 httpd

特別注意的是 :/usr/local/apache2 這一段,代表的是 Container 的路徑,也就是將 Container 的 :/usr/local/apache2 路徑掛載在 Volume 上。而如果你在掛載的同時,設定了一個不存在的 Volume,則 Docker 會自動幫我們新增所設定的 Volume Name。

以下是示範:

  1. 進入 Docker VM,並移動至 Volume 路徑,檢查 Volume 路徑底下為空
  2. 建立一個 Container,並且綁定至 Volume
  3. 檢查被綁定後的 Volume,在 Docker VM 中多了 Container 所需的資料
    (等等說明 Bind Mount 的時候,會發現 Bind Mount 不會自動加上 Container 所需的資料)
  4. 進入到 Container 的 Bash
  5. 檢查 Container 的資料是否與 Volume 的資料相同
  6. 確定 Container 與 Volume 中的 index.html 內容相同
  7. 從 Volume 中修改 index.html 內容
  8. 確定 Container 中的 index.html 一併被修改

這樣就確定已經將 Container 與 Volume 綁訂在一起了,後續如果 Container 被移除了,或者新增了其他的 Container,只要綁定的 Volume 是同一個,就可以共用資料,只要不移除 Volume,就可以保持資料的持久性。

如果使用 docker inspect my-http 查看 Container 的資訊,則可以看到 Mount 的片段內容如下:

"Mounts": [
{
"Type": "volume",
"Name": "my-vol",
"Source": "/var/lib/docker/volumes/my-vol/_data",
"Destination": "/usr/local/apache2",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],

- 移除 Volume

$ docker volume rm [OPTIONS] VOLUME [VOLUME...]

如果要刪除,要先確認沒有 Container 正在使用要刪除的 Volume,否則會出現這樣的錯誤:

Remove one or more volumes. You cannot remove a volume that is in use by a container.

更多關於 Volume 的使用可以參考官網提供的說明:

4. 使用 Bind Mount

使用 Bind Mount 的方式與使用 Volume 的方式其實差不多,差別就在於使用 Volume 的話是將資料綁定於 Docker VM 的 Volume 路徑資料中。而若是使用 Bind Mount 的話,則是綁訂在 Filesystem 中。

- 綁定至 Filesystem

一樣以 httpd 的 Image 所建立的 Container 為例。

使用 -v
$ docker run -d --name my-http -v D:\DockerMountTest\my-http:/usr/local/apache2/htdocs -p 8080:80 httpd
使用 --mount
$ docker run -d --name my-http --mount type=bind,source=D:\DockerMountTest\my-http,target=/usr/local/apache2/htdocs -p 8080:80 httpd

這裡需要別注意的是如果使用 --mount ,則一定要設定綁定的形式,也就是 type=bind (順帶一提,type 可以是 bindvolume、或tmpfs,預設值為 volume)。

如果對比綁定 Volume 的部分,則會發現使用 Bind Mount 只是將指定的 Volume 改為指定的路徑而已。另外就是如果所指定的路徑不存在時,則該路徑會被自動建立,以及在使用 Bind Mount 時,Docker 並不會自動加上 Container 所需的資料 (可以往上參考 Volume 的部分)。

以下是示範:

  1. 檢查將要指定的 Filesystem 路徑底下為空
  2. 建立 Container,並 Bind Mount 至指定的資料夾中
  3. 檢查指定的 Filesystem 路徑是否有被自動建立出 (有!)
  4. 移動至指定的 Filesystem 路徑
  5. 檢查指定的 Filesystem 路徑是否有 Container 所需的內容 (沒有!所以當打開網頁的時候,只會顯示 Index of/)
  6. 使用 vim 建立 index.html
  7. 檢查 index.html 是否有被新增於指定的 Filesystem 路徑 (有!)
  8. 印出 index.html 的內容,並打開網頁檢查是否一致 (是!)

如果使用 docker inspect my-http 查看 Container 的資訊,則可以看到 Mount 的片段內容如下:

"Mounts": [
{
"Type": "bind",
"Source": "D:\\DockerMountTest\\my-http",
"Destination": "/usr/local/apache2/htdocs",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],

更多關於 Bind Mount 的使用可以參考官網提供的說明:

5. 使用 Tmpfs Mount

Tmpfs,全名 Temporary File System,是在 Linux 暫存檔儲存空間的常見名稱,通常以掛載檔案系統方式實現。他可以將資料儲存在記憶體中而不是存在硬碟內,所以只要一重新開機,資料則會被抹除。

Tmpfs 如其名,如果使用 Tmpfs Mount 則資料會存在於記憶體上,在重啟 Container 的時候就會 Reset 資料。

- 綁定至 Memory Disk

一樣以 httpd 的 Image 所建立的 Container 為例。

特別注意的是,使用 Tmpfs Mount 並不是使用 -v 的選項,而是使用 --tmpfs--tmpfs 就如同 -v一樣簡化了使用 --mount 時所需的設定。

使用 --tmpfs
$ docker run -d --name my-http --tmpfs /usr/local/apache2/htdocs -p 8080:80 httpd
使用 --mount
$ docker run -d --name my-http --mount type=tmpfs,destination=/usr/local/apache2/htdocs -p 8080:80 httpd

以下是示範:

  1. 建立 Container,使用 Tmpfs Mount 使指定路徑掛載於記憶體中
  2. 檢查 Container 掛載於記憶體中,是否有 Container 所需的資料,結果顯示 htdocs 中沒有任何內容,同時若造訪網頁則顯示 Index of/ 的內容,如圖 A
  3. 將掛載於記憶體中的指定路徑內加入 index.html
  4. 檢查是否有正常將 index.html 加入於 htdocs 中,若有,再次造訪網頁則可以顯示內容,如圖 B
  5. 重新啟動 Container
  6. 再次檢查容器中的 htdocs 路徑內,是否資料被清空,若是,在次造訪網頁則會顯示 Index of/ 的內容,如圖 C

更多關於 Tmpfs Mount 的使用可以參考官網提供的說明:

6. 使用綁定的不同時機比較

既然 Docker 提供了這麼多的方式讓我們儲存資料,那麼我們應該在甚麼情況下使用哪一種方式來儲存呢?

- 使用 Volume 的時機

  • 想要在多個 Container 中共用資料的時候
  • 在無法確保存放資料路徑或結構的時候
  • 當 Docker 不在本機端而是在雲端或遠端的時候
  • 當有需要資料的備份、還原、轉移的時候
  • 當資料有大量 I/O 的情況,Docker 建議你可以把資料放在 Docker VM 內,會有更好的性能表現
  • 當你的應用程式需要完整且原生的 File System 的時候

- 使用 Bind Mount 的時機

  • 想要將 Config 設定檔同時分享給 Container 與本機端的時候
  • 想要同時分享程式碼或其他來源文件給 Container 與本機端的時候
  • 當非常確定所綁定的路徑底下,其資料夾與結構等等都非常確定且保持一致不會改變的時候

- 使用 Tmpfs Mount 的時機

  • 不想讓資料被永久儲存的時候
  • 需要每次重啟都有乾淨的環境時
  • 當想要讀寫性能非常好時,因為它掛載的空間是在記憶體上

文末

Docker 不建議我們將資料放在 Container 中,同時,Docker 也提出了幾種方式來進行資料的儲存,讓資料與 Container 分離。

因此本篇介紹了 Docker 所提供儲存資料的方法,並在介紹的過程中逐一示範了使用的過程,希望可以幫助到還不清楚 Volume、Bind Mount 與 Tmpfs Mount 還不清楚的你完整的了解他。

前往

上一篇

--

--

Albert Hg
alberthg-docker-notes

I am a programmer but love other things. I am a nobody but keep myself going. I am a person who wishes to reach the heaven but lost the wings.