【Docker 那些事儿】关于容器底层技术的奥秘

这篇具有很好参考价值的文章主要介绍了【Docker 那些事儿】关于容器底层技术的奥秘。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算


已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算

🌟 前言

上一篇文章讲了 Docker 的基本架构和 Namespace 隔离机制:【Docker 那些事儿】关于Namespace隔离机制的奥秘
 
本篇文章将继续承接上一篇,讲讲 Cgroup 资源控制和容器底层技术原理
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算

1. Cgroups

🍑 Cgroups介绍

在日常工作中,可能需要限制某个或者某些进程的资源分配,于是就出现了 Cgroups 这个概念。

Cgroups 全称是 Control groups,这是 Linux 内核提供的一种可以限制单个进程或者多个进程使用资源并进行分组化管理的机制,最初是由 Google 的工程师提出,后来被整合进 Linux 内核。

Cgroups 中有分配好特定比例的 CPU 时间、IO 时间、可用内存大小等。已经通过 Linux Namespace 创建的容器,Cgroups 将对其做进一步 “限制”。

另外,Cgroups 采用分层结构,每一层分别限制不同的资源,如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
图中,限制层 A 限制了 CPU 时间片,cgrp1 组中的进程可以使用 CPU60% 的时间片,cgrp2 组中的进程可以使用 CPU20% 的时间片。

限制层 B 限制了内存的子系统,Cgroups 中的重要概念就是“子系统”,也就是资源控制器。

子系统就是一个资源的分配器,例如,CPU 子系统是控制 CPU 时间分配的。首先挂载子系统,然后才有 Cgroups

例如,先挂载 memory 子系统,然后在 memory 子系统中创建一个 Cgroups 节点,在这个节点中,将需要控制的进程写入,并且将控制的属性写入,这就完成了内存的资源限制。

Cgroups 中,资源的限制与进程并不是简单的一对一关系,而是多对多的关系,多个限制对应多个进程,如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
在图中,每一个进程的描述符都与辅助数据结构 css_set 相关联。一个进程只能关联一个 css_set,而一个 css_set 可以关联多个进程。css_set 又对应多个资源限制,关联同一 css_set 的进程对应同一个 css_set 所关联的资源限制。

Cgroups 的实现不允许 css_set 同时关联同一个 Cgroups 层级下的多个限制,也就是 css_set 不会关联同一种资源的多个限制。这是因为为了避免冲突,Cgroups 对同一种资源不允许有多个限制配置。

一个 css_set 关联多个 Cgroups 资源限制表示将对当前 css_set 下的所有进程进行多种资源的控制。一个 Cgroups 资源限制关联多个 css_set 表明多个 css_set 下的所有进程都受到同一份资源的相同限制。

CgroupsLinux 内核支持,有得天独厚的性能优势,发展势头迅猛。在很多领域可以取代虚拟化技术分割资源。Cgroups 默认有诸多资源组,几乎可以限制所有服务器上的资源。

这里还是以 PID Namespace 为例,虽然容器内的 1 号进程在隔离机制的作用下只能看到容器内的情况,但是在宿主机上,它作为第 100 号进程与其他所有进程之间依然是平等竞争关系。

这就意味着,虽然第 100 号进程表面上被隔离了起来,但其能够使用到的资源(CPU、内存等),却是可以随时被宿主机上的其他进程占用,这就可能把所有资源耗光。

Cgroups 技术的出现,完美地解决了这一问题,对容器进行了合理的资源限制。

🍑 Cgroups的限制能力

下面介绍 Cgroups 的子系统。

  • blkio

该子系统为块设备设定输入/输出限制,如物理设备(磁盘、固态硬盘、USB等)。

  • cpu

该子系统使用调度程序提供对 CPUCgroups 任务访问。

  • cpuacct

该子系统自动生成 Cgroups 中任务所使用的 CPU 报告。

  • cpuset

该子系统为 Cgroups 中的任务分配独立 CPU(在多核系统)和内存节点。

  • devices

该子系统可允许或者拒绝 Cgroups 中的任务访问设备。

  • freezer

该子系统挂起或者恢复 Cgroups 中的任务。

  • memory

该子系统设定 Cgroups 中任务的内存限制,并自动生成由那些任务使用的内存资源报告。

  • net_cls

该子系统使用等级识别符标记网络数据包,可允许 Linux 流量控制程序识别从具体 Cgroups 中生成的数据包。

  • ns

该子系统提供了一个将进程分组到不同命名空间的方法。

下面重点介绍 Cgroups 与容器关系最紧密的限制能力。

