使用 Device Mapper 儲存驅動程式(已棄用)

已棄用

Device Mapper 驅動程式 已棄用,並且在 Docker Engine v25.0 中被移除。如果您正在使用 Device Mapper,則必須在升級到 Docker Engine v25.0 之前遷移到受支援的儲存驅動程式。閱讀 Docker 儲存驅動程式 頁面以瞭解受支援的儲存驅動程式。

Device Mapper 是一個基於核心的框架,它為 Linux 上許多高階卷管理技術提供了基礎。Docker 的 devicemapper 儲存驅動程式利用了此框架的精簡配置和快照功能來進行映像和容器管理。本文將 Device Mapper 儲存驅動程式稱為 devicemapper,而將核心框架稱為 *Device Mapper*。

對於支援它的系統,devicemapper 支援包含在 Linux 核心中。但是,需要特定的配置才能將其與 Docker 一起使用。

devicemapper 驅動程式使用專用於 Docker 的塊裝置,並在塊級別而不是檔案級別執行。可以透過將物理儲存新增到 Docker 主機來擴充套件這些裝置,並且它們的效能優於在作業系統 (OS) 級別使用檔案系統。

先決條件

  • devicemapper 在執行在 CentOS、Fedora、SLES 15、Ubuntu、Debian 或 RHEL 上的 Docker Engine - Community 上受支援。
  • devicemapper 需要安裝 lvm2device-mapper-persistent-data 軟體包。
  • 更改儲存驅動程式會使您已建立的任何容器在本地系統上不可訪問。使用 docker save 儲存容器,並將現有映像推送到 Docker Hub 或私有倉庫,以便您不必稍後重新建立它們。

使用 devicemapper 儲存驅動程式配置 Docker

在執行以下步驟之前,您必須首先滿足所有 先決條件

為測試配置 loop-lvm 模式

此配置僅適用於測試。loop-lvm 模式利用“迴環”機制,允許從本地磁碟上的檔案讀寫,就好像它們是實際的物理磁碟或塊裝置一樣。但是,迴環機制的新增以及與 OS 檔案系統層的互動意味著 IO 操作可能很慢且資源密集。迴環裝置的使用還可能引入競爭條件。但是,設定 loop-lvm 模式可以幫助在嘗試啟用 direct-lvm 模式所需的更復雜設定之前識別基本問題(例如缺少使用者空間軟體包、核心驅動程式等)。因此,loop-lvm 模式應僅用於在配置 direct-lvm 之前執行基本測試。因此,loop-lvm 模式僅應用於在配置 direct-lvm 之前執行基本測試。

對於生產系統,請參閱 為生產環境配置 direct-lvm 模式

  1. 停止 Docker。

    $ sudo systemctl stop docker
    
  2. 編輯 /etc/docker/daemon.json。如果它尚不存在,請建立它。假設檔案為空,請新增以下內容。

    {
      "storage-driver": "devicemapper"
    }

    守護程序參考文件 中檢視每個儲存驅動程式的所有儲存選項

    如果 daemon.json 檔案包含格式錯誤的 JSON,Docker 不會啟動。

  3. 啟動 Docker。

    $ sudo systemctl start docker
    
  4. 驗證守護程序是否正在使用 devicemapper 儲存驅動程式。使用 docker info 命令並查詢 Storage Driver

    $ docker info
    
      Containers: 0
        Running: 0
        Paused: 0
        Stopped: 0
      Images: 0
      Server Version: 17.03.1-ce
      Storage Driver: devicemapper
      Pool Name: docker-202:1-8413957-pool
      Pool Blocksize: 65.54 kB
      Base Device Size: 10.74 GB
      Backing Filesystem: xfs
      Data file: /dev/loop0
      Metadata file: /dev/loop1
      Data Space Used: 11.8 MB
      Data Space Total: 107.4 GB
      Data Space Available: 7.44 GB
      Metadata Space Used: 581.6 KB
      Metadata Space Total: 2.147 GB
      Metadata Space Available: 2.147 GB
      Thin Pool Minimum Free Space: 10.74 GB
      Udev Sync Supported: true
      Deferred Removal Enabled: false
      Deferred Deletion Enabled: false
      Deferred Deleted Device Count: 0
      Data loop file: /var/lib/docker/devicemapper/data
      Metadata loop file: /var/lib/docker/devicemapper/metadata
      Library Version: 1.02.135-RHEL7 (2016-11-16)
    <...>
    

