首页 > 其他分享 >Docker镜像分层机制

Docker镜像分层机制

时间:2023-09-03 23:13:13浏览次数:44  
标签:4096 22 分层 diff xr 镜像 overlay2 root Docker

起源

公司做云桌面,导师给我讲镜像分层机制,说到了一个弊端,即保存用户数据的层即使写入一个很小的txt文件也会占用3G大小,当时我就想到了Docker的镜像分层机制,为什么Docker不会有这个弊端,所以今天撸一下Docker的镜像分层原理。

这里默认你已经知道Docker的镜像分层机制了,所以不会对它是啥做过多的介绍。

层和Storage Drivers

假设有下面一个Dockerfile,第一行的FROM指令会pullubuntu:22.04中的层,然后第3、4、5行会分别创建一个新层:

FROM ubuntu:22.04
LABEL org.opencontainers.image.authors="[email protected]"
COPY . /app                 # new layer
RUN make /app               # new layer
RUN rm -r $HOME/.cache      # new layer
CMD python /app/app.py

当你基于该镜像启动一个容器时,会创建一个新的读写层,用于承载你的修改,原先的层都是只读的,无论你做什么修改都不会影响到它们,如下图:

img
只读层使得层可以复用,比如基于Ubuntu再创建一个镜像,它们可以共用Ubuntu的那些层,大大节省了磁盘空间。但是层级的存在使得读取速度变慢,因为每一次读取都需要自顶向下查找每一层,找到第一个具有文件的层。

如何编排这些层,以及如何使用这些层来运行容器就是存储驱动(Storage Driver)要做的,Docker提供了多种存储驱动:

  1. Btrfs
  2. Device Mapper
  3. OverlayFS
  4. ZFS
  5. VFS
  6. AUFS
  7. ...

虽然说不同的存储驱动编排层的方式不一样,但是它们都遵循上面的层叠镜像模型以及Copy-On-Write策略(后面简称COW)。

Copy-On-Write策略

我们已经知道了一个Docker镜像具有N个只读层,容器运行时会有一个最顶层的读写层,用户的写操作都会留在读写层,容器被删除,这个读写层也被删除。

那么假设/a/b在某个只读层中,容器运行时,用户期望改动这个文件,它必须将它复制到自己的层中进行修改,这就叫Copy-On-Write(写时复制)。

COW的好处显而易见,容器运行不用拷贝所有底层依赖的镜像层,只需要当有修改时将文件复制到自己的读写层即可,大大提高了空间利用率和创建容器的速度。

COW的坏处也显而易见,每次要修改低层的文件时(包括修改文件元数据),都要将文件复制一份到自己的读写层再操作,所以在写密集的应用中并不建议直接在容器中做IO操作,而是使用卷挂载

下面做一个COW的实验,我的Dockerfile.1最后一行生成了一个5G的大文件,可以看到生成后的镜像很大:

img

img

现在,基于它运行两个镜像,在没进行修改时,这些容器的大小都是5.38G,而实际大小都是0B,因为5.38G是复用镜像的层

img

我又用这个镜像运行了两个容器,在第四个容器中修改了一下这个大文件:

img

这一行执行了很久,而在实际的操作系统中应该是瞬间执行完成的,毕竟就是追加一个字节而已,所以可以推断是在执行从原始镜像层复制大文件到容器的读写层的操作,再次通过指令查看这些容器的大小,image4已经变成了10G多(虚拟大小,读写层有5.37G,加上镜像层的5G)

img

嘶,为啥不能只复制需要的块,而是整个文件复制?后来知道了这只是overlay2的特性,有些存储驱动支持块级别复制,在这种情况下会快很多。

存储驱动介绍

