Docker Storage Driver

警告
本文最后更新于 2019-11-25,文中内容可能已过时。

https://docs.docker.com/storage/storagedriver/

https://docs.docker.com/storage/storagedriver/device-mapper-driver/

Docker修改空间大小

Docker 环境 Storage Pool 用完解决方案:resize-device-mapper

关于docker动态扩展容器空间大小

dmsetup

storage driver 可以让我们在 container 的可写层中创建数据,当删除 container后,这些数据不会保留;而且可写层的读写速度低于原生文件系统;

images由一系列的layer组成;

images的每一层代表Dockerfile中的一条指令;

Layers of a container based on the Ubuntu image

对运行中的container所做的所有更改都会写入 Thin R/W layer;

每个container都有自己的container layer, 并且所有更改都在container layer,所以多个容器可以共享对同一基础image的访问,但有自己的数据状态;

容器共享同一图像

Storage Driver 用来管理image layers 和 container layer;

docker 提供了多种Storage driver, 每种Storage driver 对实现的处理方式不同,但是都使用可堆叠(stackable)的image layer和写时复制(CoW)策略;

查看container size

1
docker ps -s
1
2
3
4
5
6
7
#docker pull node:14.0.0-stretch
docker pull node:13.13.0-alpine3.11

#docker run -it -d --name node node:14.0.0-stretch
docker run -it -d --name node node:13.13.0-alpine3.11

docker run -it -d --name node_v -v /home/deepbay/deepops/:/deepops node:14.0.0-stretch
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
deep@test3:~$ docker ps -s
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES               SIZE
4b7d70e701f1        node:14.0.0-stretch   "docker-entrypoint.s…"   10 minutes ago      Up 10 minutes                           node                0B (virtual 941MB)
deep@test3:~$ docker exec -it node /bin/bash
root@4b7d70e701f1:/# wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
--2020-04-27 06:18:24--  https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
Resolving dl.google.com (dl.google.com)... 203.208.40.39, 203.208.40.34, 203.208.40.41, ...
Connecting to dl.google.com (dl.google.com)|203.208.40.39|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 123658438 (118M) [application/octet-stream]
Saving to: 'go1.14.2.linux-amd64.tar.gz'

go1.14.2.linux-amd64.tar.gz               100%[====================================================================================>] 117.93M  10.2MB/s    in 11s     

2020-04-27 06:18:35 (10.7 MB/s) - 'go1.14.2.linux-amd64.tar.gz' saved [123658438/123658438]

root@4b7d70e701f1:/# ls -alh | grep go
-rw-r--r--   1 root root 118M Apr  8 22:12 go1.14.2.linux-amd64.tar.gz
root@4b7d70e701f1:/# exit
exit
deep@test3:~$ docker ps -s
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES               SIZE
4b7d70e701f1        node:14.0.0-stretch   "docker-entrypoint.s…"   14 minutes ago      Up 14 minutes                           node                124MB (virtual 1.07GB)

在容器内下载golang安装包,docker container size 增加;

image-20200427143242271

  • size: container layer 的数据量
  • virtual size: image layers加上 container layer的数据量

https://docs.docker.com/storage/storagedriver/select-storage-driver/

  • overlay2
  • aufs
  • devicemapper
  • btrfs
  • zfs
  • vfs

centos 7

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
sudo yum install -y yum-utils

sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
    
yum list docker-ce --showduplicates | sort -r

sudo yum install docker-ce-18.03.1.ce docker-ce-cli-18.03.1.ce containerd.io

sudo tee /etc/docker/daemon.json <<-'EOF'
{
	"registry-mirrors": ["https://registry.docker-cn.com"],
	"storage-driver": "devicemapper"
}y
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

# start up automatically on boot up
sudo systemctl enable docker && sudo systemctl start docker

image-20200428181640525

image-20200428181837674

1
2
3
4
5
sudo groupadd docker
sudo gpasswd -a sunyh docker
sudo service docker restart

reboot
1
2
3
4
5
6
DATA_SIZE=1000
METADATA_SIZE=10
sudo systemctl stop docker
dd if=/dev/zero of=/var/lib/docker/devicemapper/devicemapper/data bs=1G count=0 seek=$DATA_SIZE
dd if=/dev/zero of=/var/lib/docker/devicemapper/devicemapper/metadata bs=1G count=0 seek=$METADATA_SIZE
sudo systemctl start docker

image-20200430154554095

1
2
docker pull node:13.13.0-alpine3.11
docker run -it -d --name node node:13.13.0-alpine3.11
1
2
docker ps -s
dmsetup table

image-20200430101937171

resize container

1
2
3
4
5
6
7
echo $((30*1024*1024*1024/512))