此主機正在 loop-lvm 模式下執行,該模式 **不支援** 生產系統。這由 Data loop fileMetadata loop file 位於 /var/lib/docker/devicemapper 下的檔案這一事實表明。這些是迴環掛載的稀疏檔案。對於生產系統,請參閱 為生產環境配置 direct-lvm 模式

為生產環境配置 direct-lvm 模式

使用 devicemapper 儲存驅動程式的生產主機必須使用 direct-lvm 模式。此模式使用塊裝置建立瘦池。這比使用迴環裝置更快,更有效地使用系統資源,並且塊裝置可以根據需要擴充套件。但是,與 loop-lvm 模式相比,需要更多的設定。

滿足 先決條件 後,請按照以下步驟將 Docker 配置為在 direct-lvm 模式下使用 devicemapper 儲存驅動程式。

警告:更改儲存驅動程式會使您已建立的任何容器在本地系統上不可訪問。使用 docker save 儲存容器,並將現有映像推送到 Docker Hub 或私有倉庫,以便您不必稍後重新建立它們。

允許 Docker 配置 direct-lvm 模式

Docker 可以為您管理塊裝置,簡化 direct-lvm 模式的配置。這僅適用於全新的 Docker 設定。 您只能使用一個塊裝置。如果您需要使用多個塊裝置,請改為 手動配置 direct-lvm 模式。以下新的配置選項可用

選項描述必需?預設值示例
dm.directlvm_device要為 direct-lvm 配置的塊裝置的路徑。dm.directlvm_device="/dev/xvdf"
dm.thinp_percent要從傳入的塊裝置中使用的儲存空間百分比。95dm.thinp_percent=95
dm.thinp_metapercent要從傳入的塊裝置中使用的元資料儲存空間百分比。1dm.thinp_metapercent=1
dm.thinp_autoextend_thresholdlvm 應自動擴充套件瘦池的閾值,以佔總儲存空間的百分比。80dm.thinp_autoextend_threshold=80
dm.thinp_autoextend_percent觸發自動擴充套件時要增加的瘦池百分比。20dm.thinp_autoextend_percent=20
dm.directlvm_device_force是否即使塊裝置上已經存在檔案系統也要格式化該塊裝置。如果設定為 false 並且存在檔案系統,則會記錄錯誤並且檔案系統將保持不變。falsedm.directlvm_device_force=true

編輯 daemon.json 檔案並設定適當的選項,然後重新啟動 Docker 使更改生效。以下 daemon.json 配置設定了表中所有選項。

{
  "storage-driver": "devicemapper",
  "storage-opts": [
    "dm.directlvm_device=/dev/xdf",
    "dm.thinp_percent=95",
    "dm.thinp_metapercent=1",
    "dm.thinp_autoextend_threshold=80",
    "dm.thinp_autoextend_percent=20",
    "dm.directlvm_device_force=false"
  ]
}

守護程序參考文件 中檢視每個儲存驅動程式的所有儲存選項

重新啟動 Docker 使更改生效。Docker 會呼叫命令為您配置塊裝置。

警告:在 Docker 為您準備塊裝置後更改這些值不受支援,會導致錯誤。

您仍然需要 執行定期維護任務

手動配置 direct-lvm 模式

