boost any 实现万能容器_容器化技术实现原理

容器的本质

容器的本质是什么?

容器的本质是一个进程

容器的本质是一个进程

容器的本质是一个进程

c3c03f61db697c51392d935e5090fd56.png

运行容器

进程与进程之间相互隔离造就了容器与容器互不影响的特性。在启动一个容器(即创建一个进程时),通过 Namespace 技术实现容器的隔离、通过 Cgroups 来实现容器的资源控制。

Namespace

容器进程的创建通过 Linux 平台下的 clone 方法创建,在调用该方法创建进程时,通过指定额外的 Namespace 参数,使得刚创建的进程属于一个独立的空间。int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL)指定额外参数 CLONE_NEWPID 创建的新进程,有一个自己的 独立进程空间,在这个空间里,它的进程 ID 为 1。它既看不到其在宿主机的真正进程、也看不到其他容器的进程。其实这都是假象,创建的该进程在宿主机上是真实存在的,并且也受宿主机的管理和控制,也享受宿主机的资源。但在该进程内部,它处于一个独立的空间,只看得到该进程一个资源,让其误以为自己处于一个密闭的 盒子 内。这这,就是 Linux 容器最基本的实现原理了!你可能也注意到了,虽然通过 Linux Namespace 技术实现了进程的相互隔离,但这种隔离机制只是为不同的容器进程指定不同的 namespace,但不同的容器进程其实在宿主机上是真实存在的,并且也使用相同的宿主机内核。这也是容器在和虚拟化技术相比下,隔离得不够彻底的原因。

Cgroups

2aeda0797041075b96db16750bbe8a82.png

容器进程创建好后,若不进行其他处理,该进程运行时所消耗及占用的资源(如 CPU、内存)等;是可以被其他宿主机进程或其他容器进程享用的。为了解决这个问题,Linux 容器设计中引入了 Cgroups 的概念。Linux Cgroups 的全称是 Linux Control Group,它的主要作用就是限制一个进程能够使用的资源上限(如 cpu、内存、网络等)。在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。 若你的系统中没有挂载该目录,那你需要自行 google 挂载。在该目录下,你可以看到很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。每个目录下面又有很多配置文件。如你可能在 cpu 目录下看到诸如 cfs_period 和 cfs_quota 这样的配置文件。而这两个配置文件,是限制 CPU 使用率的关键配置项。这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota的 CPU 时间。其中 period 的默认值为 100 ms(毫秒),quota 的默认值为 -1,即不做限制。当修改 quota 的值为 20 ms 时,表示在 100ms 的时间范围内,cpu 只能使用 20 ms。也就是说,cpu 的使用率最大为 20%。 上面说到,容器启动后的进程我们需要用 Linux Cgroups 来限制其资源的访问。接下来我们看看到底是如何进行控制的。我们在 /sys/fs/cgroup/cpu 目录下创建一个文件夹:可以看到,我们创建的文件夹里面已经被系统默认创建了一些配置文件。我们把这样一个目录叫做控制组,接下来修改这个控制组的 cpu使用率为 20% 。我们在命令行用一个死循环来测试,也使得该进程能占用全部的 CPU。通过 top 参数,我们看到该进程 5451 的 cpu 使用率已经达到 99.3%;由于我们创建该进程时,没有为其指定一个控制组时,他默认将享用全部的 cpu 及内存配置。接下老我们将该进程通过下面的命令加入到刚刚创建的 container 组中去。$ echo 5451 > /sys/fs/cgroup/cpu/container/tasks将改进程加入控制组后,改进程的 cpu 使用率一下就从原来的 100% 降到了 20% 左右。在 docker 中,我们可以在启动容器的时候,指定 cpu 参数来控制该容器的资源占用,如下所示,这样启动的 docker 容器,只能使用 20% 的 cpu。Docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash当然,通过 Linux Cgroups 还可以限制其他参数,如网络、挂载点、内存等等。

Cgroups 允许对可用资源设置限制和约束。例如,您可以在一台拥有 16 G 内存的计算机上创建一个 Namespace ,限制其内部进程可用内存为 1 GB。

到这,您可能已经猜到 Docker 的工作原理了。当您请求 Docker 运行容器时,Docker 会在您的计算机上设置一个资源隔离的环境。然后 Docker 会将打包的应用程序和关联的文件复制到 Namespace 内的文件系统中,此时环境的配置就完成了。之后 Docker 会执行您指定的命令运行应用程序。

