Docker动态扩容Pool大小与container大小

docker容器默认的空间是10G, Pool 大小默认是100G.

查看 docker 信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
> docker info
Containers: 3
Running: 3
Paused: 0
Stopped: 0
Images: 2
Server Version: 1.12.1
Storage Driver: devicemapper
Pool Name: docker-253:0-117441065-pool
Pool Blocksize: 65.54 kB
Base Device Size: 107.4 GB
Backing Filesystem: xfs
Data file: /dev/loop0
Metadata file: /dev/loop1
Data Space Used: 18.32 GB
Data Space Total: 107.4 GB
Data Space Available: 89.05 GB
Metadata Space Used: 12.45 MB
Metadata Space Total: 2.147 GB
Metadata Space Available: 2.135 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/devicemapper/data
WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.
Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
Library Version: 1.02.107-RHEL7 (2016-06-09)
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: host bridge overlay null
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: seccomp
Kernel Version: 3.10.0-327.28.3.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 6
Total Memory: 7.624 GiB
Name: mobile-quality
ID: NG64:K27K:ASGU:MCBI:NPOZ:Y554:5HME:3INM:UAMI:IIWC:ZQT5:ZKO6
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
Labels:
provider=generic
Insecure Registries:
127.0.0.0/8

Data Space Total: 107.4 GB 这个就是默认的 Pool 大小


调整 container 大小

新 container 的调整

如果想指定默认容器的大小(在启动容器的时候指定),可以在docker配置文件里通过dm.basesize参数指定

直接使用 docker 命令启动服务

1
docker -d --storage-opt dm.basesize=20G

使用 systemctl 命令启动服务

对于使用 systemctl 管理的docker服务, 可以编辑 systemctl 的启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> vim /etc/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
After=network.target

[Service]
Type=notify
ExecStart=/usr/bin/docker daemon -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock --registry-mirror=http://8843165a.m.daocloud.io --storage-driver devicemapper --tl
sverify --tlscacert /etc/docker/ca.pem --tlscert /etc/docker/server.pem --tlskey /etc/docker/server-key.pem --label provider=generic --storage-opt dm.basesize=20G
ExecReload=/bin/kill -s HUP
MountFlags=slave
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Environment=

[Install]
WantedBy=multi-user.target

以上方式适用于新 run 起来的 container, 会获取到新的空间

已存在的 container 的调整

查看所有的虚拟磁盘信息

1
2
3
4
5
6
7
8
9
10
> dmsetup status
docker-253:0-117441065-pool: 0 209715200 thin-pool 39 3039/524288 279539/1638400 - rw discard_passdown queue_if_no_space -
docker-253:0-117441065-bb21427f81836c96a53e7cf0ee97c9e907104ad1ce4d8f2bdade4bbfc0fdd5f5: 0 20971520 thin 17858688 209715199
docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e: 0 20971520 thin 19820928 209715199
docker-253:0-117441065-c57286b3ae5bc1bd675573902d043754aba23349306fd3a52bcd74eed5d144cb: 0 20971520 thin 2968320 209715199
centos-swap: 0 3358720 linear
centos-root: 0 29163520 linear
centos-root: 29163520 71294976 linear
centos-root: 100458496 104849408 linear
centos-root: 205307904 209707008 linear

最上面4条开头写着 docker 的虚拟磁盘就是我们即将操作的对象

其中可以明显的看出, 第一条中带有 pool 的字样, 没错, 这个就是 docker 默认的 pool 大小,现在我们要调整 container 的大小, 暂时不管 pool 的默认配置

其余的三条磁盘信息就是当前宿主机中, 起来的 container 使用的虚拟磁盘, 如果你需要指定其中一个来调整, 那么你需要找到虚拟磁盘和 container name 或 container id 的对应关系, 不要搞错!

对应关系可以使用 docker exec -it xxxx /bin/bash 进入到 container 中使用df -h 命令查看根分区的虚拟磁盘名称
也可以在 linux 中使用 docker inspect xxx 来查看 xxx 容器的详细信息

找到了它们的对应关系之后, 接下来就可以对其调整大小了

找到映射的虚拟磁盘

默认情况下, 所有的虚拟磁盘的映射都在/dev/mapper/

1
2
3
4
5
6
7
8
9
> ls -l
total 0
lrwxrwxrwx 1 root root 7 Dec 7 01:45 centos-root -> ../dm-0
lrwxrwxrwx 1 root root 7 Dec 7 01:45 centos-swap -> ../dm-1
crw------- 1 root root 10, 236 Dec 7 01:45 control
lrwxrwxrwx 1 root root 7 Dec 7 02:20 docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e -> ../dm-3
lrwxrwxrwx 1 root root 7 Dec 7 02:21 docker-253:0-117441065-bb21427f81836c96a53e7cf0ee97c9e907104ad1ce4d8f2bdade4bbfc0fdd5f5 -> ../dm-4
lrwxrwxrwx 1 root root 7 Dec 7 02:30 docker-253:0-117441065-c57286b3ae5bc1bd675573902d043754aba23349306fd3a52bcd74eed5d144cb -> ../dm-5
lrwxrwxrwx 1 root root 7 Dec 7 01:49 docker-253:0-117441065-pool -> ../dm-2