以下步驟建立配置為瘦池的邏輯卷,用作儲存池的備份。它假設您在 /dev/xvdf 處有一個備用塊裝置,具有足夠的空間來完成任務。裝置識別符號和卷大小可能在您的環境中有所不同,您應在整個過程中用自己的值替換它們。該步驟還假設 Docker 守護程序處於 stopped 狀態。

  1. 標識要使用的塊裝置。該裝置位於 /dev/ 下(例如 /dev/xvdf),需要有足夠的空間來儲存主機執行的工作負載的映像和容器層。固態硬碟是理想的選擇。

  2. 停止 Docker。

    $ sudo systemctl stop docker
    
  3. 安裝以下軟體包

    • RHEL / CentOSdevice-mapper-persistent-datalvm2 和所有依賴項

    • Ubuntu / Debian / SLES 15thin-provisioning-toolslvm2 和所有依賴項

  4. 使用 pvcreate 命令在步驟 1 中的塊裝置上建立一個物理卷。將您的裝置名稱替換為 /dev/xvdf

    警告:接下來的幾個步驟具有破壞性,因此請確保您指定了正確的裝置!

    $ sudo pvcreate /dev/xvdf
    
    Physical volume "/dev/xvdf" successfully created.
    
  5. 使用 vgcreate 命令在同一裝置上建立一個 docker 卷組。

    $ sudo vgcreate docker /dev/xvdf
    
    Volume group "docker" successfully created
    
  6. 使用 lvcreate 命令建立兩個名為 thinpoolthinpoolmeta 的邏輯卷。最後一個引數指定允許自動擴充套件資料或元資料(如果空間不足)的空間量,作為臨時權宜之計。以下是推薦的值。

    $ sudo lvcreate --wipesignatures y -n thinpool docker -l 95%VG
    
    Logical volume "thinpool" created.
    
    $ sudo lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
    
    Logical volume "thinpoolmeta" created.
    
  7. 使用 lvconvert 命令將卷轉換為一個精簡池和一個用於精簡池元資料的儲存位置。

    $ sudo lvconvert -y \
    --zero n \
    -c 512K \
    --thinpool docker/thinpool \
    --poolmetadata docker/thinpoolmeta
    
    WARNING: Converting logical volume docker/thinpool and docker/thinpoolmeta to
    thin pool's data and metadata volumes with metadata wiping.
    THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)
    Converted docker/thinpool to thin pool.
    
  8. 透過 lvm 配置檔案配置精簡池的自動擴充套件。

    $ sudo vi /etc/lvm/profile/docker-thinpool.profile
    
  9. 指定 thin_pool_autoextend_thresholdthin_pool_autoextend_percent 值。

    thin_pool_autoextend_threshold 是在 lvm 嘗試自動擴充套件可用空間之前使用的空間百分比(100 = 停用,不推薦)。

    thin_pool_autoextend_percent 是自動擴充套件時新增到裝置的空間量(0 = 停用)。

    下面的示例在磁碟使用率達到 80% 時新增 20% 的容量。

    activation {
      thin_pool_autoextend_threshold=80
      thin_pool_autoextend_percent=20
    }

    儲存檔案。

  10. 使用 lvchange 命令應用 LVM 配置檔案。

    $ sudo lvchange --metadataprofile docker-thinpool docker/thinpool
    
    Logical volume docker/thinpool changed.
    
  11. 確保邏輯卷的監控已啟用。

    $ sudo lvs -o+seg_monitor
    
    LV       VG     Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Monitor
    thinpool docker twi-a-t--- 95.00g             0.00   0.01                             not monitored
    

    如果 Monitor 列中的輸出報告邏輯卷為 not monitored(如上所示),則需要顯式啟用監控。如果沒有此步驟,邏輯卷的自動擴充套件將不會發生,無論應用的配置檔案中設定了什麼。

    $ sudo lvchange --monitor y docker/thinpool
    

    再次執行 sudo lvs -o+seg_monitor 命令,以再次檢查監控是否已啟用。Monitor 列現在應報告邏輯卷正在 monitored

  12. 如果您之前在此主機上執行過 Docker,或者 /var/lib/docker/ 存在,請將其移開,以便 Docker 可以使用新的 LVM 池來儲存映象和容器的內容。

    $ sudo su -
    # mkdir /var/lib/docker.bk
    # mv /var/lib/docker/* /var/lib/docker.bk
    # exit
    

    如果以下任何步驟失敗,您需要還原,您可以刪除 /var/lib/docker 並將其替換為 /var/lib/docker.bk

  13. 編輯 /etc/docker/daemon.json 併為 devicemapper 儲存驅動配置所需的選項。如果該檔案之前為空,則現在應包含以下內容。

    {
        "storage-driver": "devicemapper",
        "storage-opts": [
        "dm.thinpooldev=/dev/mapper/docker-thinpool",
        "dm.use_deferred_removal=true",
        "dm.use_deferred_deletion=true"
        ]
    }
  14. 啟動 Docker。

    systemd:

    $ sudo systemctl start docker
    

    service:

    $ sudo service docker start
    
  15. 使用 docker info 驗證 Docker 是否正在使用新配置。

    $ docker info
    
    Containers: 0
     Running: 0
     Paused: 0
     Stopped: 0
    Images: 0
    Server Version: 17.03.1-ce
    Storage Driver: devicemapper
     Pool Name: docker-thinpool
     Pool Blocksize: 524.3 kB
     Base Device Size: 10.74 GB
     Backing Filesystem: xfs
     Data file:
     Metadata file:
     Data Space Used: 19.92 MB
     Data Space Total: 102 GB
     Data Space Available: 102 GB
     Metadata Space Used: 147.5 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
     Thin Pool Minimum Free Space: 10.2 GB
     Udev Sync Supported: true
     Deferred Removal Enabled: true
     Deferred Deletion Enabled: true
     Deferred Deleted Device Count: 0
     Library Version: 1.02.135-RHEL7 (2016-11-16)
    <...>
    

    如果 Docker 配置正確,Data fileMetadata file 將為空白,池名稱為 docker-thinpool

  16. 驗證配置正確後,您可以刪除包含先前配置的 /var/lib/docker.bk 目錄。

    $ sudo rm -rf /var/lib/docker.bk
    