Linux 中,Cgroups 对用户暴露出来的操作接口是文件系统,即 Cgroups 以文件和目录的方式处于操作系统的 /sys/fs/cgroup 路径下。

下面通过命令查看 Cgroups 文件路径,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
以上示例中,输出结果是一系列文件系统目录。/sys/fs/cgroup 下面有很多类似 cpusetcpumemory 等子目录,也叫子系统。

这些都是这台计算机当前可以被 Cgroups 进行限制的资源种类。而在子系统对应的资源种类下,用户就可以看到该类资源具体的限制方法。

例如,对子系统 cpu 来说,有如下几个配置文件:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
cfs_periodcfs_quota 这两个参数需要组合使用,以限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quotaCPU 时间。

🍑 实例验证

下面通过一个示例,来深入理解 Cgroups

在子系统下面创建一个目录,这个目录称为一个 “控制组”,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
从以上示例中可以看到,操作系统会在新创建的目录下自动生成该子系统的资源限制文件。

下面在后台执行一条脚本,将 CPU 占满,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
以上示例执行了一个死循环命令,进程把计算机的 CPU 占到 100%,在输出信息中可以看到这个脚本在后台运行的进程号为 7780

下面使用 top 命令查看一下 CPU 的使用情况,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
从以上示例的输出结果中可以看到,CPU 的使用率已经达到 100%

下面查看 container 目录下的文件,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
从以上示例中可以看到,container 控制组里的 CPU quota 还没有任何限制(-1),CPU period 则是默认的 100ms(100000)。

通过修改这些文件的内容就可以进行资源限制。例如,向 container 组里的 cfs_quota 文件写入 20ms(20000us),示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
这就意味着在每 100ms 的时间里,被该控制组限制的进程只能使用 20msCPU 时间,也就是说这个进程只能使用到 20%CPU 带宽。

另外,还需要把被限制的进程的进程号写入 container 组里的 tasks 文件,上面的设置才会对该进程生效,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
下面再次使用 top 命令查看,验证效果,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
从以上示例中可以看到,计算机的 CPU 使用率立刻降到了 19.9%

关于 Linux Cgroups 的结构,简单理解就是一个子系统目录与一组资源限制文件的集合。而对于类似 DockerLinux 容器项目来说,只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),在启动容器进程之后,将该进程进程号填写到对应控制组的 tasks 文件中即可。

控制组下面资源文件中的值,则需要用户执行 docker run 命令的参数指定,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
启动这个容器后,查看 Cgroups 文件系统下 CPU 子系统中 “system.slice” 这个控制组里的资源限制文件,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
这就意味着这个 Docker 容器只能使用 20%CPU 带宽。

🍑 Cgroups的劣势

Cgroups 的资源限制能力也有一些不完善的地方,尤其是/proc文件系统的问题。
 
Linux 操作系统中,/proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统信息以及当前正在运行的进程信息。如 CPU 使用情况、内存占用情况等,这些文件也是 top 命令查看系统信息的主要数据来源。
 
但用户在容器中执行 top 命令时就会发现,显示的信息居然是宿主机的 CPU内存 数据,而不是当前容器的数据。
 
造成这个结果的原因是,/proc 文件系统并不知道用户通过 Cgroups 对这个容器进行了资源限制,即 /proc 文件系统不了解 Cgroups 限制的存在。
 
这是企业中容器化应用常见的问题,也是容器相较于虚拟机的劣势。

2. Docker 文件系统

🍑 容器可读可写层的工作原理

Docker 镜像采用层级结构,是根据 Dockerfile 文件中的命令一层一层的通过 docker commit 堆叠而成的一个只读文件。容器的最上层是有一个可读写层。这个可读写层在容器启动时,为当前容器单独挂载。
 
任何容器在运行时,都会基于当前镜像在其上层挂载一个可读写层,用户针对容器的所有操作都在可读可写层中完成。一旦容器被删除,这个可读可写层也将会随之删除。
 
而用户针对这个可读可写层的操作,主要基于两种方式:写时复制与用时分配。下面对这两种方式进行详解。

🍇 写时复制

写时复制(CoWCopy-on-Write)是所有驱动都要用到的技术。CoW 表示只在需要写时才去复制,针对已有文件的修改场景。

例如,基于一个镜像启动多个容器,如果为每个容器都分配一个与镜像一样的文件系统,那么就会占用大量的磁盘空间,如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
CoW 技术可以让所有容器共享镜像的文件系统,所有数据都从镜像中读取,如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
只在要对文件进行写操作时,才从镜像里把要写的文件复制到自己的文件系统进行修改,这样就可以有效地提高磁盘的利用率。

🍇 用时分配