从上面👆的回显也可以看出实际指向的虚拟磁盘文件(是不是有点绕, 这个文件只不过是虚拟磁盘的软连接而已)

接下来我们需要对其进行扩容操作

第一步: 查看指定虚拟磁盘的容量信息

1
2
> dmsetup table docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e
0 20971520 thin 253:2 25

第二步: 计算所需的容量(扇区数量)

假设你想要的容量为 20G

则该值应该为: 20*1024*1024*1024/512 = 41943040

验算: 20G 的值 41943040 = 默认10G 的值 20971520 *2

公式为: x*1024*1024*1024/512

第三步: 挂起虚拟磁盘

1
> dmsetup suspend docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e

没有回显, 没有消息就是好消息😆

第四步: 写入新参数并重新加载进去

1
> dmsetup reload docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e --table '0 41943040 thin 253:2 25'

把上一步计算出来的值, 覆盖到第一步的回显对应的位置中

第五步: 激活挂起的虚拟磁盘

1
> dmsetup resume docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e

如果执行到这一步的时候报错:

1
2
device-mapper: resume ioctl on docker-253:0-1700-pool failed: Invalid argument
Command failed

先不要慌, 稍等片刻, 再重新执行

注意:

由于挂起操作会阻塞住所有的 IO, 为了尽快完成扩容, 我们一般把第三四五步骤用一行命令去执行

1
2
3
> dmsetup suspend docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e \
&& dmsetup reload docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e --table '0 41943040 thin 253:2 25' \
&& dmsetup resume docker-253:0-117441065-17379f89f95efb5bafb234d95e0e0dfe549f7ba48fbed69c0111e2ea39c0106e

第六步: 为磁盘扩容

1
2
3
> mount /dev/dm-3 /mnt
> xfs_growfs /mnt
> umount /mnt

需要先挂载再扩容


调整 pool 大小

调整 pool 大小不同于调整 container 的大小, 需要先对其虚拟文件进行扩容, 再对虚拟磁盘扩容

到这里涉及到了三个概念:

  • 虚拟文件大小 —> 硬盘大小/PV/VG
  • 虚拟硬盘设备 —> LV/file system
  • 软连接 —> alias 别名

虚拟硬盘设备是基于虚拟文件的, 就好像我们使用的 lvm 卷, 虚拟硬盘设备就相当于 lv 或是说就相当于我们正在使用的文件系统; 而 docker 中的虚拟文件就好比我们物理机的硬盘, 或是说 PV 与 VG 的大小

  • 在物理服务器中, 磁盘空间不足的话, 我们可以增加硬盘, 条带化成 PV, 再填入到 VG 池中, 然后分配给对应的 LV, 再对其扩容
  • 在 docker 中, 磁盘空间不足的话(pool 不足的话), 我们可以扩充虚拟文件, 然后让虚拟硬盘设备扩容

查看 pool 文件大小信息

1
2
3
4
> ls -lh /var/lib/docker/devicemapper/devicemapper/
total 244M
-rw-------. 1 root root 100G Dec 8 18:27 data
-rw-------. 1 root root 2.0G Dec 8 18:24 metadata

可以看到 data 是100G 大小, 不要担心他实际占用了100G, 这个是精简配置, 实际用多少就占多少空间, 最大100G

第一步: 给文件扩容

上面看到的 data 文件有100G 的大小, 现在我需要200G 的 pool 大小, 所以需要调整 data 文件的属性

1
truncate -s 214748364800 /var/lib/docker/devicemapper/devicemapper/data

第二步: 检查大小

1
2
3
4
> ls -lh /var/lib/docker/devicemapper/devicemapper/                      
total 244M
-rw-------. 1 root root 200G Dec 8 18:35 data
-rw-------. 1 root root 2.0G Dec 8 18:24 metadata

第三步: Reload data loop device

1
2
3
4
5
> blockdev --getsize64 /dev/loop0
107374182400
> losetup -c /dev/loop0
> blockdev --getsize64 /dev/loop0
214748364800

第四步: Reload devicemapper thin pool

第四步基本就是重复上面扩容 container 的步骤, 这里省略了前几步的查看和计算

1
2
3
> dmsetup suspend docker-253:0-1700-pool \
&& dmsetup reload docker-253:0-1700-pool --table '0 419430400 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing' \
&& dmsetup resume docker-253:0-1700-pool

注意

扩容 pool 涉及到了两个计算

  • data 文件大小的计算
  • devicemapper 扇区数量的计算

上面已经给出了扇区的计算公式: x*1024*1024*1024/512

data 大小的计算公式为: x*1024*1024*1024


参考文档:

https://docs.docker.com/engine/userguide/storagedriver/device-mapper-driver/#/increase-capacity-on-a-running-device
https://segmentfault.com/a/1190000002931564
http://www.linuxidc.com/Linux/2015-01/112245.htm
http://www.projectatomic.io/blog/2016/03/daemon_option_basedevicesize/