管理 devicemapper

監控瘦池

不要只依賴 LVM 自動擴充套件。卷組會自動擴充套件,但卷仍然可能填滿。您可以使用 lvslvs -a 監控捲的剩餘空間。考慮使用作業系統級別的監控工具,例如 Nagios。

要檢視 LVM 日誌,可以使用 journalctl

$ sudo journalctl -fu dm-event.service

如果您在精簡池中遇到反覆出現的問題,您可以在 /etc/docker/daemon.json 中將儲存選項 dm.min_free_space 設定為一個值(表示百分比)。例如,將其設定為 10 確保當剩餘空間在 10% 或附近時,操作將以警告失敗。請參閱 引擎守護程序參考中的儲存驅動選項

增加正在執行裝置上的容量

您可以增加執行中的精簡池裝置的容量。如果資料的邏輯卷已滿並且卷組已滿,這將非常有用。具體的操作步驟取決於您是使用 迴圈 LVM 精簡池 還是 直接 LVM 精簡池

調整迴圈 LVM 精簡池的大小

調整 loop-lvm 精簡池大小的最簡單方法是 使用 device_tool 實用程式,但您也可以 使用作業系統實用程式

使用 device_tool 實用程式

moby/moby Github 儲存庫中提供了一個名為 device_tool.go 的社群貢獻指令碼。您可以使用此工具調整 loop-lvm 精簡池的大小,避免上述冗長的過程。此工具不能保證有效,但您應該只在非生產系統上使用 loop-lvm

如果您不想使用 device_tool,您可以 手動調整精簡池的大小

  1. 要使用該工具,請克隆 Github 儲存庫,更改為 contrib/docker-device-tool,並按照 README.md 中的說明編譯該工具。

  2. 使用該工具。以下示例將精簡池的大小調整為 200GB。

    $ ./device_tool resize 200GB
    
使用作業系統實用程式

如果您不想 使用 device-tool 實用程式,您可以使用以下步驟手動調整 loop-lvm 精簡池的大小。

loop-lvm 模式下,迴環裝置用於儲存資料,另一個用於儲存元資料。loop-lvm 模式僅支援測試,因為它具有顯著的效能和穩定性缺陷。

如果您使用的是 loop-lvm 模式,docker info 的輸出將顯示 Data loop fileMetadata loop file 的檔案路徑。

$ docker info |grep 'loop file'

 Data loop file: /var/lib/docker/devicemapper/data
 Metadata loop file: /var/lib/docker/devicemapper/metadata