用时分配是先前没有分配空间,只有要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。

例如,启动一个容器时,并不为这个容器预分配磁盘空间,当有新文件写入时,才按需分配空间。

🍑 Docker 存储驱动

Docker 提供了多种存储驱动(Storage Driver)来存储镜像,常用的几种 Storage DriverAUFSOverlayFSDevice mapper、BtrfsZFS

不同的存储驱动需要不同的宿主机文件系统,如表所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
下面通过 docker info 命令查看本机 Docker 使用的 Storage Driver,示例代码如下:
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
从以上示例中可以看到,此处使用的 Storage DriverOverlay2Backing Filesystem 代表的是本机的文件系统。用户可以通过 –storage-driver= 参数来指定要使用的存储驱动,或者在配置文件 /etc/default/Docker 中通过 DOCKER_OPTS 指定。

下面介绍几种常见的存储驱动。

🍇 AUFS

AUFSAnother Union File System)是一种联合文件系统,是文件级的存储驱动。AUFS 是一个能透明覆盖一个或多个现有文件系统的层状文件系统,把多层合并成文件系统的单层表示。

简单来说,AUFS 支持将不同目录挂载到同一个虚拟文件系统下,它可以一层一层地叠加修改文件。下面无论有多少层都是只读的,只有最上层的文件系统是可读可写的。

当需要修改一个文件时,AUFS 会为该文件创建一个副本,使用 CoW 将文件从只读层复制到可度可写层进行修改,修改结果也保存在可读可写层。

Docker 中,下面的只读层就是镜像,可读可写层就是容器。AUFS 存储驱动结构如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算

🍇 OverlayFS

OverlayFSLinux 内核 3.18 版本开始支持的,它也是一种联合文件系统,与 AUFS 不同的是 Overlay 只有两层:upper 层与 lower 层,分别代表 Docker 的镜像层与容器层,如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
当用户需要修改一个文件时,OverlayFS 使用 CoW 将文件从只读的 lower 层复制到可读可写的 upper 层进行修改,结果也保存在 upper 层。

🍇 Device mapper

Device mapperLinux 内核 2.6.9 版本开始支持的,它提供一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便地根据自己的需要制定实现存储资源的管理策略。AUFSOverlayFS 都是文件级存储,而 Device Mapper 是块级存储,所有的操作都是直接对块进行的。

Device Mapper 会先在块设备上创建一个资源池,然后在资源池上创建一个带有文件系统的基本设备,所有镜像都是这个基本设备的快照,而容器则是镜像的快照。所以在容器里看到文件系统是资源池上基本设备的文件系统的快照,容器并没有被分配空间,如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
当用户要写入一个新文件时,Device Mapper 在容器的镜像内为其分配新的块并写入数据,也就是用时分配。

当用户要修改已有文件时,Device Mapper 使用 CoW 为容器快照分配块空间,将要修改的数据复制到在容器快照中新的块里,再进行修改。

Device mapper 默认会创建一个 100GB 的文件来包含镜像和容器。每一个容器被限制在 10GB 大小的卷内,可以自己配置调整。

Device Mapper 存储驱动读写机制结构如图所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算
Docker 容器的存储驱动各有其特点,下面对三种存储驱动进行对比,如表所示👇
已经通过linux namespace创建的容器,将对其做进一步限制,Kubernetes原理与实战,云原生,kubernetes,docker,容器,云计算

  • AUFSOverlayFS

AUFSOverlayFS 都是联合文件系统,但 AUFS 有多层,而 OverlayFS 只有两层,所以在做写时复制操作时,如果文件比较大且存在于比较低的层,则 AUFS 可能会更慢一点。
 
另外,OverlayFS 并入了 Linux 系统核心主线,而 AUFS 没有。

  • OverlayFSDevice mapper

OverlayFS 是文件级存储,Device Mapper 是块级存储。
 
文件级存储不管修改的内容大小都会复制整个文件,对大文件进行修改显示要比小文件消耗更多的时间,而块级存储无论是大文件还是小文件都只复制需要修改的块,并不是复制整个文件,如此一来 Device Mapper 速度就要快一些。
 
块级存储直接访问逻辑磁盘,适合 IO 密集的场景。而对于程序内部复杂,多并发但少 IO 的场景, OverlayFS 的性能相对要强一些。

3. 总结

本章深层次剖析了容器的底层技术,包括 Docker 的基本架构、NamespaceCgroups存储驱动 等。
 
通过这两篇文章的学习可以明白,容器的强大不仅来源于其本身的结构,更重要的是依靠宿主机的硬件支持。
 
