这里 说 的 容器 是 操作系统 层 的 容器,   比如  ixc 、Docker     这种  。

 

容器,  有 自己 的 硬件资源,    可以 给 每个 容器 分配 指定 的 硬件资源 ,   容器 和 容器 之间 是 隔离 的 ,   隔离 是指 一个 容器 里 的 应用程序 不能 访问 到 另一个 容器 的 资源  , 容器 和 容器 之间 就像 一个个 独立 的 计算机 和 操作系统  。

 

对 使用者 来说,   容器 提供 的 接口 和 操作系统 一样,     所以 容器 也是 一个 虚拟操作系统  。

 

 

这就是 容器,   可以用 容器 实现 虚拟化,     或者说,   可以 把 容器 当 虚拟机 用  。

 

 

了解了 容器 的 功能,    那么,   要 怎么 实现 容器 呢  ?

 

我 提出 2 个 方案 :

 

方案一 ,  进程组

方案二 ,  进程

 

 

方案一 是 把 容器 当成 一个 进程组,   方案二 是 把  容器 当成 一个 进程  。

 

 

先来 看看 方案一,       上面说到 容器 有 自己 的 硬件资源,  这些 “硬件资源”  不是 直接 的 硬件资源,  而是 经过 操作系统 抽象 的,  比如  虚拟内存,  文件系统  。

 

虚拟内存 由 内存 和 外存 组成,     文件系统 对应 的 硬件 是 硬盘 、光盘 、U 盘,   文件系统 是 对 硬盘 、光盘 、U 盘 等  外部存储器  的 抽象  。

 

具体 的 ,   容器 的 资源 有 :

 

1   CPU,      按 占用率 算

2   虚拟内存,       按 存储空间 和 地址空间 算,   存储空间 表示 大小,  地址空间 表示 范围,     地址空间 用于 容器 间 的 隔离

3   文件系统,       每个 容器 有 一个 虚拟 的 文件系统,   比如 每个 容器  有 自己 的 C 盘 、D 盘 、E 盘   ……

4   虚拟 IP,          每个 容器 都有 一个 自己 的 IP,    甚至 可以 有 多个 IP,    这些 IP 都是 虚拟 IP,   是 从 操作系统 的 IP 协议 里 虚拟出来的,   而 操作系统 的 IP 协议 的 底层 是 物理网卡  。        如果 认为 一个 IP 对应 一个 网卡,   那么  也可以 认为 容器 有 一个 或 多个 虚拟网卡  。

 

 

设计 容器,   就是 要 设计 怎样  分配 和 隔离   CPU 、虚拟内存 、文件系统 、虚拟 IP   这 4 项 资源   。

 

 

在 方案一 里 ,   容器 是 一个 进程组,    这些 进程 都是 操作系统 里 的 普通 的 进程,    只要 让 这些 进程 的 CPU 占用率 总和 不超过  分配 的 大小 就可以  。

 

这 在 操作系统 的 进程调度 里 可以实现 。   就是 在 进程调度 的 时候,   考虑 给 哪个进程 分配时间片 的 时候,   计算 和 判断 一下 容器 里 的 进程 的 CPU 占用率 总和  就可以了  。

 

这 对 操作系统 的 进程调度 部分 的 代码 稍作修改 就可以  。      也就是 对 操作系统 的 内核代码 稍作修改 就可以  。

 

 

长话短说  。    方案二  进程 的 方式 可能 行不通  。     一个 进程 作为 一个 容器,  则 容器 里 的 进程 就是 “进程 里 的 进程”  ,   这 需要 容器 把  操作系统 管理进程 的 部分 都实现一遍,  还有 进程 和 操作系统 之间 的 接口 比如 系统调用 等 都要 实现一遍,    这 呵呵 了  。

 

还是 方案一 进程组 的 方式  好  。

 

进程组 的 话,   实现 容器 很简单,     就是 把 操作系统 内核代码 改一下,   把 对 容器 (进程组) 的  CPU 使用率 的 管理 加到 进程调度 的 代码 里 ,

 