按照以下步驟增加精簡池的大小。在本例中,精簡池為 100 GB,並增加到 200 GB。

  1. 列出裝置的大小。

    $ sudo ls -lh /var/lib/docker/devicemapper/
    
    total 1175492
    -rw------- 1 root root 100G Mar 30 05:22 data
    -rw------- 1 root root 2.0G Mar 31 11:17 metadata
    
  2. 使用 truncate 命令將 data 檔案的大小增加到 200G,該命令用於增加 **或** 減少檔案的大小。請注意,減小大小是一個破壞性操作。

    $ sudo truncate -s 200G /var/lib/docker/devicemapper/data
    
  3. 驗證檔案大小是否已更改。

    $ sudo ls -lh /var/lib/docker/devicemapper/
    
    total 1.2G
    -rw------- 1 root root 200G Apr 14 08:47 data
    -rw------- 1 root root 2.0G Apr 19 13:27 metadata
    
  4. 迴環檔案已在磁碟上更改,但不在記憶體中。列出記憶體中迴環裝置的大小(以 GB 為單位)。重新載入它,然後再次列出大小。重新載入後,大小為 200 GB。

    $ echo $[ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 ]
    
    100
    
    $ sudo losetup -c /dev/loop0
    
    $ echo $[ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 ]
    
    200
    
  5. 重新載入 devicemapper 精簡池。

    a. 首先獲取池名稱。池名稱是第一個欄位,以 : 分隔。此命令將其提取出來。

    $ sudo dmsetup status | grep ' thin-pool ' | awk -F ': ' {'print $1'}
    docker-8:1-123141-pool
    

    b. 轉儲精簡池的 device mapper 表。

    $ sudo dmsetup table docker-8:1-123141-pool
    0 209715200 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing
    

    c. 使用輸出的第二個欄位計算精簡池的總扇區數。該數字以 512k 扇區表示。一個 100G 檔案有 209715200 個 512k 扇區。如果將其翻倍到 200G,則得到 419430400 個 512k 扇區。

    d. 使用以下三個 dmsetup 命令,使用新的扇區數重新載入精簡池。

    $ sudo dmsetup suspend docker-8:1-123141-pool
    $ sudo dmsetup reload docker-8:1-123141-pool --table '0 419430400 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing'
    $ sudo dmsetup resume docker-8:1-123141-pool
    

調整直接 LVM 精簡池的大小

要擴充套件 direct-lvm 精簡池,您需要首先將新的塊裝置附加到 Docker 主機,並記下核心為其分配的名稱。在本例中,新的塊裝置為 /dev/xvdg

按照以下步驟擴充套件 direct-lvm 精簡池,將您的塊裝置和其他引數替換為適合您情況的引數。

  1. 收集有關卷組的資訊。

    使用 pvdisplay 命令查詢當前由您的精簡池使用的物理塊裝置以及卷組的名稱。

    $ sudo pvdisplay |grep 'VG Name'
    
    PV Name               /dev/xvdf
    VG Name               docker
    

    在以下步驟中,根據需要替換您的塊裝置或卷組名稱。

  2. 使用 vgextend 命令擴展卷組,使用上一步中的 VG Name 以及您 **新的** 塊裝置的名稱。

    $ sudo vgextend docker /dev/xvdg
    
    Physical volume "/dev/xvdg" successfully created.
    Volume group "docker" successfully extended
    
  3. 擴充套件 docker/thinpool 邏輯卷。此命令立即使用卷的 100%,不進行自動擴充套件。要擴充套件元資料精簡池,請使用 docker/thinpool_tmeta

    $ sudo lvextend -l+100%FREE -n docker/thinpool
    
    Size of logical volume docker/thinpool_tdata changed from 95.00 GiB (24319 extents) to 198.00 GiB (50688 extents).
    Logical volume docker/thinpool_tdata successfully resized.
    
  4. 使用 docker info 輸出中的 Data Space Available 欄位驗證新的精簡池大小。如果您擴充套件的是 docker/thinpool_tmeta 邏輯卷,請查詢 Metadata Space Available

    Storage Driver: devicemapper
     Pool Name: docker-thinpool
     Pool Blocksize: 524.3 kB
     Base Device Size: 10.74 GB
     Backing Filesystem: xfs
     Data file:
     Metadata file:
     Data Space Used: 212.3 MB
     Data Space Total: 212.6 GB
     Data Space Available: 212.4 GB
     Metadata Space Used: 286.7 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
    <...>

