容器现在是内核里的“系统实例”:宿主机是 0 号实例,每个容器是一台自己的小机器,有自己的 1 号进程和进程号、出不去的根目录、自己的 /proc、/dev 和终端、主机名、内存 / 线程 / CPU / 磁盘 / 文件数预算。根目录可以是普通目录,也可以是叠加视图(只读的镜像层加一个可写层,按 Linux overlayfs 的盘上写法)。新的 containers 模块按设置建立、启动、停止、按策略重启容器,宿主机重启或模块替换后接着管。
| 步骤 | 内容 | 验收 |
|---|---|---|
| M7a.1 内核 | 系统实例:自己的进程号(第一个是 1,孤儿归 1 号,1 号只收它处理的信号,1 号结束实例就停);出不去的根(chroot 之后 .. 也出不去);预算:内存按实例计页(宿主机不计,没有开销),超了结束实例里最大的进程;线程数;CPU 按 100 ms 窗口限制;管理接口 instance_*、updater 的 inst 命令 | 实例里的 1 号进程自己检查 24 项(进程号、孤儿、信号、只看得到自己的进程、kill(-1) 的范围、根、线程和内存预算);外面:宿主机进程不受影响、CPU 预算 25% 实测 25.0%、运行中替换 linux 模块、停止和再启动 |
| M7a.2 文件 | ext4 扩展属性(Linux 的格式,共用的属性块先复制);ext4 项目配额(标准的 project + quota 特性和配额文件,经过日志写);每个实例自己的挂载表、/dev(只有允许的设备)、/dev/pts、/proc 的视图、statfs(df 看到的是自己的磁盘预算);叠加的根(多层,复制上来、删除标记、不透明目录);VFS 交接格式 5;images 工具保留层里的扩展属性 | e2fsck 检查我们写的镜像;Linux 写的属性和配额我们读得对;Linux 带 prjquota 挂载后继续写,用量一致;实例里写到 2 MiB 预算得到 EDQUOT、建到 40 个文件得到 EDQUOT;叠加根上同样的检查都过;Linux 的 overlayfs 挂同样的层,看到的一样 |
| M7a.3 兼容层 | uname 和 /proc 的主机名是实例的(sethostname 改,每次启动回到设定的);实例里 reboot(2) 只停这个实例并标成要重启;sysinfo 是实例的内存和开机时间;实例里不能建设备节点;抽象 Unix 套接字名按实例分开 | insttest 的这些检查;实例里 reboot 后停下并标成要重启 |
| M7a.4 containers 模块 | 按设置 ct.<名字>.* 建立和启动容器;停止先发 SIGTERM,超时后结束;重启策略 no / always / on-failure / unless-stopped(连续结束时等待加长);预算、状态改了直接生效,别的改了重建;1 号进程的输出写到日志文件 | containers_test 39 项:外面结束后按策略回来、按设置停止(1 号进程忽略 SIGTERM,2 s 后结束)、预算直接生效、改主机名重建、替换模块不影响运行中的容器、restart=no、实例里 reboot 后再启动、宿主机重启后回来、删设置就删容器、日志文件里有输出 |
| 测试中发现并修好 | 我们的 ext4 读不了 Linux 内核自己建的大目录(哈希索引的根块尾部留着像普通目录块校验尾的旧字节,我们把块当成短了 12 字节)。以前的测试只用过 mke2fs 和我们自己建的目录 | 新单元测试:Linux 内核建的 1045 项目录完整读出、逐个查得到 |
instance.rs;ProcHost 加了实例、根、进程号换算、主机名、reboot;Syscalls::start;Admin::instance_*;At::jail;VfsHost::instance / hostname;Vfs 加了扩展属性、项目配额、按实例卸载、叠加挂载、statfs;Filesystem 加了扩展属性和项目配额。tune2fs -O ^quota,^project 关掉(或以后加一个关闭命令)。| 缺口 | 打算 |
|---|---|
| instance_test 在单独跑的 5 次里失败过 1 次(叠加根上 insttest 的检查),日志没留下 | 测试现在失败时打印具体的检查、等待时间放到 120 s;再出现就能定位 |
| 用户编号段只记录了,没有做编号映射(实例里的文件用自己的编号;宿主机目录挂进实例要映射) | M7b 做数据卷时 |
| /dev/shm、/dev/mqueue 是只读的空目录(没有 tmpfs) | 需要的程序出现时加 tmpfs |
| Docker 式命令行、compose、镜像工具随发布分发、端口映射接到容器 | M7b |
| 快照、systemd 当 1 号进程、实例嵌套 | 按路线文档的顺序 |
M7a 是否发布:内核改了,部署时重启一次,所有模块重装,新模块 containers。两台生产机上没有实例时什么都不会变(配额不会打开)。之后按计划是 M7b(Docker 式命令行和 compose,带端口映射,以及和 Docker 不同之处的说明)。