Docker使用devicemapper存儲驅動

Device Mapper 介紹

Device Mapper 是 Linux2.6 內核中支持邏輯卷管理的通用設備映射機制,它爲實現用於存儲資源管理的塊設備驅動提供了一個高度模塊化的內核架構。整個 device mapper 機制由兩部分組成:

  • 內核部分:主要提供完成存儲策略所需要的機制
  • 用戶空間部分:device mapper 庫以及它提供的 dmsetup 工具

內核部分包含三個重要的對象概念,Mapped Device、Mapping Table、Target device。

  • Mapped Device:是一個邏輯抽象,可以理解成爲內核向外提供的邏輯設備,它通過Mapping Table描述的映射關係和 Target Device 建立映射;

  • Mapping Table:存有 Mapped Device 邏輯的起始地址、範圍、和表示在 Target Device 所在物理設備的地址偏移量以及Target 類型等信息;

  • Target device:表示的是 Mapped Device 所映射的物理空間段,對 Mapped Device 所表示的邏輯設備來說,就是該邏輯設備映射到的一個物理設備;

Device Mapper在內核中通過一個一個模塊化的 Target Driver 插件實現對 IO 請求的過濾或者重新定向等工作,當前已經實現的插件包括軟 Raid、加密、多路徑、鏡像、快照等,在這諸多“插件”中,有一個東西叫Thin Provisioning Snapshot,這是Docker使用Device Mapper中最重要的模塊,稱爲devicemapper存儲驅動,它利用Device Mapper框架的精簡置備和快照功能來管理鏡像和容器。

Thin Provisioning Snapshot 簡介

先說一下 Thin Provisioning 技術,這個技術是虛擬化技術中的一種,實現對存儲空間的”超賣“能力。

而Docker使用了Thin Provisioning的Snapshot的技術,在 docker 啓動時,會在精簡池(Thin Pool)中創建一個具有文件系統的 Base 設備,每一個新鏡像(和鏡像數據層)是這個 base 設備的一個快照,而容器數據層又是從其鏡像創建的快照。

快照是寫時複製(CoW)策略的實現,這意味着給定的文件或目錄只有在容器被修改或刪除時纔會被複制到容器的可寫層。

配置 direct-lvm 模式用於生產環境

docker默認安裝時,devicemapper存儲驅動程序配置的是loop-lvm模式,該模式使用兩個稀疏文件作爲迴環設備,來存儲鏡像和容器的數據和元數據:

/var/lib/docker/devicemapper/devicemapper/data
/var/lib/docker/devicemapper/devicemapper/metadata

由於迴環設備速度慢且資源密集,生產環境建議使用direct-lvm 模式。

做以下步驟(轉自)前,請先停止docker。

1.由於使用的是虛擬機,先創建個新的分區(或其他塊設備):
$ fdisk /dev/sda

按提示創建一個新的分區: /dev/sda4

2.通過pvcreate命令在 /dev/sda4塊設備上創建物理卷pv:
$ pvcreate /dev/sda4
  Physical volume "/dev/sda4" successfully created.
3.通過 vgcreate 命令在同一個設備上創建名爲 docker的卷組vg:
$ vgcreate docker /dev/sda4
  Volume group "docker" successfully created
4.通過 lvcreate 命令創建兩個名爲 thinpool 和 thinpoolmeta 的邏輯卷lv:

最後一個參數指定可用空間的大小,以便在空間不足時自動擴展數據或元數據。這些是推薦值。

$ lvcreate --wipesignatures y -n thinpool docker -l 95%VG
  Logical volume "thinpool" created.
$ lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
  Logical volume "thinpoolmeta" created.
5.通過 lvconvert 命令把thinpool數據卷和thinpoolmeta元數據卷換爲精簡池(Thin Pool):
$ lvconvert -y \
--zero n \
-c 512K \
--thinpool docker/thinpool \
--poolmetadata docker/thinpoolmeta

  Thin pool volume with chunk size 512.00 KiB can address at most 126.50 TiB of data.
  WARNING: Converting 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 and docker/thinpoolmeta to thin pool.
6.通過 lvm 配置文件配置精簡池的自動擴展:
$ vi /etc/lvm/profile/docker-thinpool.profile

指定 thin_pool_autoextend_threshold 和 thin_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
}
7.使用 lvchange 命令應用 LVM 配置文件:
$ lvchange --metadataprofile docker-thinpool docker/thinpool
  Logical volume docker/thinpool changed.
8.啓用對主機上邏輯卷的監視:

沒有這一步,即使存在 LVM 配置文件,也不會自動擴展。

