Docker容器奥秘:原理剖析

Docker容器奥秘:原理剖析一 容器镜像的组成二 分层设计思想三 UnionFS联合文件系统


Docker容器奥秘:原理剖析

在云计算和容器化技术的浪潮中,容器镜像成为了一个核心概念。容器镜像是一种轻量级、可执行的独立软件包,用于创建并运行Docker容器。它包含了运行某个软件所需的所有内容,包括代码、运行时环境、库、配置文件等。理解容器镜像的原理,特别是其分层设计和联合文件系统(UnionFS)的应用,对于深入掌握Docker技术至关重要。

一 容器镜像的组成

容器镜像由多个只读层叠加而成,每一层都包含了文件系统的变化部分。这种分层结构使得镜像的复用、管理和更新变得高效而灵活。每个层都对应Dockerfile中的一条指令,例如,一个层可能包含了操作系统的基础设置,另一个层则可能添加了应用程序的代码。当Docker构建镜像时,它会按照Dockerfile中的指令顺序,逐层构建并缓存这些层,以便后续复用。

二 分层设计思想

分层设计的核心思想是将复杂的系统分解为多个简单的部分,每一部分都专注于实现特定的功能。在容器镜像的上下文中,这种设计带来了诸多优势。首先,它提高了构建效率,因为当Dockerfile中的指令发生变化时,只有受影响的层需要重新构建,其他层可以从缓存中复用。其次,它减少了存储空间的占用,因为多个镜像可以共享相同的层。最后,它使得镜像的更新变得简单而快速,只需要替换或添加新的层,而无需重新构建整个镜像。

使用docker inspect可查看镜像的分层信息

[superman@docker ~]$ docker image inspect httpd:2.4

示例:

[superman@docker ~]$ docker image inspect httpd:2.4
[
  {
       "Id": "sha256:dabbfbe0c57b6e5cd4bc089818d3f664acfad496dc741c9a501e72d15e803b34",
       "RepoTags": [
           "httpd:2.4",
           "httpd:latest"
      ],
       "RepoDigests": [
           "httpd@sha256:0954cc1af252d824860b2c5dc0a10720af2b7a3d3435581ca788dff8480c7b32"
      ],
       "Parent": "",
       "Comment": "",
       "Created": "2021-12-21T01:36:12.729599368Z",
       "Container": "2e3825874c832964f871068b149d74ac708e0968257683b2177adc127faf9b4e",
       "ContainerConfig": {
           "Hostname": "2e3825874c83",
           "Domainname": "",
           "User": "",
           "AttachStdin": false,
           "AttachStdout": false,
           "AttachStderr": false,
           "ExposedPorts": {
               "80/tcp": {}
          },
           "Tty": false,
           "OpenStdin": false,
           "StdinOnce": false,
           "Env": [
               "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
               "HTTPD_PREFIX=/usr/local/apache2",
               "HTTPD_VERSION=2.4.52",
               "HTTPD_SHA256=0127f7dc497e9983e9c51474bed75e45607f2f870a7675a86dc90af6d572f5c9",
               "HTTPD_PATCHES="
          ],
           "Cmd": [
               "/bin/sh",
               "-c",
               "#(nop) ",
               "CMD [\"httpd-foreground\"]"
          ],
           "Image": "sha256:3dbe4a320fc074558d83d314cac5df890d915d3d35e4062d3bed484d3b2693ed",
           "Volumes": null,
           "WorkingDir": "/usr/local/apache2",
           "Entrypoint": null,
           "OnBuild": null,
           "Labels": {},
           "StopSignal": "SIGWINCH"
      },
       "DockerVersion": "20.10.7",
       "Author": "",
       "Config": {
           "Hostname": "",
           "Domainname": "",
           "User": "",
           "AttachStdin": false,
           "AttachStdout": false,
           "AttachStderr": false,
           "ExposedPorts": {
               "80/tcp": {}
          },
           "Tty": false,
           "OpenStdin": false,
           "StdinOnce": false,
           "Env": [
               "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
               "HTTPD_PREFIX=/usr/local/apache2",
               "HTTPD_VERSION=2.4.52",
               "HTTPD_SHA256=0127f7dc497e9983e9c51474bed75e45607f2f870a7675a86dc90af6d572f5c9",
               "HTTPD_PATCHES="
          ],
           "Cmd": [
               "httpd-foreground"
          ],
           "Image": "sha256:3dbe4a320fc074558d83d314cac5df890d915d3d35e4062d3bed484d3b2693ed",
           "Volumes": null,
           "WorkingDir": "/usr/local/apache2",
           "Entrypoint": null,
           "OnBuild": null,
           "Labels": null,
           "StopSignal": "SIGWINCH"
      },
       "Architecture": "amd64",
       "Os": "linux",
       "Size": 143541188,
       "VirtualSize": 143541188,
       "GraphDriver": {
           "Data": {
               "LowerDir": "/var/lib/docker/overlay2/0f922151522c8625825b82ae897c679f4156553c28de64ffd6dc24cbacb87b10/diff:/var/lib/docker/overlay2/0d10ddaad447420608a991bf9d1eeb2eab43aa94d357b11e27cbebecb266a397/diff:/var/lib/docker/overlay2/bed8bb10a171b8d67d7c17b9f3b790c155566c9fc74d1ccd569579ffd5b0c832/diff:/var/lib/docker/overlay2/db81c66aaafe71538fea4043788a774bd5bebb0b2c9efe9caa2005aa428fc8a6/diff",
               "MergedDir": "/var/lib/docker/overlay2/03b49278fced73e9848efec6f17c5c3aa87536c7dc7537385435fab596ad37b1/merged",
               "UpperDir": "/var/lib/docker/overlay2/03b49278fced73e9848efec6f17c5c3aa87536c7dc7537385435fab596ad37b1/diff",
               "WorkDir": "/var/lib/docker/overlay2/03b49278fced73e9848efec6f17c5c3aa87536c7dc7537385435fab596ad37b1/work"
          },
           "Name": "overlay2"
      },
       "RootFS": {
           "Type": "layers",
           "Layers": [
              "sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f",
              "sha256:1da636a1aa95e3ebce3b792e7321123a1ed5c593b8ef9f473fdf2b9969f4a6c7",
              "sha256:15e4bf5d0804460f17050c3c511cd1733a583865fca18f6993e4b0f222aeab95",
              "sha256:9cff3206f9a63cfbf021b4a99b80366b2e3d941813e9940fc8b5287a1af5c2f6",
              "sha256:deefaa620a71254c6089757cd6fa7704da656d728ae722a10b562b350f70c674"
          ]
      },
       "Metadata": {
           "LastTagTime": "0001-01-01T00:00:00Z"
      }
  }
]
[superman@docker ~]$

