Docker 基礎知識 - 使用綁定掛載(bind mounts)管理應用程序數據

綁定掛載(bind mounts)在 Docker 的早期就已經出現了。與卷相比,綁定掛載的功能有限。當您使用綁定掛載時,主機上的文件或目錄將掛載到容器中。文件或目錄由其在主機上的完整或相對路徑引用。相反地,當您使用卷時,在主機上 Docker 的存儲目錄中建立一個新目錄,Docker 管理該目錄的內容。html

該文件或目錄不須要已經存在於 Docker 主機上。若是還不存在,則按需建立。綁定掛載的性能很是好,但它們依賴於主機的文件系統,該文件系統具備特定的可用目錄結構。若是您正在開發新的 Docker 應用程序,請考慮改用命名卷。不能使用 Docker CLI 命令直接管理綁定掛載。linux

docker-types-of-mounts-bind

選擇 -v 或者 --mount 標記

最初,-v--volume 標記用於獨立容器,--mount 標記用於集羣服務。可是,從 Docker 17.06 開始,您也能夠將 --mount 用於獨立容器。一般,--mount 標記表達更加明確和冗長。最大的區別是 -v 語法將全部選項組合在一個字段中,而 --mount 語法將選項分離。下面是每一個標記的語法比較。nginx

提示:新用戶推薦使用 --mount 語法,有經驗的用戶可能更熟悉 -v or --volume 語法,可是更鼓勵使用 --mount 語法,由於研究代表它更易於使用。git

  • -v--volume: 由三個字段組成,以冒號(:)分隔。字段必須按照正確的順序排列,且每一個字段的含義不夠直觀明顯。
    • 對於綁定掛載(bind mounts), 第一個字段是主機上文件或目錄的路徑。
    • 第二個字段是容器中文件或目錄掛載的路徑。
    • 第三個字段是可選的,是一個逗號分隔的選項列表,好比 roconsistentdelegatedcachedzZ。這些選項會在本文下面討論。
  • --mount:由多個鍵-值對組成,以逗號分隔,每一個鍵-值對由一個 <key>=<value> 元組組成。--mount 語法比 -v--volume 更冗長,可是鍵的順序並不重要,標記的值也更容易理解。
    • 掛載的類型(type),能夠是 bindvolume 或者 tmpfs。本主題討論綁定掛載(bind mounts),所以類型(type)始終爲綁定掛載(bind)。
    • 掛載的源(source),對於綁定掛載,這是 Docker 守護進程主機上的文件或目錄的路徑。能夠用 source 或者 src 來指定。
    • 目標(destination),將容器中文件或目錄掛載的路徑做爲其值。能夠用 destinationdst 或者 target 來指定。
    • readonly 選項(若是存在),則會將綁定掛載以只讀形式掛載到容器中。
    • bind-propagation 選項(若是存在),則更改綁定傳播。 可能的值是 rprivateprivatersharedsharedrslaveslave 之一。
    • consistency 選項(若是存在), 可能的值是 consistentdelegatedcached 之一。 這個設置只適用於 Docker Desktop for Mac,在其餘平臺上被忽略。
    • --mount 標記不支持用於修改 selinux 標籤的 zZ選項。

下面的示例儘量同時展現 --mount-v 兩種語法,而且先展現 --mountgithub

-v--mount 行爲之間的差別

因爲 -v-volume 標記長期以來一直是 Docker 的一部分,它們的行爲沒法改變。這意味着 -v-mount 之間有一個不一樣的行爲。docker

若是您使用 -v-volume 來綁定掛載 Docker 主機上還不存在的文件或目錄,則 -v 將爲您建立它。它老是做爲目錄建立的。macos

若是使用 --mount 綁定掛載 Docker 主機上還不存在的文件或目錄,Docker 不會自動爲您建立它,而是產生一個錯誤。bash

啓動帶有綁定掛載的容器

考慮這樣一個狀況:您有一個目錄 source,當您構建源代碼時,工件被保存到另外一個目錄 source/target/ 中。您但願工件在容器的 /app/ 目錄可用,並但願每次在開發主機上構建源代碼時,容器能訪問新的構建。使用如下命令將 target/ 目錄綁定掛載到容器的 /app/。在 source 目錄中運行命令。在 Linux 或 macOS 主機上,$(pwd) 子命令擴展到當前工做目錄。app

下面的 --mount-v 示例會產生相同的結果。除非在運行第一個示例以後刪除了 devtest 容器,不然不能同時運行它們。性能

--mount

$ 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

使用 docker inspect devtest 驗證綁定掛載是否被正確建立。查看 Mounts 部分:

"Mounts": [
    {
        "Type": "bind",
        "Source": "/tmp/source/target",
        "Destination": "/app",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
],

這代表掛載是一個 bind 掛載,它顯示了正確的源和目標,也顯示了掛載是可讀寫的,而且傳播設置爲 rprivate

中止容器:

$ docker container stop devtest

$ docker container rm devtest

掛載到容器上的非空目錄

若是您將其綁定掛載到容器上的一個非空目錄中,則該目錄的現有內容會被綁定掛載覆蓋。這多是有益的,例如當您想測試應用程序的新版本而不構建新鏡像時。然而,它也多是使人驚訝的,這種行爲不一樣於 docker volumes

這個例子被設計成極端的,僅僅使用主機上的 /tmp/ 目錄替換容器的 /usr/ 目錄的內容。在大多數狀況下,這將致使容器沒法正常工做。

--mount-v 示例有相同的結果。

--mount

$ docker run -d \
  -it \
  --name broken-container \
  --mount type=bind,source=/tmp,target=/usr \
  nginx:latest

docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".

-v

$ docker run -d \
  -it \
  --name broken-container \
  -v /tmp:/usr \
  nginx:latest

docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".

容器被建立,但沒有啓動。刪除它:

$ docker container rm broken-container

使用只讀綁定掛載

對於一些開發應用程序,容器須要寫入綁定掛載,所以更改將傳播回 Docker 主機。在其餘時候,容器只須要讀訪問。

這個示例修改了上面的示例,可是經過在容器內的掛載點以後的選項列表(默認爲空)中添加 ro,將目錄掛載爲只讀綁定掛載。當有多個選項時,使用逗號分隔它們。

--mount-v 示例有相同的結果。

--mount

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app,readonly \
  nginx:latest

-v

$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app:ro \
  nginx:latest

使用 docker inspect devtest 驗證綁定掛載是否被正確建立。查看 Mounts 部分:

"Mounts": [
    {
        "Type": "bind",
        "Source": "/tmp/source/target",
        "Destination": "/app",
        "Mode": "ro",
        "RW": false,
        "Propagation": "rprivate"
    }
],

中止容器:

$ docker container stop devtest

$ docker container rm devtest

配置綁定傳播

對於綁定掛載和卷,綁定傳播默認都是 rprivate 。只能爲綁定掛載配置,並且只能在 Linux 主機上配置。綁定傳播是一個高級主題,許多用戶從不須要配置它。

綁定傳播是指在給定綁定掛載或命名卷中建立的掛載是否能夠傳播到該掛載的副本。考慮一個掛載點 /mnt,它也掛載在 /tmp 上。傳播設置控制 /tmp/a 上的掛載是否也能夠在 /mnt/a 上使用。每一個傳播設置都有一個遞歸對應點。在遞歸的狀況下,考慮一下 /tmp/a 也被掛載爲 /foo。傳播設置控制 /mnt/a 和/或 /tmp/a 是否存在。

傳播設置 描述
shared 原始掛載的子掛載公開給副本掛載,副本掛載的子掛載也傳播給原始掛載。
slave 相似於共享(shared)掛載,但僅在一個方向上。若是原始掛載公開子掛載,副本掛載能夠看到它。可是,若是副本掛載公開子掛載,則原始掛載沒法看到它。
private 該掛載是私有的。原始掛載的子掛載不公開給副本掛載,副本掛載的子掛載也不公開給原始掛載。
rshared 與 shared 相同,但傳播也擴展到嵌套在任何原始或副本掛載點中的掛載點。
rslave 與 slave 相同,但傳播也擴展到嵌套在任何原始或副本掛載點中的掛載點。
rprivate 默認值。與 private 相同,這意味着原始或副本掛載點中的任何位置的掛載點都不會在任何方向傳播。

當你在掛載點上設置綁定傳播以前,主機文件系統須要已經支持綁定傳播。

有關綁定傳播的更多信息,請參見 Linux 內核共享子樹文檔

下面的示例兩次將 target/ 目錄掛載到容器中,第二次掛載設置了 ro 選項和 rslave 綁定傳播選項。

--mount-v 示例有相同的結果。

--mount

$ 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

-v

$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app \
  -v "$(pwd)"/target:/app2:ro,rslave \
  nginx:latest

如今,若是您建立 /app/foo//app2/foo/ 也存在。

配置 selinux 標籤

若是使用 selinux ,則能夠添加 zZ 選項,以修改掛載到容器中的主機文件或目錄的 selinux 標籤。這會影響主機上的文件或目錄,而且會產生超出 Docker 範圍以外的後果。

  • z 選項表示綁定掛載內容在多個容器之間共享。
  • Z 選項表示綁定掛載內容是私有的、非共享的。

使用這些選項時要格外當心。使用 Z 選項綁定掛載系統目錄(如 /home/usr )會致使您的主機沒法操做,您可能須要從新手動標記主機文件。

重要提示:當對服務使用綁定掛載時,selinux 標籤(:Z:Z) 以及 :ro 將被忽略。詳情請參閱 moby/moby #32579

這個示例設置了 z 選項來指定多個容器能夠共享綁定掛載的內容:

沒法使用 --mount 標記修改 selinux 標籤。

$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app:z \
  nginx:latest

爲 macOS 配置掛載一致性

Docker Desktop for Mac 使用 osxfs 將從 macOS 共享的目錄和文件傳播到 Linux VM。這種傳播使運行在 Docker Desktop for Mac 上的 Docker 容器可使用這些目錄和文件。

默認狀況下,這些共享是徹底一致的,這意味着每次在 macOS 主機上或經過容器中的掛載發生寫操做時,更改都會刷新到磁盤上,以便共享中的全部參與者都擁有徹底一致的視圖。在某些狀況下,徹底一致性會嚴重影響性能。Docker 17.05及更高版本引入了一些選項,在每一個掛載、每一個容器的基礎上調整一致性設置。如下選項可供選擇:

  • consistentdefault: 徹底一致性的默認設置,如上所述。
  • delegated: 容器運行時的掛載視圖是權威的。在容器中所作的更新,在主機上可見以前,可能會有延遲。
  • cached: macOS 主機的掛載視圖是權威的。在主機上所作的更新,在容器中可見以前,可能會有延遲。

這些選項在除 macOS 以外的全部主機操做系統上都被徹底忽略。

--mount-v 示例有相同的結果。

--mount

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,destination=/app,consistency=cached \
  nginx:latest

-v

$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app:cached \
  nginx:latest

做者 : Docker 官網
譯者 : 技術譯民
出品 : 技術譯站
連接 : 英文原文

相關文章
相關標籤/搜索