,

用通俗易懂的语言解释无根 Podman 用户命名空间

在我个人看来,用户命名空间是无根容器中最令人费解的方面之一。可以说,它的学习曲线和 Kubernetes 一样陡峭。在本文中,我将尝试通过一个易于理解的类比,来降低新 Podman 用户(和转换者)的学习难度。希望这能帮助防止任何重要的“脑汁”从您的耳孔流出。

我的假设是您刚刚接触容器(通常来说),特别是无根 Podman(即作为普通、常规、非特权用户操作)。尽管您如何使用 Podman 在技术上并不重要——直接在命令行上,通过 podman-remote 远程使用,podman-machine,在像 podman-desktop 这样的 GUI 中,或者像 Cockpit 这样的 WebUI 中。我将要阐述的基本概念基本上是通用的。

首先,关于命名空间的一些背景知识。像容器镜像cgroups一样,命名空间是容器的基本组成部分。有几种不同类型的命名空间,涵盖了网络、存储和进程树等领域。您可以将命名空间想象成房子里的基础设施。房子有自己的电气系统、管道、排水系统等。它们都相互独立,各司其职,但由国家或公用事业公司提供和管理。

继续这个类比,房屋基础设施以受控的方式与公用事业服务交互。换句话说,每栋房屋之间都有一定程度的核算和隔离。例如,电表独立记录使用情况,一栋房屋的故障不会影响另一栋房屋。公用事业之间也有一个有用的分离,这样排水管堵塞不会导致保险丝(或断路器)失灵。

这些公用事业服务中的每一个都代表一种不同类型的命名空间,并且(如果还不明显)房屋代表容器。公用事业公司(或国家)对服务的监督和管理代表了来自主机系统的命名空间交互。为了帮助理解用户命名空间,让我们将这个类比扩展到人类居住者及其对分享想法的持续需求。由于每个人从出生起就拥有手机,每个人都可以轻松地相互交流。然而,孩子们很难记住长号码。因此,对于家庭内部通信,让我们发明一种快捷系统,每个人都被分配一个短号码,与他们的手机号码分开。

为进一步方便起见,让我们使用电话号码零作为快速联系电话公司(房子外面)的方式。而在房子内部拨打零则连接到负责支付电话费的人。例如,小比利可以拨打零来给妈妈打电话,妈妈可以拨打零来要求限制比利的短信过度使用。

如果你还在跟着我,你就会意识到我们现在已经制造了一些主要的麻烦:人们的手机号码和快捷号码可能会重叠。换句话说,手机号码123和快捷号码123之间没有明显的区别,但结果可能会因一个房子里的人数与另一个房子里的人数而大相径庭。更糟糕的是,拨打零投诉垃圾电话,使用快捷号码和蜂窝号码会得到截然不同的结果。说到这里,让我们通过简单地限制所有家庭电话只能拨打快捷号码,完全阻止从房子内部访问更广泛的蜂窝网络,来解决垃圾电话问题。

至于号码歧义问题,一个看似明显的解决方案似乎是拥有一本电话簿,记录每个人的姓名、手机号码和快捷号码。然而,电话簿实际上会使问题变得更糟,因为不同房子里的人可能共享相同的姓名和快捷号码。相反,让我们为每所房子保留一个独有的(否则未使用的)手机号码集合。然后,每所房子都可以使用简单的转换方案,将快捷号码转换为这些预留的手机号码,让电话公司满意。此外,如果某个家庭成员设法破解系统并拨打更广泛的蜂窝网络,他们将被阻止,因为他们的手机号码属于未使用的范围。

这一切都变得有点抽象了,让我们用一个简单的例子。贝克街221B的房子,可能被赋予预留的(未使用的)手机号码1000-1999来支持快捷号码。在房子里,如果华生的快捷号码是三,那么在房子外面它将转换为(未使用的)手机号码1002。此外,在这个房子里,快捷号码零将直接转换为分配给夏洛克的手机号码(同样,在房子外面)。通过这种方式,电话公司可以精确地模拟用于其他公用事业的分离和隔离。通信被限制在每栋房子内,并且所有房子之间都有高度的隔离。

回到主机和容器的真实世界,您可以将此手机和快捷方式类比直接应用于无根用户命名空间。您在 /etc/subuid/etc/subgid 中看到的三个值描述了主机上未使用的 ID 的保留范围,这些 ID 将被分配用于容器内部的转换。每个 subuid/subgid 行的第一个项是用户的名称(或组),它将在容器内部转换为 ID 零。第二个数字是主机上未使用 ID 范围的开始,后面跟着分配范围的长度。

所以,就上面贝克街的例子而言,这些主机文件中的一个条目(一个用于 UID,另一个用于 GID)可能是 sherlock:1000:999。这意味着由 Sherlock 启动的容器将拥有一个由主机上的 Sherlock ID 表示的 root 用户(UID/GID 零)(无论这个 ID 是什么)。容器内部的后续 UID/GID(例如 Watson)将简单地(按顺序)转换为主机上从 1000 开始的未使用范围。由于 Watson 在容器中的 ID 是三,这就是为什么他在容器外部被分配了 ID 1002。如果容器中的 ID 尝试超出 999,系统将简单地抛出错误——因为主机端的 ID 分配止于 1999。同样,这里的关键是 UID(和/或 GID)1000-1999 被主机上的任何东西使用——从而保持了系统上所有用户命名空间的限制。

在实际主机上,您通常会在 /etc/subuid/etc/subgid 中找到更大的值。通常,范围长度将设置为 65536,因为大多数 Linux 容器镜像将需要该最小值。无论如何,牢记这些类比,您将能够很好地理解容器命名空间的概念。特别是,快捷方式到手机号码的转换方案完美地反映了用户命名空间的工作方式。当您准备进一步强化这些概念时,我强烈推荐 Dan Walsh 关于控制用户命名空间访问的博客文章。在此之后,对于更实际的例子,Dan 的文章 处理无根容器上的用户命名空间和 SELinux 也非常好。

发表评论

订阅

输入您的电子邮件地址以接收来自本网站的电子邮件更新。

返回

您的消息已发送

警告
警告
警告。

分类


搜索