简而言之,Docker 通过使用 Linux namespace 和 cgroup(以及其他一些命令)来协调配置容器,将应用程序文件复制到为容器分配的磁盘,然后运行启动命令。Docker 还附带了许多其他用于管理容器的工具,例如:列出正在运行的容器,停止容器,发布容器镜像等许多其他工具。

与虚拟机相比,容器更轻量且速度更快,因为它利用了 Linux 底层操作系统在隔离的环境中运行。虚拟机的 hypervisor 创建了一个非常牢固的边界,以防止应用程序突破它,而容器的边界不那么强大。另一个区别是,由于 Namespace 和 Cgroups 功能仅在 Linux 上可用,因此容器无法在其他操作系统上运行。此时您可能想知道 Docker 如何在 macOS 或 Windows 上运行? Docker 实际上使用了一个技巧,并在非 Linux 操作系统上安装 Linux 虚拟机,然后在虚拟机内运行容器。

让我们利用目前为止学到的所有内容,从头开始创建和运行 Docker 容器。如果你还没有将 Docker 安装在你的机器上,可以参考这里[1]安装 Docker。在这个示例中,我们将创建一个 Docker 容器,下载一个用 C语言写的 Web 服务,编译并运行它,然后使用浏览器访问这个 Web 服务。

我们将从所有 Docker 项目开始的地方从创建一个 Dockerfile 开始。此文件描述了如何创建用于运行容器的 Docker 镜像。既然我们还没有聊到镜像,那么让我们看一下镜像的官方定义[2]:

镜像是一个可执行包,其包含运行应用程序所需的代码、运行时、库、环境变量和配置文件,容器是镜像的运行时实例。

简单的讲,当你要求 Docker 运行一个容器时,你必须给它一个包含如下内容的镜像:

包含应用程序及其所有依赖的文件系统快照。

在我们的示例中,我们选择 Alpine Linux 为基础镜像。当您在 Docker 中看到 “alpine” 时,它通常意味着一个精简的基本镜像。 Alpine Linux 镜像大小只有约为5 MB!

在您的计算机创建一个新目录(例如 dockerprj),然后新建一个 Dockerfile 文件。

umermansoor:dockerprj$ touch Dockerfile1

将如下内容粘贴到 Dockerfile:

# Use Alpine Linux rootfs tarball to base our image onFROM alpine:3.9 # Set the working directory to be '/home'WORKDIR '/home'# Setup our application on container's file systemRUN wget http://www.cs.cmu.edu/afs/cs/academic/class/15213-s00/www/class28/tiny.c && apk add build-base && gcc tiny.c -o tiny && echo 'Hello World' >> index.html# Start the web server. This is container's entry pointCMD ["./tiny", "8082"]# Expose port 8082EXPOSE 8082 1234567891011121314151617

这个 Dockerfile 包含创建镜像的内容说明。我们创建镜像基于 Alpine Linux(rootfs tarball),并将工作目录设置为 /home 。接下来下载,编译并创建了一个用 C 编写的简单 Web 服务器的可执行文件,然后指定在运行容器时要执行的命令,并将容器端口 8082 暴露给主机。

现在,我们就可以构建镜像了。在 Dockerfile 的同级目录运行 docker build 命令:

umermansoor:dockerprj$ docker build -t codeahoydocker .

如果这个命令成功了,您将看到:

Successfully tagged codeahoydocker:latest

此时我们的镜像就创建成功了,该镜像主要包括:

  • 文件系统快照(Alpine Linux 和 我们安装的 Web 服务)
  • 启动命令(./tiny 8092)


既然成功构建了镜像,那么我们可以使用如下命令运行容器。

umermansoor:dockerprj$ docker run -p 8082:8082 codeahoydocker:latest

让我们了解下这里发生了什么。

通过 docker run 命令,我们请求 Docker 基于 codeahoydocker:latest 镜像创建和启动一个容器。-p 8082:8082 将本地的 8082 端口映射到容器的 8082 端口(容器内的 Web 服务器正在监听 8082 端口上的连接)。打开你的浏览器并访问 localhost:8082/index.html 。你将可以看到 Hello World 信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值