在重新引導後啟用 devicemapper

如果您重新啟動主機並發現 docker 服務啟動失敗,請查詢錯誤“Non existing device”。您需要使用以下命令重新啟用邏輯卷。

$ sudo lvchange -ay docker/thinpool

devicemapper 儲存驅動程式的工作原理

警告:不要直接操作 /var/lib/docker/ 中的任何檔案或目錄。這些檔案和目錄由 Docker 管理。

使用 lsblk 命令從作業系統的角度檢視裝置及其池。

$ sudo lsblk

NAME                    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda                    202:0    0    8G  0 disk
└─xvda1                 202:1    0    8G  0 part /
xvdf                    202:80   0  100G  0 disk
├─docker-thinpool_tmeta 253:0    0 1020M  0 lvm
│ └─docker-thinpool     253:2    0   95G  0 lvm
└─docker-thinpool_tdata 253:1    0   95G  0 lvm
  └─docker-thinpool     253:2    0   95G  0 lvm

使用 mount 命令檢視 Docker 使用的掛載點。

$ mount |grep devicemapper
/dev/xvda1 on /var/lib/docker/devicemapper type xfs (rw,relatime,seclabel,attr2,inode64,noquota)

當您使用 devicemapper 時,Docker 將映象和層內容儲存在精簡池中,並透過將它們掛載到 /var/lib/docker/devicemapper/ 的子目錄下,將其公開給容器。

磁碟上的映像和容器層

/var/lib/docker/devicemapper/metadata/ 目錄包含有關 Devicemapper 配置本身以及每個存在映象和容器層的元資料。devicemapper 儲存驅動使用快照,這些元資料包含有關這些快照的資訊。這些檔案採用 JSON 格式。

/var/lib/docker/devicemapper/mnt/ 目錄包含每個存在映象和容器層的掛載點。映象層掛載點為空,但容器的掛載點顯示容器的檔案系統,如同從容器內部檢視一樣。

映像分層和共享

devicemapper 儲存驅動使用專用的塊裝置而不是格式化的檔案系統,並在塊級別操作檔案,以便在寫入時複製 (CoW) 操作期間獲得最大效能。

快照

devicemapper 的另一個功能是它使用快照(有時也稱為 *精簡裝置* 或 *虛擬裝置*),這些快照將每個層中引入的差異儲存為非常小的、輕量級的精簡池。快照提供許多好處。

  • 容器之間共享的層僅在磁碟上儲存一次,除非它們是可寫的。例如,如果您有 10 個不同的映象,它們都基於 alpine,則 alpine 映象及其所有父映象在磁碟上僅儲存一次。

  • 快照是寫入時複製 (CoW) 策略的實現。這意味著只有當容器修改或刪除給定檔案或目錄時,該檔案或目錄才會被複制到容器的可寫層。

  • 由於 devicemapper 在塊級別執行,因此可寫層中的多個塊可以同時修改。

  • 可以使用標準作業系統級備份實用程式備份快照。只需複製 /var/lib/docker/devicemapper/ 即可。

Devicemapper 工作流程

當您使用 devicemapper 儲存驅動啟動 Docker 時,與映象和容器層相關的所有物件都儲存在 /var/lib/docker/devicemapper/ 中,它由一個或多個塊級裝置支援,這些裝置可以是迴環裝置(僅用於測試)或物理磁碟。

  • *基本裝置* 是最低階的物件。這是精簡池本身。您可以使用 docker info 檢查它。它包含一個檔案系統。這個基本裝置是每個映象和容器層的起點。基本裝置是 Device Mapper 實現細節,而不是 Docker 層。

  • 有關基本裝置和每個映象或容器層的元資料儲存在 /var/lib/docker/devicemapper/metadata/ 中,並採用 JSON 格式。這些層是寫入時複製快照,這意味著它們在與父層發生分歧之前是空的。

  • 每個容器的可寫層都掛載在 /var/lib/docker/devicemapper/mnt/ 中的掛載點上。每個只讀映象層和每個已停止容器都有一個空目錄。