$ lvs -o+seg_monitor

  LV       VG     Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Monitor  
  thinpool docker twi-a-t--- <19.00g             0.00   0.03                             monitored
9.如果之前在這個主機上運行過 Docker,或 /var/lib/docker/ 文件已經存在,移除文件以便讓 Docker 使用新的 LVM pool 來存儲鏡像和容器:
$ mkdir /var/lib/docker.bk

$ mv /var/lib/docker/* /var/lib/docker.bk
10.編輯 /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"
 ]
}
11.啓動 Docker:
$ systemctl start docker
12.通過 docker info 命令驗證 Docker 使用了新的配置:
$ docker info

Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.8
 Storage Driver: devicemapper
  Pool Name: docker-thinpool
  Pool Blocksize: 524.3kB
  Base Device Size: 10.74GB
  Backing Filesystem: xfs
  Udev Sync Supported: true
  Data Space Used: 20.45MB
  Data Space Total: 20.4GB
  Data Space Available: 20.38GB
  Metadata Space Used: 61.44kB
  Metadata Space Total: 213.9MB
  Metadata Space Available: 213.8MB
  Thin Pool Minimum Free Space: 2.039GB
......

如果 Docker 配置正確,Pool Name 應該是 docker-thinpool

13.可以使用lsblk命令從操作系統角度查看設備和對應的池:
$ lsblk

NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                         8:0    0   41G  0 disk 
├─sda1                      8:1    0  300M  0 part /boot
├─sda2                      8:2    0    2G  0 part [SWAP]
├─sda3                      8:3    0 17.7G  0 part /
└─sda4                      8:4    0   20G  0 part 
  ├─docker-thinpool_tmeta 253:0    0  204M  0 lvm  
  │ └─docker-thinpool     253:2    0   19G  0 lvm  
  └─docker-thinpool_tdata 253:1    0   19G  0 lvm  
    └─docker-thinpool     253:2    0   19G  0 lvm  
sr0                        11:0    1 1024M  0 rom

dmsetup 工具

命令參考:dmsetup - Unix, Linux Command

常用參數:

  • dmsetup info [device_name] : 輸出所有目前配置的 Device Mapper 設備信息
  • dmsetup ls : 命令列出映射的設備的設備名稱列表
  • dmsetup status [device_name] : 輸出結果是所有目前配置的設備映射器設備信息
  • dmsetup message device_name sector message : 給設備發送消息
  • dmsetup create device_name --table "0 20971520 thin 253:3 185" : 創建dm設備
  • dmsetup remove device_name : 移除dm設備

dmsetup 工具的使用

查看運行容器、鏡像的device信息

獲取容器的DeviceName:

$ docker inspect ba3ee5be798c | grep DeviceName
"DeviceName": "docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4",

其中docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4即爲dm設備的名字。

查看Mapping Table:

$ dmsetup table | grep docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4
docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4: 0 20971520 thin 253:3 163

dmsetup table  docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4
0 20971520 thin 253:3 163

其中0 20971520 thin 253:3 163的解釋爲:

logical_start_sector  num_sectors  target_type  target_args
開始扇區             	 扇區數      	設備類型      設備參數
0					   20971520	     thin		253:3 163

20971520 爲扇區數,一個扇區大小爲512kb,總共爲10g
即:20971520個扇區 = 20971520*512kb = 10,737,418,240kb = 10 * 2^30 kb = 10g

取出鏡像的文件

查看鏡像的Device信息

$ docker inspect centos | grep Device
"DeviceId": "13",
"DeviceName": "docker-8:3-36654382-89b4c8a4c8d56fde69622bc6e8df5f402eebf4b0f026966b56c65de7cd4517c0",
"DeviceSize": "10737418240"

使用dmsetup ls命令查看docker-thinpool設備的主設備號和次設備號

$ dmsetup ls
centos-dm	(253:4)
docker-thinpool_tdata	(253:1)
docker-thinpool_tmeta	(253:0)
docker-thinpool	(253:2)

得到主設備號和次設備號爲253:2

生成Mapping Table:0 20971520 thin 253:2 13

  • 0 : 開始扇區
  • 20971520 : 刪除數,由DeviceSize除以每個扇區的大小得到,即 10737418240/512 = 20971520
  • thin : 設備類型
  • 253:2 13 : 設備參數,由 [主設備號]:[次設備號] [DeviceId] 組成

創建dm設備:
dmsetup create centos-dm --table "0 20971520 thin 253:2 13"

再次使用dmsetup ls命令,發現新增的名爲centos-dm的dm設備:

$ dmsetup ls
centos-dm	(253:4)
docker-thinpool_tdata	(253:1)
docker-thinpool_tmeta	(253:0)
docker-thinpool	(253:2)

查看/dev/mapper目錄,發現新增了1個鏈接文件,鏈接到dm-4設備

$ ll /dev/mapper
lrwxrwxrwx. 1 root root       7 Apr 26 02:55 centos-dm -> ../dm-4

把dm-4設備掛載出來

$ mount /dev/dm-4 /tmp/test

查看掛載:

$ mount | grep centos-dm
/dev/mapper/centos-dm on /tmp/test type xfs (rw,relatime,seclabel,attr2,inode64,sunit=1024,swidth=1024,noquota)

查看鏡像文件:

$ ll /tmp/test
total 8
-rw-------.  1 root root   64 Apr 23 01:05 id
drwxr-xr-x. 14 root root 4096 Apr 23 01:05 rootfs

rootfs目錄中即爲鏡像裏的文件:

$ ll /tmp/test/rootfs/
lrwxrwxrwx.  1 root root     7 Apr  6  2017 bin -> usr/bin
drwxr-xr-x. 47 root root  4096 Apr  6  2017 etc
drwxr-xr-x.  2 root root     6 Nov  5  2016 home
lrwxrwxrwx.  1 root root     7 Apr  6  2017 lib -> usr/lib
lrwxrwxrwx.  1 root root     9 Apr  6  2017 lib64 -> usr/lib64
drwx------.  2 root root     6 Apr  6  2017 lost+found
drwxr-xr-x.  2 root root     6 Nov  5  2016 media
drwxr-xr-x.  2 root root     6 Nov  5  2016 mnt
取出運行中/停掉的容器中的內容

使用docker inspect命令查看容器的device信息:

$ docker inspect {containerId} | grep Device
"DeviceId": "21",
"DeviceName": "docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c",
"DeviceSize": "10737418240"

之後的步驟與取出鏡像的文件的方法相同。

給運行中的容器進行快照

使用docker inspect命令查看容器的DeviceName和DeviceId:

$ docker inspect {containerId} | grep Device
"DeviceId": "21",
"DeviceName": "docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c",
"DeviceSize": "10737418240"

向dm設備發送create_snap的消息:

dmsetup message /dev/mapper/docker-thinpool 0 "create_snap 22 21"

其中:

  • 21 : 爲容器的DeviceId
  • 22 : 爲自定的目標DeviceId

使用dmsetup create命令創建dm設備:

$ dmsetup create dockersnap --table "0 20971520 thin /dev/mapper/docker-thinpool 22"

使用dmsetup ls命令,發現新增的名爲dockersnap的dm設備:

$ dmsetup ls
centos-dm	(253:4)
docker-thinpool_tdata	(253:1)
docker-thinpool_tmeta	(253:0)
docker-thinpool	(253:2)
docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c	(253:3)
dockersnap	(253:5)

接下來即可使用之前的步驟mount出來。

devicemapper存儲驅動下統計容器使用量

由於容器啓動後會對鏡像進行一次快照,並mount到一個掛載點(在/var/lib/docker/devicemapper/mnt目錄中),可以考慮使用df命令結果裏的Used字段:

$ df -hT
Filesystem            Type      Size  Used Avail Use% Mounted on
/dev/sda3             xfs        18G  4.5G   14G  26% /
devtmpfs              devtmpfs  1.9G     0  1.9G   0% /dev
tmpfs                 tmpfs     1.9G     0  1.9G   0% /dev/shm
tmpfs                 tmpfs     1.9G  9.1M  1.9G   1% /run
tmpfs                 tmpfs     1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/sda1             xfs       297M  144M  154M  49% /boot
tmpfs                 tmpfs     378M     0  378M   0% /run/user/0
/dev/dm-3             xfs        10G   57M   10G   1% /var/lib/docker/devicemapper/mnt/804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c

可以看到/dev/dm-3對應的掛載點/var/lib/docker/devicemapper/mnt/804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c,其Used值爲57M。

掛載點路徑中有一串很長的hash串,這個串與DeviceName中hash串相對應:

$ docker inspect 17a65165d9b6 | grep DeviceName
"DeviceName": "docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c",

由於格式化後的xfs文件系統自身的metadata也會佔用一定空間,所以這個Used值往往比mount出的目錄要大(使用du命令進行統計):

$ cd \
/var/lib/docker/devicemapper/mnt/804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c
$ du -sh *
4.0K	id
24M	rootfs

可見mount出的目錄的總大小爲24M,並不與Used值相同。

當然,這個差異也與dfdu命令的統計方法有關。

注意:在啓動容器時使用-v參數掛載出來的目錄或文件,都不包含在dfdu命令的統計結果中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章