不止 Docker:8 款容器管理开源方案
Docker 诞生于 2013 年,并普及了容器的概念,以至于大多数人仍然将容器的概念等同于“Docker 容器”。
作为第一个吃螃蟹的人,Docker 设置了新加入者必须遵守的标准。例如,Docker 有一个大型系统镜像库。所有的替代方案都必须使用相同的镜像格式,同时试图改变 Docker 所基于的整个堆栈的一个或多个部分。
在此期间,出现了新的容器标准,容器生态系统朝着不同方向发展。现在除了 Docker 之外,还有很多方法可以使用容器。
在本文中,我们将介绍以下内容:
-
将 Chroot、cgroups 和命名空间作为容器的技术基础
-
定义 Docker 所基于的软件堆栈
-
说明 Docker 和 Kubernetes 需要坚持和遵守的标准
-
介绍替代解决方案,这些解决方案尝试使用具有更好更安全的组件来替换原始 Docker 容器。
容器的软件堆栈
像 Chroot 调用、 cgroups 和命名空间等 Linux 特性帮助容器在与所有其他进程隔离的情况下运行,从而保证运行时的安全性。
Chroot
所有类似 Docker 的技术都起源于类似 Unix 操作系统(OS)的根目录。在根目录上方是根文件系统和其他目录。
从长远来看,这是很危险的,因为根目录中任何不需要的删除都会影响整个操作系统。这就是为什么存在一个系统调用 chroot()。它创建了额外的根目录,例如一个用于运行遗留软件,另一个用于包含数据库等等。
对于所有这些环境,chroot 似乎是一个真正的根目录,而是实际上,它只是将路径名添加到任何以/开头的名字上。真正的根目录仍然存在,并且任何进程都可以引用指定根目录以外的任何位置。
Linux cgroups
自 2008 年 2.6.24 版本以来,Control groups (cgroups)一直是 Linux 内核的一项功能。Cgroup 将同时限制、隔离和测量多个进程的系统资源(内存、CPU、网络和 I/O)使用情况。
假设我们想阻止用户从服务器发送大量电子邮件。我们创建了一个内存限制为 1GB、CPU 占用率为 50%的 cgroup,并将应用程序的 processid 添加到该组中。当达到这些限制时,系统将限制电子邮件发送过程。它甚至可能终止进程,这取决于托管策略。
Namespaces
Linux 命名空间是另一个有用的抽象层。命名空间允许我们拥有许多进程层次,每个层次都有自己的嵌套“子树(subtree)”。命名空间可以使用全局资源,并将其呈现给其成员,就像它是自己的资源一样。
具体来看,Linux 系统开始时的进程标识符(PID)为 1,并且所有其他进程将包含在其树中。PID 命名空间允许我们跨越一棵新树,它拥有自己的 PID 1 进程。现在有两个值为 1 的 PID,每个命名空间可以产生自己的命名空间,并且相同的过程可以附加了几个 PID。
子命名空间中的一个进程将不知道父级的进程存在,而父命名空间将可以访问整个子命名空间。
有七种类型的名称空间:cgroup、IPC、网络、mount、PID、用户和 UTS。
Network Namespace
一些资源是稀缺的。按照惯例,有些端口具有预定义的角色,不应用于其他任何用途:端口 80 仅服务于 HTTP 调用,端口 443 仅服务于 HTTPS 调用等等。在共享主机环境中,两个或多个站点可以监听来自端口 80 的 HTTP 请求。第一个获得该端口的站点不允许任何其他应用程序访问该端口上的数据。第一个应用程序在互联网上是可见的,而其他所有应用程序将不可见。
解决方案是使用网络命名空间,通过网络命名空间,内部进程将看到不同的网络接口。
在一个网络命名空间中,同一端口可以是开放的,而在另一个网络命名空间中,可以关闭该端口。为此,我们必须采用额外的“虚拟”网络接口,这些接口同时属于多个命名空间。中间还必须有一个路由器进程,将到达物理设备的请求连接到相应的名称空间和其中的进程。
复杂吗?这就是为什么 Docker 和类似工具如此受欢迎。现在让我们来介绍一下 Docker,以及它的替代方案。
Docker: 人人可用的容器
在容器统治云计算世界之前,虚拟机非常流行。如果你有一台 Windows 机器,但想为 iOS 开发移动应用程序,你可以购买一台新的 Mac,或者将其虚拟机安装到 Windows 硬件上。虚拟机也可能是笨重的,它们经常吞噬不需要的资源,而且启动速度通常很慢(长达一分钟)。
容器是标准软件单元,具有运行程序所需的一切:操作系统、数据库、镜像、图标,软件库、代码和所需的其他组件。容器的运行也与所有其他容器,甚至与操作系统本身隔离。与虚拟机相比,容器是轻量级的,所以它们可以快速启动,并且容易被替换。
要运行隔离和保护,容器需要基于 Chroot、cgroups 和命名空间。
容器的镜像是在实际机器上形成应用程序的模板,能够根据单个镜像创建尽可能多的容器,一个名为 Dockerfile 的文本文件包含了组装镜像所需的所有信息。
Docker 带来的真正革命是创建了 Docker 镜像仓库和开发了 Docker 引擎,这些镜像以相同的方式在各地运行,作为第一个被广泛采用的容器镜像,形成了一个不成文的世界标准,所有后来的入局者都必须关注它。
CRI and OCI
请注意,Containerd 和 CRI-O 都坚持 CRI 和 OCI 规范。对于 Kubernetes 而言,这意味着它可以使用 Containerd 或 CRI-O,而用户不会注意到其中的区别。它还可以使用我们现在要提到的任何其他替代方案——这正是创建和采用了 OCI 和 CRI 等软件标准的目标。
Docker 软件堆栈
Docker 的软件堆栈包括:
-
docker-cli,面向开发者的 Docker 命令行界面
-
containerd,最初由 Docker 编写,后来作为一个独立的项目启动; 它实现了 CRI 规范
-
runc,它实现了 OCI 规范
-
容器(使用 chroot、cgroups、命名空间等)
Kubernetes 的软件堆栈几乎是相同的;Kubernetes 使用 CRI-O,而不是 Containerd,这是由 Red Hat / IBM 和其他人创建的 CRI 实现。
containerd
Google 的 gVisor 创建包含自己内核的容器。它通过名为 runsc 的项目实现 OCI,该项目与 Docker 和 Kubernetes 集成。有自己内核的容器比没有内核的容器更安全,但它不是万能的,而且这种方法在资源使用上要付出代价。
今天它支持 runc 和 Kata Containers 作为容器运行时,但也可以插入任何其他 OC 兼容的运行时(至少在理论上)。
它是一个 CNCF 孵化项目。
Podman
Podman 是一个没有守护进程的 Docker 替代品。它的命令有意与 Docker 尽可能兼容,以至于您可以在 CLI 界面中创建一个别名并开始使用单词“Docker”而不是“podman”。
Podman 的目标是取代 Docker,因此坚持使用相同的命令集是有意义的。Podman 试图改进 Docker 中的两个问题。
首先,Docker 总是使用内部守护进程执行。守护进程是在后台运行的单进程。如果它失败了,整个系统就会失败。
第二,Docker 作为后台进程运行,具有 root 权限,所以当你给一个新的用户访问权时,你实际上是给了整个服务器的访问权。
Podman 是一个远程 Linux 客户端,可直接从操作系统运行容器。你也可以以 rootless 模式运行它们。它从 DockerHub 下载镜像,并以与 Docker 完全相同的方式运行它们,具有完全相同的命令。
Podman 以 root 以外的用户身份运行命令和镜像,所以它比 Docker 更安全。另一方面,有许多为 Docker 开发的工具在 Podman 上是不可用的,如 Portainer 和 Watchtower。摆脱 Docker 意味着放弃你之前建立的工作流程。
Podman 的目录结构与 buildah、skopeo 和 CRI-I 类似。它的 Pod 也非常类似于 KubernetesPod。
Linux 容器:LXC 和 LXD
LXC(LinuX Containers)于 2008 年推出,是 Linux 上第一个上游内核的容器。Docker 的第一个版本使用了 LXC,但在后来的发展中,由于已经实现了 runc,所以 LXC 被移除了。
LXC 的目标是使用一个 Linux 内核在一个控制主机上运行多个隔离的 Linux 虚拟环境。为此,它使用了 cgroups 功能,而不需要启动任何虚拟机;它还使用命名空间,将应用程序与底层系统完全隔离。
LXC 旨在创建系统容器,几乎就像你在虚拟机中一样——但硬件开销很小,因为这些硬件是被虚拟化的。
LXC 不模拟硬件和软件包,只包含需要的应用程序,所以它几乎以裸机速度执行。相反,虚拟机包含整个操作系统,然后模拟硬件,如硬盘、虚拟处理器和网络接口。
所以,LXC 是小而快的,而虚拟机是大而慢的。另一方面,虚拟环境不能被打包成现成的、可快速部署的机器,而且很难通过 GUI 管理控制台进行管理。LXC 要求技术人员有很高的技术水平,并且优化后的机器可能与其他环境不兼容。
LXC VS Docker
LXC 就像 Linux 上的一个增压 chroot,它产生的“小”服务器启动更快,需要更少的 RAM。然而,Docker 提供了更多特性:
-
跨机器的可移植部署:使用一个版本的 Docker 创建的对象可以传输并安装到任何其他支持 Docker 的 Linux 主机上。
-
版本控制:Docker 可以用一种类似 git 的方式跟踪版本——您可以创建容器的新版本,将它们回滚等等。
-
重复使用组件:使用 Docker,您可以将已经创建的包堆叠到新包中。如果您想要一个 LAMP 环境,可以安装一次它的组件,然后将它们作为预先制作的 LAMP 镜像重新使用。
-
Docker 镜像存档:可以从专用站点下载数十万个 Docker 镜像,并且很容易将新镜像上传到这样的镜像仓库中。
LXC 面向系统管理员,而 Docker 更面向开发人员。这就是 Docker 更受欢迎的原因所在。
LXD
LXD 有一个特权守护进程,它通过本地 UNIX socket 和网络(如果启用)公开 REST API。您可以通过命令行工具访问它,但它总是使用 REST API 调用进行通信。无论客户端是在本地机器上还是在远程服务器上,它的功能都是一样的。
LXD 可以从一台本地机器扩展到几千台远程机器。与 Docker 类似,它是基于镜像的,所有更流行的 Linux 发行版都可以使用镜像。Ubuntu 的公司 Canonical 正在资助 LXD 的开发,因此它将始终运行在 Ubuntu 以及其他类似 Linux 操作系统的最新版本上。LXD 可以与 OpenNebula 和 OpenStack 标准无缝集成。
从技术上讲,LXD 是站在 LXC 的肩膀上(两者都使用相同的 liblxc 库和 Go 语言创建容器),但 LXD 的目标是改善用户体验。
Docker 会永远存在吗?
Docker 拥有 1100 万开发者、700 万个应用程序和每月 130 亿次的镜像下载。如果仅仅说 Docker 仍然是领导,那就太轻描淡写了。然而,在这篇文章中,我们已经看到,现在已经有许多产品可以取代 Docker 软件栈的一个或多个部分,并且通常情况下没有兼容性问题。而且与 Docker 提供的服务相比,其他软件的主要目标是安全性。
本文转载自:RancherLabs(ID:RancherLabs)
原文链接:不止Docker:8款容器管理开源方案
本文文字及图片出自 InfoQ
共有 1 条讨论