每個映象層都是對下方層的快照。每個映象的最低層是對池中基礎裝置的快照。當你執行一個容器時,它就是基於該容器映象的快照。以下示例展示了一個 Docker 主機,上面執行著兩個容器。第一個是 `ubuntu` 容器,第二個是 `busybox` 容器。

Ubuntu and busybox image layers

容器如何使用 devicemapper 進行讀寫

讀取檔案

使用 `devicemapper` 時,讀操作發生在塊級別。下圖顯示了在一個示例容器中讀取單個塊(`0x44f`)的高階過程。

Reading a block with devicemapper

應用程式在容器中發出對塊 `0x44f` 的讀請求。由於容器是對映象的薄快照,它不包含該塊,但它擁有指向該塊在最近父映象中的位置的指標,並且它從那裡讀取該塊。現在該塊存在於容器的記憶體中。

寫入檔案

**寫入新檔案:** 使用 `devicemapper` 驅動器時,向容器寫入新資料是透過**按需分配**操作完成的。新檔案的每個塊都會在容器的可寫層中分配,並且該塊被寫入那裡。

**更新現有檔案:** 檔案的相關塊從其存在的最接近的層讀取。當容器寫入檔案時,只有修改的塊才會寫入容器的可寫層。

**刪除檔案或目錄:** 當你在容器的可寫層中刪除檔案或目錄時,或者當映象層刪除在其父層中存在的檔案時,`devicemapper` 儲存驅動器會攔截對該檔案或目錄的後續讀取嘗試,並響應該檔案或目錄不存在。

**寫入檔案,然後刪除檔案:** 如果容器寫入檔案,然後刪除檔案,所有這些操作都在容器的可寫層中進行。在這種情況下,如果你使用的是 `direct-lvm`,這些塊會被釋放。如果你使用的是 `loop-lvm`,這些塊可能不會被釋放。這是在生產環境中不使用 `loop-lvm` 的另一個原因。

Device Mapper 和 Docker 效能

  • **按需分配**效能影響:

    `devicemapper` 儲存驅動器使用**按需分配**操作,將薄池中的新塊分配到容器的可寫層中。每個塊大小為 64KB,因此這是寫入所使用的最小空間量。

  • **寫時複製效能影響:** 當容器第一次修改特定塊時,該塊會被寫入容器的可寫層。由於這些寫入發生在塊級別而不是檔案級別,因此效能影響最小化。但是,寫入大量塊仍然會對效能產生負面影響,並且 `devicemapper` 儲存驅動器在這種情況下實際上可能會比其他儲存驅動器表現更差。對於寫入密集型工作負載,你應該使用資料卷,它完全繞過儲存驅動器。

效能最佳實踐

使用 `devicemapper` 儲存驅動器時,請記住以下幾點,以最大限度地提高效能。

  • **使用 `direct-lvm`:** `loop-lvm` 模式效能不佳,不應在生產環境中使用。

  • **使用快速儲存:** 固態硬碟 (SSD) 提供比旋轉磁碟更快的讀寫速度。

  • **記憶體使用情況:** `devicemapper` 使用的記憶體比其他一些儲存驅動器更多。每個啟動的容器會將一個或多個檔案副本載入到記憶體中,具體取決於同時修改的檔案的塊數。由於記憶體壓力,`devicemapper` 儲存驅動器可能不適合在高密度使用情況下某些工作負載。

  • **對寫入密集型工作負載使用卷:** 卷為寫入密集型工作負載提供最佳且最可預測的效能。這是因為它們繞過儲存驅動器,並且不會產生薄配置和寫時複製帶來的任何潛在開銷。卷還有其他優勢,例如允許你在容器之間共享資料,並且即使在沒有執行的容器使用它們時也能持久儲存。

  • **注意:** 使用 `devicemapper` 和 `json-file` 日誌驅動器時,容器生成的日誌檔案仍然儲存在 Docker 的資料根目錄中,預設情況下為 `/var/lib/docker`。如果你的容器生成大量日誌訊息,這可能會導致磁碟使用量增加,或者由於磁碟已滿而無法管理你的系統。你可以配置一個 日誌驅動器,將容器日誌外部儲存。