驱动 介绍 受支持的底层文件系统
overlay2 overlay2是当前所有受支持的Linux发行版的默认存储驱动,不需要额外配置 ftype=1下的xfsext4
fuse-overlayfs fuse-overlayfs是在运行Rootless Docker的主机上,并且主机不提供rootless的overlay2支持时的默认选项。在Ubuntu和Debian10上,fuse-overlayfs驱动不需要被使用,即使是在rootless模式,overlay2也能工作。细节请看Rootless mode documentation 任何文件系统
btrfszfs 它俩提供一些高级选项,比如创建快照,但是需要更多的维护和设置,每一个都需要背后的文件系统被正确的配置 btrfszfs
vfs 这个存储驱动用于测试亩地,以及那些没有copy-on-write文件系统可用的情况。它的性能很差,通常不推荐在生产环境使用 任何文件系统
devicemapper 该存储驱动在生产环境需要direct-lvm,因为loopback-lvm虽然是零配置,但是性能很差。devicemapper在CentOS和RHEL上曾经是推荐的存储引擎,因为它们的内核版本不支持overlay2。然而,当前的CentOS和RHEL已经支持overlay2了。 direct-lvm

每一个存储驱动有自己的性能特征,使得它们或多或少地适合不同的workloads

  1. overlay2在文件层级工作,而非块层级,这能更高效的利用内存,但在写入比较重的workload下可能让容器的可写层变得非常大。
  2. 块级存储驱动,比如devicemapperbtrfszfs,在重写入workload时性能更好(虽然不如卷)
  3. btrfszfs需要大量内存
  4. zfs在密集的工作负载(如PaaS)下是一个好选择

本节上面的内容都是翻译自官方文档,一些地方看不懂,不用管。

OverlayFS

磁盘存储结构

我的docker没有任何镜像,现在pull一个mysql,它具有11个层:

img

Docker将文件存储在/var/lib/docker/<storage driver>/下,进入查看:

img

除了第一个1是一个文件以外,剩下的都是一堆名字很古怪的文件夹,不知道里面都是啥,看一看每一个文件夹里都有啥:

yudoge-arch# ls $(ls | tr '\s' '\n')

24c8f8ad45062676747efcee80794e7199f07bbbe3c5eb1cb3e5d7c4602050e9:
committed  diff  link

29f1a2f52e4307af79565e38b3e16b54bdb13d81e55679cce4f38ecc559b4d50:
committed  diff  link  lower  work

2f7e13e6b80f9f19837cbe61578e01141f012a2bbad38efc62aa2d99a095ca2c:
committed  diff  link  lower  work

3c554617f26581acebe341ce9242b406dc5b05388d346d1856e2663cdd14e441:
committed  diff  link  lower  work

8f72c03dafd2cd46cab06fb10667060cddd86799f857e943da2fbe43d43807a2:
committed  diff  link  lower  work

9ebff6298e82baa0337a971e37c9d0e70bb32f4b968eeb018762301edc39505c:
committed  diff  link  lower  work

c7c8b73afa6247e87502a016838d12d45ed1f4a024be182040aa88df5f954d7e:
diff  link  lower  work

cdc4dfdc0baa0eef9c6f12097d8e7d40fe332b87b3115282499aba6f514b41b2:
committed  diff  link  lower  work

e4adcd02a5079dcfa19f967a21c371dc20b81f048f6f97e037c03b9f44ce12e1:
committed  diff  link  lower  work

ff4c13585960bb1b823e3e0e89987905ca638cc212feba4a3b265ff2aa767bca:
committed  diff  link  lower  work

l:
2CYSJH5HKCRQYLT3YZ6YJUSWNS  MHN435GTE26WH3XQK7GHKLA2WX	UE2RISJIAXR2COS55ETHU3M6UU  ZI2FF4Z2IIOY2Q5AFJ4KN6COUG
2H3EAOI3ZSQZSC5HDUOD2J72UY  OGHUJ26UTM36F4442J67JG6IMT	UZCYLVTJUTL2NTUJ2L5HCBG4O3
HJGKKE5R2IYWFOXK3B4VS6P2D6  QPICFLQJ7JGK2RJCMWGHXFOFGK	XXP5E2KJH6PJ6XFVB6HBJC4DG2

那些名称像一串哈希值的都是一个层级,它们大都包含committeddifflinklowerwork这些子文件(目录),lower文件中写明了它的所有父级,diff文件夹包含该层级自己的文件内容,work则是OverlayFS内部需要的文件夹。

