暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

容器技术原理:Docker容器技术原理

一叶扁舟 2021-10-22
905

image.png

一、Docker文件系统

1.1、概述

分层镜像

rootfs 的基础上,Docker 公司结合UnionFS创新性地提出了使用多个增量 rootfs 联合挂载一个完整 rootfs 的方案,这就是容器镜像中“层”的概念。

分层镜像的好处

通过“分层镜像”的设计,以 Docker 镜像为核心,来自不同公司、不同团队的技术人员被紧密地联系在了一起。而且,由于容器镜像的操作是增量式的,这样每次镜像拉取、推送的内容,比原本多个完整的操作系统的大小要小得多;而共享层的存在,可以使得所有这些容器镜像需要的总空间,也比每个镜像的总和要小。这样就使得基于容器镜像的团队协作,要比基于动则几个 GB 的虚拟机磁盘镜像的协作要敏捷得多。

强一致性

一旦这个镜像被发布,那么你在全世界的任何一个地方下载这个镜像,得到的内容都完全一致,可以完全复现这个镜像制作者当初的完整环境。这,就是容器技术“强一致性”的重要体现。

1.2、Docker如何应用UnionFS

镜像文件系统

我们拉取一个ubuntu的镜像,通过image inspect查看他的文件系统

$ docker image inspect ubuntu:latest ... "RootFS": { "Type": "layers", "Layers": [ "sha256:f49017d4d5ce9c0f544c...", "sha256:8f2b771487e9d6354080...", "sha256:ccd4d61916aaa2159429...", "sha256:c01d74f99de40e097c73...", "sha256:268a067217b5fe78e000..." ] }

这五个层就是五个增量 rootfs,每一层都是 Ubuntu 操作系统文件与目录的一部分。

如何应用UnionFS

在使用镜像时,Docker 会把这些增量联合挂载在一个统一的挂载点上(等价于前面例子里的“/C”目录),挂在成一个完整的Ubuntu文件系统。

(1)这个信息记录在 AuFS 的系统目录 /sys/fs/aufs 下面。首先,通过查看 AuFS 的挂载信息,我们可以找到这个目录对应的 AuFS 的内部 ID(也叫:si):

# si=972c6d361e6b32ba $ cat /proc/mounts| grep aufs none /var/lib/docker/aufs/mnt/6e3be5d2ecccae7cc0fc... aufs rw,relatime,si=972c6d361e6b32ba,dio,dirperm1 0 0

(2)使用这个 ID,你就可以在 /sys/fs/aufs 下查看被联合挂载在一起的各个层的信息:

$ cat /sys/fs/aufs/si_972c6d361e6b32ba/br[0-9]* /var/lib/docker/aufs/diff/6e3be5d2ecccae7cc...=rw /var/lib/docker/aufs/diff/6e3be5d2ecccae7cc...-init=ro+wh /var/lib/docker/aufs/diff/32e8e20064858c0f2...=ro+wh /var/lib/docker/aufs/diff/2b8858809bce62e62...=ro+wh /var/lib/docker/aufs/diff/20707dce8efc0d267...=ro+wh /var/lib/docker/aufs/diff/72b0744e06247c7d0...=ro+wh /var/lib/docker/aufs/diff/a524a729adadedb90...=ro+wh

从这里我们可以看到:镜像的层都放置在 /var/lib/docker/aufs/diff 目录下,然后被联合挂载在 /var/lib/docker/aufs/mnt 里面。最终,这 7 个层都被联合挂载到 /var/lib/docker/aufs/mnt 目录下,表现为一个完整的 Ubuntu 操作系统供容器使用。

1.3、Docker文件系统结构图

从上面目录可以看出Docker的文件系统如下图所示:

image.png

从这个结构可以看出,容器的 rootfs 由如下图所示的三部分组成:只读层、Init层、可读写层

  • 只读层(存储基础镜像文件)

    这层对应的正是 ubuntu:latest 镜像的五层,这些层,都以增量的方式分别包含了 Ubuntu 操作系统的一部分。这层在容器中是不会被改动的。

  • Init层

    用户在启动容器时,写入一些指定的值比如hostname等,这些值只对当前容器有效,因此,我们并不希望再执行docker commit时,把这些数据连同读写层一起提交,因此形成一个单独的层。

    所以,docker commit 只会提交可读写层,不包含这一层的内容。

  • 可读写层

    用户在容器中做得增删改的操作,会被增量的记录在可读写层。

1.3、Docker容器全景

我们先编写有个DockerFile构建出一个镜像,看看他启动后的全景

FROM python:3.7 WORKDIR /app ADD . /app RUN pip install --trusted-host pypi.python.org -r requirements.txt EXPOSE 80 ENV NAME World # CMD,意思是 Dockerfile 指定 python app.py 为这个容器的进程。 CMD ["python", "app.py"]

Dockerfile 中的每个原语执行后,都会生成一个对应的镜像层。即使原语本身并没有明显地修改文件的操作(比如,ENV 原语),它对应的层也会存在。只不过在外界看来,这个层是空的。

image.png

我们可以看到:

(1)这个容器进程“python app.py”,运行在由 Linux Namespace 和 Cgroups 构成的隔离环境里;

(2)而它运行所需要的各种文件,比如 python,app.py,以及整个操作系统文件,则由多个联合挂载在一起的 rootfs 层提供。

(3)DockerFile中的每一步,都是一层,组成了只读层;

(4)只读层 + Init层 + 可读写层 = rootfs;

二、Docker网络

2.1、Docker的三种网络模式

安装 Docker 以后,会默认创建三种网络,可以通过 docker network ls 查看。

[root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 688d1970f72e bridge bridge local 885da101da7d host host local f4f1b3cf1b7f none null local

bridge

  • 为容器创建一个隔离的网络环境(network namespace)
  • 容器端口号可以与主机端口号重合
  • 网络互通

host

  • 并没有为容器创建一个隔离的网络环境
  • 容器的 IP 地址同 Docker host 的 IP 地址,因此容器中端口号不能与主机的端口号重合
  • 网络互通

none

  • 不为Docker容器构造任何网络环境
  • 容器只能使用127.0.0.1的本机网络(无法ping www.baidu.com)

2.2、如何设置网络

当你运行一个容器的时候,可以使用–network参数来指定

docker run -it -d --network none --name test2 centos7:new002 /bin/bash
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论