一、容器的实质(特殊进程)
二、隔离与限制
namespaces是为了模仿虚拟机的”看”,cgroups是为了模仿虚拟机的”用”。namespace解决可见性问题,cgroup解决资源隔离问题。
namespces(隔离)
概念:是一种资源逻辑隔离机制。
它的“视线”被系统做了限制,只看”看到”某些指定的内容。对于宿主机来说,这些被“隔离”的进程跟其他进程没有太大区别。
Docker本身并没有对应用进程进行隔离,也没有创建所谓的“容器”,而是通过宿主机的操作系统通过namespace对应用进程进行隔离,通过cgroups对被隔离的应用进程限制相关资源属性。(namespace是对进程的隔离,cgroup是对系统资源的隔离)
虚拟机与容器的区别:
虚拟机需要借助GuestOS才能运行应用,容器实际上就是OS的进程,一组文件和运行环境,更加简单。相对而言更精细一些。
性能优势:
敏捷”和“高性能”是容器相较于虚拟机最大的优势。(敏捷是指快速打包,快速发布;高性能是指容器进程本来就是系统里的普通进程,没有虚拟化层的性能损失。 但缺点是没有虚拟化层的隔离性,隔离不彻底)
不能被隔离的资源:内核和时间,在容器中使用settimeofday(2)可以修改时间,但是修改完之后会同步到宿主机
隔离性
- 查看当前系统的 namespace:lsns –t
- 查看某进程的 namespace:ls -la /proc/
/ns/ 进入某 namespace 运行命令:nsenter -t
-n ip addr Pid namespace
不同用户的进程就是通过 Pid namespace 隔离开的,且不同 namespace 中可以有相同 Pid。
有了 Pid namespace, 每个 namespace 中的 Pid 能够相互隔离。
net namespace
网络隔离是通过 net namespace 实现的, 每个 net namespace 有独立的 network devices, IPaddresses, IP routing tables, /proc/net 目录。
Docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge: docker0 连接在一起。
ipc namespace
Container 中进程交互还是采用 linux 常见的进程间交互方法 (interprocess communication – IPC), 包括常见的信号量、消息队列和共享内存。
container 的进程间交互实际上还是 host上 具有相同 Pid namespace 中的进程间交互,因此需要在 IPC资源申请时加入 namespace 信息 - 每个 IPC 资源有一个唯一的 32 位 ID。
mnt namespce
mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看
到的文件目录就被隔离开了。uts namespace
UTS(“UNIX Time-sharing System”) namespace允许每个 container 拥有独立的 hostname 和
domain name, 使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。user namespace
每个 container 可以有不同的 user 和 group id, 也就是说可以在 container 内部用 container 内部的用户
执行程序而非 Host 上的用户。cgroups(限制)
cgroups就是一个子系统目录加上一组资源限制文件的组合。
- 资源限制:限制任务使用的资源总额,并在超过这个配额时发出提示。
- 优先级分配:分配CPU时间片数量及磁盘 IO 带宽大小、控制任务运行的优先级。
- 资源统计:统计系统资源使用量,如 CPU 使用时长、内存用量等。
- 任务控制:对任务执行挂起、恢复等操作。 ```shell
$ mount -t cgroup cpuset on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cpu on /sys/fs/cgroup/cpu type cgroup (rw,nosuid,nodev,noexec,relatime,cpu) cpuacct on /sys/fs/cgroup/cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct) blkio on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio) memory on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) …
$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
```
作用:限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
cgroups 是Linux内核提供的一种可以限制单个进程或者多个进程所使用资源的机制
Cgroups每个一个子系统都有独有的资源限制能力:
- cpu 子系统,主要限制进程的 cpu 使用率。
- cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
- cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
- memory 子系统,可以限制进程的 memory 使用量。
- blkio 子系统,可以限制进程的块设备 io。
- devices 子系统,可以控制进程能够访问某些设备。
- net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
- freezer 子系统,可以挂起或者恢复 cgroups 中的进程。
- ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace。
每个subsystem背后都有相应的内核模块来配合它完成对资源的控制。
Cgroups分为三个组件:
- 控制组:一个cgroups包括一组进程,可以在cgroups上增加 subsystem的参数配置,将一组进程与cgroups关系。
- subsystem:子系统是一组资源控制模块,控制节点中进程的资源占用。
- hierarchy层级数:把cgroups串成一个树形结构
疑问:
1.容器启动实际是PID=1的进程,后续创建的进程在宿主机能查到进程吗?
2.在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。