三 UnionFS联合文件系统

UnionFS是实现容器镜像分层结构的关键技术。它是一种轻量级的高性能分层文件系统,能够将多个文件系统联合到一个挂载点,形成一个单一的可读写文件系统。在Docker中,UnionFS被用来将多个只读镜像层和一个可写的容器层联合在一起。当用户启动一个容器时,Docker会在镜像的基础上添加一个可写的容器层,用于保存容器运行时的修改。这种设计使得容器可以在不修改原始镜像的情况下进行个性化的配置和数据存储。

UnionFS的写时复制策略保证了只读层的不可变性。当对联合文件系统进行写操作时,UnionFS会先将相应的文件从只读层复制到可写的容器层,然后再进行修改。这种机制确保了原始镜像的完整性,同时允许容器在其上进行个性化的修改。

docker最大的贡献就是定义了容器镜像的分层的存储格式,docker镜像技术的基础是联合文件系统(UnionFS),其文件系统是分层的。这样既可以充分利用共享层,又可以减少存储空间占用。

联合挂载系统的工作原理:读:如果文件在upperdir(容器)层,直接读取文件;如果文件不在upperdir(容器)层,则从镜像层(lowerdir)读取。

目前docker支持的联合文件系统有很多种,包括:AUFS、overlay、overlay2、DeviceMapper、VSF等。

当选择Docker的存储驱动时,有几个常用的选项可供选择,包括AUFS, Overlay, Overlay2, DeviceMapper和VFS。下面是它们的对比:

1. AUFS (Advanced Multi-Layered Unification Filesystem)

AUFS是一种基于union mount技术的存储驱动,它允许将多个文件系统合并为一个只读的虚拟文件系统。AUFS在多个容器之间共享基础镜像的文件,并在每个容器中提供一个可写的层。然而,AUFS对于大型镜像和多层容器的性能可能有一些负面影响。此外,AUFS在最新的Linux内核版本中已不再被广泛支持。

2. Overlay

Overlay是一种较新的存储驱动,它通过在底层文件系统上创建一个只读的基础镜像并叠加一个可写的层来实现容器的文件系统。Overlay相对于AUFS有更好的性能,而且它在最新的Linux内核中得到了更广泛的支持。然而,Overlay的缺点是不支持在同一个文件中存储大型镜像。

3. Overlay2

Overlay2是Overlay的改进版,它在Overlay的基础上解决了一些性能和功能的问题。Overlay2使用一个单独的只读层来存储基础镜像,并且可以支持更大的镜像。它是Docker默认的存储驱动,因为它在大多数情况下都提供了更好的性能和可靠性。

4. DeviceMapper

DeviceMapper是一种成熟的Linux存储驱动,它利用LVM(逻辑卷管理器)提供了高级功能,如快照和克隆。DeviceMapper是Docker支持的可插拔的存储后端之一,并被广泛用于可靠和复杂的存储需求。

5. VFS (Virtual File System)

VFS是Docker的默认存储驱动,它直接在宿主机上操作文件。VFS基于操作系统的本地文件系统,但在性能和可扩展性方面不如其他驱动。它适用于开发和测试环境,但不适合生产环境。

综上所述,当选择Docker存储驱动时,Overlay2是最常见和推荐的选择,因为它提供了较好的性能和可靠性。另外,如果需要高级功能和复杂的存储需求,可以考虑使用DeviceMapper。

查看docker容器使用的文件系统使用的命令如下,其中Storage Driver: overlay2代表使用的是overlay2联合文件系统。

[root@home]# docker info

示例:

[superman@docker ~]$ docker info
Client: Docker Engine - Community
Version:    24.0.7
Context:   default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
  Version: v0.11.2
  Path:     /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
  Version: v2.21.0
  Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
Containers: 1
Running: 1
Paused: 0
Stopped: 0
Images: 3
Server Version: 24.0.7
Storage Driver: overlay2     ------存储驱动类型
Backing Filesystem: xfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 3dd1e886e55dd695541fdcd67420c2888645a495
runc version: v1.1.10-0-g18a0cb0
init version: de40ad0
Security Options:
seccomp
  Profile: builtin
Kernel Version: 3.10.0-957.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 3.683GiB
Name: docker
ID: 70cdde2c-be80-48b8-bfbb-f562145167a6
Docker Root Dir: /var/lib/docker
Debug Mode: false
Experimental: false
Insecure Registries:
 127.0.0.0/8
Registry Mirrors:
https://d0xlru8b.mirror.aliyuncs.com/
Live Restore Enabled: false

[superman@docker ~]$


? 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向!

✏️ 评论,你的意见是我进步的财富!


PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我吧!


请使用浏览器的分享功能分享到微信等