如何揭开Linux中的命名空间和容器的神秘面纱

集装箱已经席卷全球了。听到这个术语时,无论您想到Kubernetes,Docker,CoreOS,Silverblue还是Flatpak,很明显,现代应用程序都在容器中运行,以提供便利、安全性和可伸缩性。

但是,容器可能会让人困惑。在容器中运行意味着什么?容器中的进程如何与运行它们的其余计算机交互?开源不喜欢谜题,所以本文解释了容器技术的后端,就像我在Flatpak上的文章解释了一个常见的前端一样。

命名空间

命名空间在编程世界中很常见。如果您生活在计算机世界中技术含量很高的地方,那么您可能已经看到过这样的代码:

using namespace std;

或者您可能已经在XML中看到了这一点:

<book xmlns =“ http://docbook.org/ns/docbook” xml:lang =“ zh_CN”>

这些类型的短语为以后在源代码文件中使用的命令提供了上下文。例如,C ++知道程序员在键入cout时意味着什么的唯一原因是因为C ++知道cout命名空间是一个有意义的词。

如果这对于您来说太技术性了,您可能会惊讶地发现,我们现实生活中每天也都使用命名空间。 我们不称它们为命名空间,但我们一直使用该概念。 例如,短语“我是企业的粉丝”在为大型企业提供服务的IT公司(通常称为“企业”)中具有某一种特定的含义,但在科幻小说惯例中它可能具有不同的含义。 问题“它在运行什么引擎?” 在车库中有一种特定的含义,而在Web开发中则有不同的含义。 我们并不总是在随意的对话中阐明命名空间,因为我们是人类,我们的大脑可以快速适应环境,但是对于计算机,必须明确声明该命名空间。

对于容器,名称空间定义了进程对周围运行的其他事物的“意识”的边界。

lsns

您可能没有意识到这一点,但是您的Linux机器维护了特定于给定进程的不同名称空间。 通过使用util-linux软件包的最新版本,您可以列出计算机上的现有的命名空间:

$ lsns
        NS TYPE   NPROCS   PID USER    COMMAND
4026531835 cgroup     85  1571 seth /usr/lib/systemd/systemd --user
4026531836 pid        85  1571 seth /usr/lib/systemd/systemd --user
4026531837 user       80  1571 seth /usr/lib/systemd/systemd --user
4026532601 user        1  6266 seth /usr/lib64/firefox/firefox [...]
4026532928 net         1  7164 seth /usr/lib64/firefox/firefox [...]
[...]

如果您的util-linux版本不提供lsns命令,则可以在/ proc中看到命名空间条目:

$ ls /proc/*/ns
1571
6266
7164
[...]
$ ls /proc/6266/ns
ipc net pid user uts [...]

在Linux机器上运行的每个进程都用进程ID(PID)枚举。每个PID都分配有一个名称空间。同一名称空间中的PID可以相互访问,因为它们被编程为在给定名称空间中运行。默认情况下,不同名称空间中的PID无法相互交互,因为它们在不同的上下文或名称空间中运行。这就是为什么在一个命名空间下的“容器”中运行的进程无法访问其容器外部的信息或在另一个容器内部运行的信息的原因。

创建一个新的名称空间

处理容器的软件的通常功能是自动命名空间管理。启动新的容器化应用程序或环境的人工管理员不必使用lsns来检查存在哪些命名空间,然后手动创建一个新的命名空间。使用PID名称空间的软件会在Linux内核的帮助下自动执行此操作。但是,您可以手动模拟该过程,以更好地了解幕后发生的事情。

首先,您需要确定计算机上未运行的进程。在此示例中,我将使用Z shell(Zsh),因为我正在计算机上运行Bash shell。如果您在计算机上运行Zsh,请使用Bash或tcsh或其他当前未运行的Shell。目的是找到可以证明未运行的东西。您可以使用pidof命令证明某些程序未运行,该命令查询系统以发现您命名的任何应用程序的PID:

$ pidof zsh
$ sudo pidof zsh

Unshare

Unshare命令在与其父进程不共享的命名空间中运行程序。有很多可用的命名空间,因此请阅读unshare手册页以获取所有可用选项。

为测试命令创建新的命名空间:

$ sudo unshare --fork --pid --mount-proc zsh
%

由于Zsh是交互式外壳程序,因此在启动时可以方便地将您带入其命名空间。但并非所有进程都这样做,因为某些进程在后台运行,从而在其本机命名空间中提示您。只要您保持在Zsh会话中,就可以通过查看新的派生进程的PID来看到已经离开了常规的命名空间:

%pidof zsh
pid 1

如果您知道有关Linux进程ID的任何信息,那么您就知道PID 1总是为初始化应用程序保留的,这主要是由启动过程决定的(系统安装在Slackware,Devuan之外的大多数发行版上,并且可能是一些自定义的Arch安装) 。 Zsh或非启动初始化应用程序的任何应用程序几乎不可能成为PID 1(因为没有初始化系统,计算机将不知道如何启动)。然而,据您在本演示中外壳所知,Zsh占用了PID 1插槽。

尽管您的外壳现在告诉您什么,但系统上的PID 1尚未更换。打开计算机上的第二个终端或终端选项卡,然后查看PID 1:

$ ps 1
init

然后找到Zsh的PID:

$ pidof zsh
7723

正如您所看到的,您的“主机”系统看到了全局,并了解到Zsh实际上是以某种高编号的PID运行的(除了巧合,它在计算机上可能不会是7723)。 Zsh将自己视为PID 1只是因为其范围限于其命名空间(或包含在其命名空间内)。将进程分叉到其自己的名称空间后,其子进程将从1开始编号,但仅在该命名空间内。

命名空间以及其他技术(例如cgroups等)构成了容器化的基础。了解命名空间存在于主机环境的更广泛名称空间的上下文中(在本演示中,这是您的计算机,但在现实世界中,主机通常是服务器或混合云)可以帮助您了解容器化应用程序的行为方式和原因他们的方式。例如,运行Wordpress博客的容器并不“知道”它不在容器中运行;而是在容器中运行。它知道它可以访问内核和一些RAM以及您提供的任何配置文件,但是它可能无法访问您的主目录或您未明确授予其访问权限的任何目录。此外,该博客软件中的失控进程不会影响您系统上的任何其他进程,因为就其所知,PID“树”仅返回1,而1是运行它的容器。

容器是Linux的强大功能,并且每天都在变得越来越流行。既然您了解了它们的工作原理,请尝试探索诸如Kubernetes,Silverblue或Flatpak之类的容器技术,并看看如何使用容器化应用程序。容器是Linux,因此请启动它们,仔细地观察,再不断学习。

原文链接:https://opensource.com/article/19/10/namespaces-and-containers-linux

原文作者:Seth Kenlon

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券