• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Docker容器化2023版本——引擎

武飞扬头像
数据智能老司机
帮助1

简介

Docker引擎是运行和管理容器的核心软件。我们通常将其简称为Docker。如果您对VMware有一些了解,可以将Docker引擎类比为ESXi。

Docker引擎的设计是模块化的,由许多小型专用组件构建而成。其中大部分组件来自Moby项目(mobyproject.org/),并实现了由Open Container Initiative(OCI)维护的开放标准。

在很多方面,Docker引擎类似于汽车引擎——两者都是模块化的,通过连接许多小型专用部件来创建:

汽车引擎由许多专用部件组成,它们共同协作使汽车运行,如进气歧管、节气门、汽缸、活塞、火花塞、排气歧管等。 Docker引擎由许多专用工具组成,它们共同协作创建和运行容器,如API、镜像构建器、高级运行时、低级运行时、shims等。 在撰写本文时,构成Docker引擎的主要组件包括Docker守护进程、构建系统、containerd、runc,以及各种插件,如网络和卷插件。它们共同创建和运行容器。

学新通

深入探究

当Docker首次发布时,Docker引擎包含两个主要组件:

  1. Docker守护进程(有时简称为“守护进程”)
  2. LXC

Docker守护进程是一个整体的二进制文件,它包含了API、运行时、镜像构建等所有代码。

LXC为守护进程提供了对Linux内核中存在的容器基本构建块的访问。这些构建块包括命名空间和控制组(cgroups)。

学新通

摆脱LXC

对LXC的依赖从一开始就是一个问题。

首先,LXC是特定于Linux的。这对于一个有着多平台愿景的项目来说是一个问题。

其次,依赖外部工具来完成项目核心部分的工作是一个巨大的风险。

因此,Docker公司开发了自己的工具,名为libcontainer,作为LXC的替代品。libcontainer的目标是成为一个与平台无关的工具,为Docker提供访问主机内核中存在的基本容器构建块的能力。

在很久之前的Docker 0.9中,libcontainer取代了LXC成为默认的执行驱动程序。

摆脱单块式Docker守护进程

随着时间的推移,Docker守护进程的单块式本质变得越来越棘手:

  1. 创新困难
  2. 速度变慢
  3. 与生态系统需求不符

Docker公司意识到这些挑战,并开始了一个巨大的工作,以拆分单块式守护进程并模块化它。这项工作的目标是尽可能从守护进程中拆分出大部分功能,并在更小的专门工具中重新实现它。这些专门的工具可以互相替换,同时第三方可以轻松地重用它们来构建其他工具。这个计划遵循了经过验证的Unix哲学,即构建可以组合成更大工具的小而专门的工具。

这个拆分和重构Docker引擎的工作已经将所有的容器执行和容器运行时代码完全从守护进程中移除,并重新设计为小型、专门的工具。

学新通

开放容器倡议(OCI)的影响

在Docker公司拆分守护进程并重构代码的同时,开放容器倡议(OCI)正在制定与容器相关的标准:

  • 镜像规范(Image spec)
  • 容器运行时规范(Container runtime spec)

这两个规范于2017年7月发布了1.0版本,由于稳定性是关键,所以不应该看到太多变化。在撰写本文时,已经添加了第三个规范,用于通过注册表(registries)标准化镜像分发。

Docker公司在创建这些规范方面参与度很高,并贡献了大量代码。

自2016年以来的所有Docker版本都实现了OCI规范。例如,Docker守护进程不再包含任何容器运行时代码,所有容器运行时代码都在单独的OCI兼容层中实现。默认情况下,Docker使用runc来实现这一点。runc是OCI容器运行时规范的参考实现。这在上图中的runc容器运行时层中得到体现。

此外,Docker引擎的containerd组件确保将Docker镜像呈现为有效的OCI捆绑包(bundles),供runc使用。

runc

正如之前提到的,runc是OCI容器运行时规范的参考实现。Docker公司在定义规范和开发runc方面发挥了重要作用。

如果将其他内容剥离,runc是libcontainer的小型、轻量级CLI包装器。请记住,libcontainer最初曾在早期Docker架构中取代了LXC,作为与主机操作系统的接口层。

runc在生命周期中只有一个目标——创建容器。它非常快速。但由于它是一个CLI包装器,它实际上是一个独立的容器运行时工具。这意味着您可以下载并构建二进制文件,从而拥有构建和操作runc(OCI)容器所需的一切。但它非常基础且低级,意味着您无法获得完整Docker引擎所具备的丰富功能。

我们有时说runc在“OCI层”运行。请参见上图。

您可以在以下链接中查看runc的发布信息:

github.com/opencontain…

containerd

作为剥离 Docker 守护程序功能的努力的一部分,所有的容器执行逻辑被剥离并重构为一个名为 containerd(发音为 container-dee)的新工具。它的唯一目的是管理容器的生命周期操作,如启动、停止、暂停、删除等。