内存隔离 也不用做什么,   在 操作系统 里,  不管 进程 是不是 同一个 进程组(容器),   都不允许 访问 其它 进程 的 内存空间,    如果 尝试访问 就是 越界, 抛出异常, 进程 可能 中止  。

 

也就是,   进程 的 内存 都是 隔离 的,    容器(进程组) 的 内存 自然 的 就是 隔离 的  。

 

唯一 要 考虑 的 是,  当 发生 越界时,   异常信息 要不要 区分 同一个容器内 的 进程 间 的 越界,   还是 两个 容器 (的 进程) 间 的 越界,   如果 不区分 异常信息,  那 什么都不用做  。

 

如果 要 区分 异常信息,   那可能要 硬件支持 和 修改 操作系统 内核代码  。     硬件支持 指 存储管理部件 也要支持 在 进程 之上 还有个 “进程组”,   这样 当 越界 抛出 硬件中断 时, 可以知道  是 哪一个 进程组(容器) 的 哪一个 进程 发生了 越界,    以及 越界访问 的 是不是 另一个 进程组(容器) 的 内存空间  。

 

同时,也要 修改 操作系统 内核代码,    这里 修改 的 内核代码 是   虚拟内存 模块  ,   操作系统 对 存储管理部件  设置 页表 时 要 设置 进程组  。  也就是,  本来,操作系统 设置 页表 会 设置  页 和 进程 的 对应关系,  当然 还有 页 和 物理内存页 的 对应关系,  现在,  还要 加上 设置 进程 和 进程组 的 对应关系  。

 

另一方面,  当 越界时,  存储管理部件 抛出 越界中断,    操作系统 要 读取 引发越界 和 被越界 的 2 个进程组 的  ID  。

 

但,   就为了 在 越界 的 异常信息 里 知道 是不是 跨容器 的 越界,    要 搞这么多 周折,    这也不至于吧 ?

 

 

真正 要 硬件支持 内存隔离 的 应该是 虚拟机 (VMWare,  HyperVisor,  XGetn,   指令映射,   虚拟指令 ?) ,    由此看来,  容器 确实 轻量 很多  。

 

 

外部存储器 (硬盘) 的  隔离(划分) 就 更简单了,  把 一个 文件夹(及其 子文件夹)  虚拟为 一个 盘(分区),    就行了  。

 

这也要 修改  内核代码,    修改的是  文件系统 模块  。

 

 

容器 对  计算机(硬件 / 系统) 资源 的 隔离 和 分配 最基本 的 就是    CPU 内存 外存 这 3 样,   现在,  这 3 样 的 隔离 和 分配 都 解决了  。

 

我刚 看了 本文 开头,  是 4 样,   还有 网卡, 也就是 虚拟 IP ,    这个,   就 改一下  网络协议 模块,  也就是 Socket 模块 吧  。

 

 

我听 网友 (还是 文章?)  说,   容器 是 共用一个 内核 的  。    看起来,  还真是  。

 

 

我 之前 看过 一篇 文章 里 的 一段文字,     有人 跟 Linus 说 ,  容器 现在 做的 怎么怎么样了 ,   Linus 说,  我不管你们什么容器,   我只要 把 我的 内核 做好就好  。

 

由此看来,   容器 是 在 开源文化 和 开源技术 上,    对  Linux 的 内核 修改 而来  。

 

 

如果 操作系统 是  你 写 的,    在 这个 操作系统 里 改 一个 容器 出来 很容易  。      就跟 开发业务系统,   老板 说 “喂 ,  商品 能不能分个组 ?  客户 能不能分个组 ?  权限 能不能分个组?  用户 能不能分个组(角色)?”     一样,    差不多了  。

 

如果很闲,   三五 个 人,    拿来一个 硬件,   为 它 写一个 操作系统 也 很容易  。    什么硬件 ?   比如 单片机,   这 有点老套 ,  那就 手机 吧 !

 

在 这个年代,   手机 很接地气,      拿一个手机,   把 它 当成 一个 裸机,   写一个 程序 启动 它 吧,   把 它 (的 显示屏) 点亮 吧  !