yudoge-arch# cat 29f1a2f52e4307af79565e38b3e16b54bdb13d81e55679cce4f38ecc559b4d50/lower
l/MHN435GTE26WH3XQK7GHKLA2WX:l/HJGKKE5R2IYWFOXK3B4VS6P2D6:l/ZI2FF4Z2IIOY2Q5AFJ4KN6COUG:l/UE2RISJIAXR2COS55ETHU3M6UU#

yudoge-arch# tree 8f72c03dafd2cd46cab06fb10667060cddd86799f857e943da2fbe43d43807a2/diff
8f72c03dafd2cd46cab06fb10667060cddd86799f857e943da2fbe43d43807a2/diff
└── etc
    └── yum.repos.d
        └── mysql-community-tools.repo

l文件夹中包含一堆符号链接,指向每一个层级文件夹中的diff

yudoge-arch# ls -al l
total 56
drwx------  2 root root 4096 Sep  3 22:31 .
drwx--x--- 15 root root 4096 Sep  3 22:31 ..
lrwxrwxrwx  1 root root   72 Sep  3 22:02 2CYSJH5HKCRQYLT3YZ6YJUSWNS -> ../c7c8b73afa6247e87502a016838d12d45ed1f4a024be182040aa88df5f954d7e/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 2H3EAOI3ZSQZSC5HDUOD2J72UY -> ../29f1a2f52e4307af79565e38b3e16b54bdb13d81e55679cce4f38ecc559b4d50/diff
lrwxrwxrwx  1 root root   77 Sep  3 22:31 4FYPZQFKTYVCP5J56MXWT7Y5PG -> ../de0b45609e14ad7d9f18c283b68f9b5ef2beb9d7d25f3910b490c6abb47f1213-init/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:31 6L3W4MP2S23ZVOZHV467SMV237 -> ../de0b45609e14ad7d9f18c283b68f9b5ef2beb9d7d25f3910b490c6abb47f1213/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 HJGKKE5R2IYWFOXK3B4VS6P2D6 -> ../9ebff6298e82baa0337a971e37c9d0e70bb32f4b968eeb018762301edc39505c/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 MHN435GTE26WH3XQK7GHKLA2WX -> ../3c554617f26581acebe341ce9242b406dc5b05388d346d1856e2663cdd14e441/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 OGHUJ26UTM36F4442J67JG6IMT -> ../ff4c13585960bb1b823e3e0e89987905ca638cc212feba4a3b265ff2aa767bca/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 QPICFLQJ7JGK2RJCMWGHXFOFGK -> ../e4adcd02a5079dcfa19f967a21c371dc20b81f048f6f97e037c03b9f44ce12e1/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 UE2RISJIAXR2COS55ETHU3M6UU -> ../24c8f8ad45062676747efcee80794e7199f07bbbe3c5eb1cb3e5d7c4602050e9/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 UZCYLVTJUTL2NTUJ2L5HCBG4O3 -> ../8f72c03dafd2cd46cab06fb10667060cddd86799f857e943da2fbe43d43807a2/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 XXP5E2KJH6PJ6XFVB6HBJC4DG2 -> ../2f7e13e6b80f9f19837cbe61578e01141f012a2bbad38efc62aa2d99a095ca2c/diff
lrwxrwxrwx  1 root root   72 Sep  3 22:02 ZI2FF4Z2IIOY2Q5AFJ4KN6COUG -> ../cdc4dfdc0baa0eef9c6f12097d8e7d40fe332b87b3115282499aba6f514b41b2/diff

之所以这样编排,好像是因为开启容器的时候运行mount命令挂载时,mount的参数长度首页大小限制,最多4096字节,多的会被截断,所以这里有一批简写的链接,然后lower文件中记录的貌似也是这些链接,层级文件中的link记录的就是它在l中的链接文件名。

挂载

就像你在某一个设备上mkfs创建某种格式的文件系统之后,需要通过mount来挂载到linux一样,容器运行时OverlayFS也要通过mount挂载。

使用mount命令可以查看系统下所有挂载的情况