echo 0 41943040 thin 253:0 7 | sudo dmsetup load docker-8:2-101407194-f69fd6ac662db4fd50e56ad2d4d45987bf31ade7b0b17a2e9d29b333df98c76a

sudo dmsetup resume docker-8:2-101407194-f69fd6ac662db4fd50e56ad2d4d45987bf31ade7b0b17a2e9d29b333df98c76a

sudo xfs_growfs -d /dev/mapper/docker-8:2-101407194-f69fd6ac662db4fd50e56ad2d4d45987bf31ade7b0b17a2e9d29b333df98c76a

image-20200430102726332

脚本简化以上流程:

  1. 获取deviceName

    1
    2
    3
    
    # docker inspect -f '{{ .GraphDriver.Data.DeviceName }}' [container id]
    
    docker inspect -f '{{ .GraphDriver.Data.DeviceName }}' 2d9ddb14b348
    
  2. 使用dmsetup table 命令显示出device mapper的具体信息

    1
    2
    
    # dmsetup table [device name]
    sudo dmsetup table docker-8:2-101407194-f69fd6ac662db4fd50e56ad2d4d45987bf31ade7b0b17a2e9d29b333df98c76a
    

    当容器在stop状态时以上操作得不到device mapper信息,虽然由于空 间不足不能启动成功,但需要先docker start 才能查找到对应 device mapper信息。

  3. 算出想要扩容的扇区数

    1
    2
    
    SIZE=15
    echo $(($SIZE*1024*1024*1024/512))
    
  4. load一个新的设备信息表(新表与旧表相比只修改扇区数量)

    1
    
    echo 0 31457280 thin 253:0 7 | sudo dmsetup load docker-8:2-101407194-f69fd6ac662db4fd50e56ad2d4d45987bf31ade7b0b17a2e9d29b333df98c76a
    
  5. 通过dmsetup resume激活新的设备信息表

    1
    
    sudo dmsetup resume docker-8:2-101407194-f69fd6ac662db4fd50e56ad2d4d45987bf31ade7b0b17a2e9d29b333df98c76a
    
  6. 调整文件系统大小(只能增,不能减)

    File TypeResize CLI
    xfsxfs_growfs
    ex2,ex3,ex4resize2fs
    1
    
    sudo xfs_growfs -d /dev/mapper/docker-8:2-101407194-f69fd6ac662db4fd50e56ad2d4d45987bf31ade7b0b17a2e9d29b333df98c76a
    
 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
import paramiko

hostname = '192.168.232.133'
username = 'sunyh'
password = 'hisunyh'
container_id = "3afd866418592636fc27754bfebdf29576daa5c22118e323a912320571dcabc0"
device_size = 16
paramiko.util.log_to_file('syslogin.log')  # 发送paramiko日志到syslogin.log文件


def resize_container():
    ssh = paramiko.SSHClient()
    # 获取客户端host_keys,默认~/.ssh/known_hosts,非默认路径需指定ssh.load_system_host_keys(/xxx/xxx)
    ssh.load_system_host_keys()
    ssh.connect(hostname=hostname, username=username, password=password)
    # echo "yourpasswd" |sudo -S yourcommand
    stdin, stdout, stderr = ssh.exec_command("docker inspect -f '{{ .GraphDriver.Data.DeviceName }}' %s" % container_id)
    # print(stdout.read().decode('utf-8'))
    device_name = stdout.readlines()[0]
    if device_name.find('docker') == -1:
        print('get device name failed')
        return
    print('device name: %s' % device_name)

    stdin, stdout, stderr = ssh.exec_command("echo %s | sudo -S dmsetup table %s" % (password, device_name))
    device_mapper = stdout.readlines()[0]
    if device_mapper.find('thin') == -1:
        print('get device mapper info failed')
        return
    print('device mapper info: %s' % device_mapper)

    device_sector = device_mapper.replace('\n', '').split('thin')[1]
    print('device sector: %s' % device_sector)

    stdin, stdout, stderr = ssh.exec_command('echo 0 %s thin%s | sudo dmsetup load %s' % (device_size * 1024 * 1024 * 1024 / 512, device_sector, device_name))
    print('dmsetup load finish')

    stdin, stdout, stderr = ssh.exec_command('sudo dmsetup resume %s' % device_name)
    print('dmsetup resume finish')

    fs_line = 'sudo xfs_growfs -d /dev/mapper/%s' % device_name
    print(fs_line)
    stdin, stdout, stderr = ssh.exec_command(fs_line)
    print(stdout.readlines())
    print('file system modify finish')
    ssh.close()
    pass

if __name__ == "__main__":
    resize_container()

相关内容