containerd 可用作 Linux 和 Windows 的守护程序,在 Docker 的 1.11 版本后就已经在 Linux 上使用。在 Docker 引擎堆栈中,containerd 位于守护程序和 runc 之间的 OCI 层。

正如之前所述,containerd 最初旨在成为一个小巧、轻量级的工具,专注于容器生命周期操作。然而,随着时间的推移,它逐渐扩展并承担了更多功能,如镜像拉取、卷和网络等。

增加更多功能的原因之一是为了在其他项目中更容易使用。例如,在 Kubernetes 中,让 containerd 执行像推送和拉取镜像等操作是有益的。然而,所有额外的功能都是模块化和可选的,这意味着您可以选择想要的部分。因此,在诸如 Kubernetes 等项目中可以包含 containerd,但只选择您的项目需要的部分。

containerd 最初由 Docker, Inc. 开发,并捐赠给了 Cloud Native Computing Foundation (CNCF)。在撰写本文时,containerd 是一个完全成熟的 CNCF 项目,意味着它是稳定的,并且被认为已经准备好投入生产使用。您可以在此处查看最新的发布版本:

github.com/containerd/…

启动新容器(示例)

现在我们已经了解了整体情况和一些历史背景,让我们来详细了解创建新容器的过程。

最常见的启动容器的方式是使用Docker CLI。下面的docker run命令将基于alpine:latest镜像启动一个简单的新容器。

$ docker run --name ctr1 -it alpine:latest sh

当您在Docker CLI中键入类似这样的命令时,Docker客户端会将其转换为适当的API有效载荷,并将其POST到Docker守护程序公开的API端点。

API在守护进程中实现,并可以通过本地套接字或网络进行公开。在Linux上,套接字是/var/run/docker.sock,而在Windows上,它是\pipe\docker_engine。

一旦守护进程收到创建新容器的命令,它会调用containerd。请记住,守护程序不再包含任何创建容器的代码!

守护进程通过gRPC通过CRUD风格的API与containerd进行通信。

尽管名为containerd,但它实际上无法创建容器。它使用runc来完成这个任务。它将所需的Docker镜像转换为OCI包,并告诉runc使用它来创建新的容器。

runc与操作系统内核交互,以汇集创建容器所需的所有结构(命名空间、cgroups等)。容器进程作为runc的子进程启动,一旦启动,runc就会退出。

大功告成!容器现在已经启动。

学新通

新模型的优势

将启动和管理容器的所有逻辑和代码从守护程序中移除,意味着整个容器运行时与Docker守护程序解耦。我们有时称之为“无守护程序容器”,这使得可以在不影响正在运行的容器的情况下对Docker守护程序进行维护和升级。

在旧的模型中,所有的容器运行时逻辑都在守护程序中实现,启动和停止守护程序会导致主机上的所有正在运行的容器停止。这在生产环境中是一个巨大的问题。

幸运的是,这不再是一个问题。

"shim"是什么意思?

在本章的一些图表中,出现了一个“shim”组件。

这个“shim”对于实现无守护进程容器非常重要——即我们刚刚提到的将正在运行的容器与守护进程分离,用于诸如守护进程升级等情况。

我们之前提到,containerd使用runc来创建新的容器。实际上,对于每个创建的容器,它都会分叉出一个新的runc实例。然而,一旦每个容器被创建,runc进程就会退出。这意味着我们可以运行数百个容器,而不必运行数百个runc实例。

一旦容器的父runc进程退出,相关的containerd-shim进程将成为容器的父进程。shim作为容器的父进程执行的一些职责包括:

保持任何STDIN和STDOUT流保持开启,以便在守护进程重新启动时,由于管道被关闭等原因,容器不会终止。 向守护进程报告容器的退出状态。

在Linux上的实现方式

在Linux系统上,我们讨论过的组件分别实现为以下独立的二进制文件:

  • /usr/bin/dockerd(Docker守护进程)
  • /usr/bin/containerd
  • /usr/bin/containerd-shim-runc-v2
  • /usr/bin/runc

您可以通过在Docker主机上运行ps命令来查看所有这些文件。当然,只有在系统上有正在运行的容器时,其中一些文件才会存在。

守护进程的目的是什么?

在守护进程中剥离了所有的执行和运行时代码后,您可能会问一个问题:“守护进程中还剩下什么呢?”。

显然,随着越来越多的功能被剥离和模块化,这个问题的答案会随之改变。然而,在目前的情况下,守护进程仍然能够推送和拉取镜像、实现Docker API、进行身份验证、提供安全性等功能。

在撰写本文时,镜像管理正在逐步从守护进程中剥离,并由containerd来处理。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgcjjkh
系列文章
更多 icon
同类精品
更多 icon
继续加载