运行容器后,查看挂载情况,docker将/var/lib/docker/overlay2/dfxxx/merged的一个文件夹挂载了(刚刚没这个df什么的文件夹哦),并指定了lowerdir列表,刚好11个,对应镜像的11个层级,而upperdir则指向了自己(dfxxx)的diffworkdir指向自己的work,权限是读写的:

yudoge-arch# mount | grep overlay
overlay on /var/lib/docker/overlay2/df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/2RWAC6GZLJV64RBOZDSCUCWHJE:/var/lib/docker/overlay2/l/2CYSJH5HKCRQYLT3YZ6YJUSWNS:/var/lib/docker/overlay2/l/QPICFLQJ7JGK2RJCMWGHXFOFGK:/var/lib/docker/overlay2/l/UZCYLVTJUTL2NTUJ2L5HCBG4O3:/var/lib/docker/overlay2/l/OGHUJ26UTM36F4442J67JG6IMT:/var/lib/docker/overlay2/l/XXP5E2KJH6PJ6XFVB6HBJC4DG2:/var/lib/docker/overlay2/l/2H3EAOI3ZSQZSC5HDUOD2J72UY:/var/lib/docker/overlay2/l/MHN435GTE26WH3XQK7GHKLA2WX:/var/lib/docker/overlay2/l/HJGKKE5R2IYWFOXK3B4VS6P2D6:/var/lib/docker/overlay2/l/ZI2FF4Z2IIOY2Q5AFJ4KN6COUG:/var/lib/docker/overlay2/l/UE2RISJIAXR2COS55ETHU3M6UU,upperdir=/var/lib/docker/overlay2/df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260/diff,workdir=/var/lib/docker/overlay2/df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260/work,index=off)

这个/var/lib/docker/overlay2/df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260就是为容器新创建的文件夹:

yudoge-arch# ls | grep df9a
df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260
df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260-init

查看df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260/merged文件夹,里面的内容是多个层合并后的统一视图:

yudoge-arch# ls -al df9a7a8984736e75b4348be3234580bbc91e8519bb9a26e07c9c0a3e8cc66260/merged
total 84
drwxr-xr-x 1 root root 4096 Sep  3 22:44 .
drwx--x--- 5 root root 4096 Sep  3 22:44 ..
lrwxrwxrwx 1 root root    7 Oct  9  2021 bin -> usr/bin
dr-xr-xr-x 2 root root 4096 Oct  9  2021 boot
drwxr-xr-x 1 root root 4096 Sep  3 22:44 dev
drwxr-xr-x 2 root root 4096 Aug 11 09:38 docker-entrypoint-initdb.d
-rwxr-xr-x 1 root root    0 Sep  3 22:44 .dockerenv
drwxr-xr-x 1 root root 4096 Sep  3 22:44 etc
drwxr-xr-x 2 root root 4096 Oct  9  2021 home
lrwxrwxrwx 1 root root    7 Oct  9  2021 lib -> usr/lib
lrwxrwxrwx 1 root root    9 Oct  9  2021 lib64 -> usr/lib64
drwxr-xr-x 2 root root 4096 Oct  9  2021 media
drwxr-xr-x 2 root root 4096 Oct  9  2021 mnt
drwxr-xr-x 2 root root 4096 Oct  9  2021 opt
dr-xr-xr-x 2 root root 4096 Aug 10 11:44 proc
dr-xr-x--- 1 root root 4096 Aug 11 09:38 root
drwxr-xr-x 1 root root 4096 Aug 11 09:38 run
lrwxrwxrwx 1 root root    8 Oct  9  2021 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Oct  9  2021 srv
dr-xr-xr-x 2 root root 4096 Aug 10 11:44 sys
drwxrwxrwt 1 root root 4096 Sep  3 22:44 tmp
drwxr-xr-x 1 root root 4096 Aug 10 11:44 usr
drwxr-xr-x 1 root root 4096 Aug 10 11:44 var

OverlayFS将在单一Linux主机上的多个文件夹展现为单一文件夹,这些文件夹被称为层,而将它们归一化的过程被称为联合挂载(union mount),OverlayFS将底层的那些文件夹称为lowerdir,顶层的称为upperdir,最后通过upperdir下的merged文件夹暴露出统一视图

