在之前的文章中,我写过关于 容器镜像 和 运行时 的文章。在本文中,我将探讨容器是如何通过一些特殊的 Linux 技术(包括命名空间和控制组)的基础实现的。

图 1:构成容器的 Linux 技术
Linux 技术构成了在您的系统上构建和运行容器进程的基础。技术包括
- 命名空间
- 控制组 (cgroups)
- Seccomp
- SELinux
命名空间
命名空间 通过为容器提供看似其自己的 Linux 文件系统的视图,为容器提供隔离层。这限制了进程可以看到的内容,从而限制了可供其使用的资源。
在 Linux 内核中,Docker 或 Podman 等在创建容器时使用了多个命名空间
$ docker container run alpine ping 8.8.8.8
$ sudo lsns -p 29413
NS TYPE NPROCS PID USER COMMAND
4026531835 cgroup 299 1 root /usr/lib/systemd/systemd --
switched...
4026533105 mnt 1 29413 root ping 8.8.8.8
4026533106 uts 1 29413 root ping 8.8.8.8
4026533105 ipc 1 29413 root ping 8.8.8.8
[...]
用户
用户命名空间隔离容器内的用户和组。这是通过允许容器具有与主机系统不同的 UID 和 GID 范围视图来完成的。用户命名空间使软件能够在容器内以 root 用户身份运行。如果入侵者攻击容器然后逃逸到主机,他们将被限制为仅具有非 root 身份。
Mnt
mnt 命名空间允许容器拥有其自己的系统文件系统层次结构视图。您可以在 Linux 系统中的 /proc/<PID>/mounts 位置找到每个容器进程的挂载点。
UTS
Unix 分时系统 (UTS) 命名空间允许容器拥有唯一的主机名和域名。当您运行容器时,即使使用 — name
标签,也会使用随机 ID 作为主机名。您可以使用 unshare
命令 来了解这是如何工作的。
$ docker container run -it --name nived alpine sh
/ # hostname
9c9a5edabdd6
/ #
$ sudo unshare -u sh
# hostname isolated.hostname
# hostname
# exit
$ hostname
homelab.redhat.com
IPC
进程间通信 (IPC) 命名空间允许不同的容器进程通过访问共享内存范围或使用共享消息队列进行通信。
# ipcmk -M 10M
Shared memory id: 0
# ipcmk -M 20M
Shared memory id: 1
# ipcs
---- Message Queues ----
key msqid owner perms used-bytes messages
---- Shared Memory Segments
key shmid owner perms bytes nattch status
0xd1df416a 0 root 644 10485760 0
0xbd487a9d 1 root 644 20971520 0
[...]
PID
进程 ID (PID) 命名空间确保容器内运行的进程与外部世界隔离。当您在容器内运行 ps
命令时,由于此命名空间,您只会看到容器内运行的进程,而不会看到主机上的进程。
Net
网络命名空间允许容器拥有其自己的网络接口、IP 地址、路由表、端口号等的视图。容器如何能够与外部世界通信?您创建的所有容器都连接到一个特殊的虚拟网络接口以进行通信。
控制组 (cgroups)
Cgroups 是构成容器的基本构建块。cgroup 分配和限制容器使用的资源,例如 CPU、内存、网络 I/O。容器引擎自动创建每种类型的 cgroup 文件系统,并在容器运行时为每个容器设置值。
SECCOMP
Seccomp 基本上代表 安全计算。它是一个 Linux 功能,用于限制应用程序允许进行的系统调用集。例如,Docker 的默认 seccomp 配置文件禁用大约 44 个系统调用(超过 300 个可用)。
这里的想法是仅向容器提供容器可能需要的那些资源的访问权限。例如,如果您不需要容器更改主机上的时钟时间,您可能不需要 clock_adjtime 和 clock_settime 系统调用,并且阻止它们是有意义的。同样,您不希望容器更改内核模块,因此它们无需进行 create_module、delete_module 系统调用。
SELinux
SELinux 代表 安全增强型 Linux。如果您在主机上运行 Red Hat 发行版,则默认情况下启用 SELinux。SELinux 允许您限制应用程序仅访问其自己的文件,并阻止任何其他进程访问它们。因此,如果应用程序受到威胁,它将限制它可以影响或控制的文件数量。它通过为文件和进程设置上下文,并通过定义策略来强制执行进程可以看到和更改的内容来实现这一点。
容器的 SELinux 策略由 container-selinux
软件包定义。默认情况下,容器使用 container_t 标签运行,并允许在 /usr 目录下读取 (r) 和执行 (x),并从 /etc 目录读取大部分内容。标签 container_var_lib_t 对于与容器相关的文件很常见。
总结
容器是当今 IT 基础设施的关键组成部分,也是一项非常有趣的技术。即使您的角色不直接涉及容器化,了解一些基本的容器概念和方法也能让您体会到它们如何帮助您的组织。容器构建在开源 Linux 技术之上这一事实使它们更加出色!
本文基于一篇 techbeatly 文章,并已获得许可进行改编。
评论已关闭。