在实际应用 Docker 容器时,还会利用相关的系统配置与资源限制,来对容器进行优化。文章来源地址https://www.toymoban.com/news/detail-779654.html

到了这里,关于【Docker 那些事儿】关于容器底层技术的奥秘的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android | 关于 OOM 的那些事儿

    作者:345丶 前言 Android 系统对每个app都会有一个最大的内存限制,如果超出这个限制,就会抛出 OOM,也就是Out Of Memory 。本质上是抛出的一个异常,一般是在内存超出限制之后抛出的。最为常见的 OOM 就是内存泄露(大量的对象无法被释放)导致的 OOM,或者说是需要的内存大小

    2024年02月11日
    浏览(59)
  • 【网络安全】关于CTF那些事儿你都知道吗?

    CTF比赛是快速提升网络安全实战技能的重要途径,已成为各个行业选拔网络安全人才的通用方法。但是,本书作者在从事CTF培训的过程中,发现存在几个突出的问题: 1.线下CTF比赛培训中存在严重的“最后一公里”问题,线下培训讲师的水平参差不齐。 2.国内高等院校和职业

    2024年02月08日
    浏览(54)
  • 边缘计算那些事儿—边缘智能技术

            边缘智能是边缘计算中一个非常重要的方向。它将边缘计算和人工智能算法结合起来,在边缘设备上就近处理目标检测、物体跟踪,识别等任务。这种处理方式可以降低时延,减少数据上送云端对回传网络的冲击,同时保证数据的隐私和安全性。但是,我们要面对一

    2023年04月22日
    浏览(48)
  • 边缘计算那些事儿-漫谈网络切片关键技术

    0、背景         网络切片作为一种比较前沿的技术,当前并没有太多系统的资料可以学习,很多的技术资料都是比较分散地分布在论文和一些技术博客中,笔者当前是通过论文的解读获取相关的技术信息,在过程中笔者总结了相关的技术栈,本文就是针对该技术栈的一次探

    2024年02月13日
    浏览(44)
  • 【Docker 那些事儿】还不会安装Docker?建议看这篇就够了

    Docker 作为新兴的容器技术,目前在企业中得到了广泛的应用,市场也十分渴望相关技术人才。   由于各企业使用的服务器系统有所差异,本文章将详细介绍如何在 Windows、Linux 以及 Mac 系统下安装 Docker。 Docker 原本是 dotCloud 公司旗下一个业余的开源产品,随着 Docker 的流行与

    2023年04月08日
    浏览(38)
  • Docker修改容器已经映射的端口

    Docker启动容器后,需要新增或者修改端口映射 修改配置文件更改端口 关闭容器 需要先关闭Docker,否则配置不生效 查看容器挂载目录 修改配置 修改 hostconfig.json 文件 修改 config.v2.json 文件 并不需要修改Ports,只有在你没有stop容器时,Ports才会有值,如果关闭了容器,就是空数

    2024年02月05日
    浏览(53)
  • docker给已经启动容器添加挂载目录

    1.关闭docker 2. sudo su切换到root身份 cd /var/lib/docker/containers/容器id/,进入对应容器目录 3.vim hostconfig.json 修改如下,将容器目录/import绑定到主机/data目录: \\\"Binds\\\": [\\\"/data:/import\\\"], 4.vim config.v2.json 修改如下,添加MountPoints: 5.启动docker    systemctl start docker.socket  systemctl start docker.ser

    2024年02月11日
    浏览(45)
  • 【容器底层技术】 namespaces详解

    namespaces是 Linux 内核的一项功能,它 对内核资源进行隔离 ,让一组进程只能看到与自己相关的一部分资源,而另一组进程看到另一组资源, 使得处于不同 namespaces 的进程拥有独立的全局系统资源,改变一个 namespaces 中的系统资源只会影响当前 namespaces 里的进程,对其他 nam

    2024年02月07日
    浏览(50)
  • Docker 对已经启动的容器添加目录映射

    需要在测试环境先进行试验,操作不当可能导致容器无法启动!!! 操作系统:CentOS 7.9.2009 x86_64 Docker 版本:20.10.12 使用 Docker 进行部署 TDengine 数据库,需要每天进行数据备份,但是创建该容器时没有添加目录映射到宿主机,如果容器异常可能导致数据无法恢复。 关闭 doc

    2024年02月04日
    浏览(52)
  • docker 在已经启动的容器中开启端口映射

    在找这个ID的时候要先在之前docker没关闭之前查看 配置文件如下 这个是hostconfig.json 在这里要把映射的端口信息写入 这里是config.v2.json 这里要把暴露的端口写入 在本机查看一下端口占用

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包