本文翻译自 https://www.annwan.me/computers/what-why-how-containers。
副标题:UNIX 和 Linux 系统中的操作系统级虚拟化史
本文是 Handmade Network 学习 Jam 2024 活动的一部分。
问题
这一切都起源于 chroot
(UNIX, 1982)
$ apropos chroot
chroot (1) - run command or interactive shell with special root directory
chroot (2) - change root directory
译:
chroot (1) - 使用特定根目录运行命令或交互式 shell chroot (2) - 更改根目录
Chroot 是一种自 UNIX 早期版本就存在的内核机制,可以用来在运行一个程序时给程序分配一个别的目录作为进程的根目录(也就是/
),让这个进程共享内核和硬件,但只能访问文件系统的子目录。
FreeBSD 上的 Jails (FreeBSD, 2000)
FreeBSD Jails 在 chroot 基础的进一步开发,添加了隔离和控制除文件系统外的其他系统资源的机制。
最终结果是一个完整的容器实现内核机制:
- 完全隔离的用户空间(根据 Jail 的具体配置而有所不同)
- 与主机共用同一内核
快速插曲:cgroups (Linux, 2007, 2016 年重大更新)
cgroups 是 Linux 中的一种机制,可以控制一个进程(及其子进程)可以使用多少系统资源。它最初不是为虚拟化而设计的,而是用于防止进程争夺硬件,并实现配额。但人们发现它用在实现容器上非常好用。
namespaces (Linux, 2002 年开始)
namespaces 可以用来将一部分进程与外部隔离,以便针对特定的全局资源(如挂载点、进程 ID、用户 ID、进程间通信、网络或时间)进行隔离。
更重要的是,它可以和 cgroups 组合使用,可以在 cgroups 之间进行隔离,给人一种系统上独立存在的错觉。
如何创建一个 Linux 容器
有了这些机制(chroot、cgroups 和 namespaces),造一个理论上的容器轮子就相对很简单了:
- 首先,准备好容器可以访问的子目录,准备 chroot 进去
- 然后,为所有需要隔离的东西创建 namespaces(通常至少包括 PID、UID、挂载点和 cgroups )
- 最后,在 namespaces 内运行你的容器化进程,并将其 chroot 到子目录中
结论
你当然不需要从头开始造容器轮子,已经有人开发了具有更友好用户界面的容器管理系统。其中包括 Docker、LXC 和 systemd-nspawn,这些只是其中一些,可能有一款正好符合你的需求。