img

容器如何使用overlay2读写

先睡觉...

参考

标签:4096,22,分层,diff,xr,镜像,overlay2,root,Docker
From: https://www.cnblogs.com/lilpig/p/17675584.html

相关文章

  • docker二进制安装
    docker自动安装脚本下载软件wgethttps://download.docker.com/linux/static/stable/x86_64/docker-24.0.5.tgzwgethttps://github.com/docker/compose/releases/download/v2.21.0/docker-compose-linux-x86_641.安装docker和docker-compose将安装脚本install.sh和二进制......
  • Windows与网络基础——虚拟机镜像相关
    1.虚拟机Windows10安装硬盘分区时,先新建分区,再格式化在启动此电脑——管理——本地用户和组 向下箭头代表为禁用开机状态快照占用内存大于关机状态快照2.虚拟机WindowsServer2016安装要桌面的话,需要选择桌面体验版Server版本的WINDOWS需要给管理员设置密码,且具备复杂性,......
  • Docker构建Jenkins
    拉取jenkins的docker镜像,这里用的是lts的长期支持版本,你可以到jenkins官网自由选择其他版本(下载速度慢,花了两个小时,如果中途出现超时再次运行该命令即可)dockerpulljenkins/jenkins:lts配置宿主机映射到容器的目录,之后jenkins的一些配置文件......
  • Linux--安装部署Docker
    Docker介绍Docker理解Docker是基于Go语言实现的开源容器项目,专业的叫法是应用容器一次封装、到处运行对应用封装、分发、部署、运行的生命周期进行管理应用组件:Web应用、数据库平台、操作系统、集群为应用的开发、运行和部署提供一站式的使用解决方案Docker优势Docker容器好比一......
  • sonarqube教程:docker-compose安装sonarqube及sonar-scanner插件的使用
    docker-compose安装sonarqubevim/etc/sysctl.conf vm.max_map_count=262144vm.max_map_count参数含义version:'3'services:postgres:image:postgres:14.5restart:alwayscontainer_name:postgresports:-5432:5432volumes:......
  • docker下安装clickhouse
    文章目录01前言02安装03修改配置3.1安装vim插件3.2修改用户密码04验证01前言clickhousedockerhub首页:https://hub.docker.com/r/yandex/clickhouse-server,这里描述了clickhouse在docker下的简介以及部署方式:搜索自己需要的版本:https://hub.docker.com/r/yandex/clickhou......
  • 在Docker下一键安装部署免费开源的问答社区!
    在Docker下一键安装部署免费开源的问答社区! 1.准备一台VPS主机,没有的话,【搞一台】 2.一键安装部署Dockerwgethttps://raw.githubusercontent.com/QUANTAXIS/QUANTAXIS/master/config/install_docker.shsudobashinstall_docker.sh全选代码复制3.一键安装Answ......
  • docker 安装rabbitmq
    dockerpullrabbitmqdockerrun-d--hostnamemyrabbitmq--namerabbitmq-p15672:15672-p5672:5672rabbitmqdockerexec-itrabbitmq/bin/bashrabbitmq-pluginsenablerabbitmq_management可以通过访问http://localhost-ip:15672,访问web界面,这里的用户名和密......
  • ubuntu 虚拟机安装docker
    1. downloadimages:https://releases.ubuntu.com/22.04/       加速:https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/22.04/2.installvmware3.vmware选择安装这个镜像。这个镜像安装完之后,没有docker4.用熟悉的编辑器打开: /etc/apt/sources.list ......
  • docker中两个容器使用同一个IP的方法
    如果你希望允许两个容器使用相同的IP地址,可以使用Macvlan网络驱动程序。Macvlan网络驱动程序允许容器共享主机网络接口的MAC地址,从而允许多个容器使用相同的IP地址。以下是使用Macvlan网络驱动程序实现两个容器共享相同IP地址的步骤:1.创建一个Macvlan网络,指定父接口和IP地址范......