容器 = cgroup + namespace + rootfs + 容器引擎
一、Cgroup
Cgroup 是 Control group 的简称,是 Linux 内核提供的一个特性,用于限制和隔离一组进程对系统资源的使用。对不同资源的具体管理是由各个子系统分工完成的。
Cgroup 可以对进程进行任意分组,如何分组由用户自定义。
cpuset 的主要接口如下:
devices.list: 只读文件,显示目前允许被访问的设备列表,文件格式为
类型[a|b|c] 设备号[major:minor] 权限[r/w/m 的组合]
a/b/c 表示 所有设备、块设备和字符设备。
devices.allow: 只写文件,以上述格式描述允许相应设备的访问列表。
devices.deny: 只写文件,以上述格式描述禁止相应设备的访问列表。
sethostname
这个系统调用会改变主机名,这个主机名就是全局资源,内核通过 UTS Namespace可以将不同的进程分隔在不同的 UTS Namespace 中,
与命名空间相关的三个系统调用:
clone创建全新的Namespace,由clone创建的新进程就位于这个新的namespace里。创建时传入 flags参数,可选值有 CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWUSER, 分别对应上面六种namespace。
unshare
为已有进程创建新的namespace。
setns
把某个进程放在已有的某个namespace里。
UTS namespace
UTS namespace 对主机名和域名进行隔离。为什么要隔离主机名?因为主机名可以代替IP来访问。如果不隔离,同名访问会出冲突。
IPC namespace
Linux 提供很多种进程通信机制,IPC namespace 针对 System V 和 POSIX 消息队列,这些 IPC 机制会使用标识符来区别不同的消息队列,然后两个进程通过标识符找到对应的消息队列。
IPC namespace 使得 相同的标识符在两个 namespace 代表不同的消息队列,因此两个namespace 中的进程不能通过 IPC 来通信。
PID namespace
隔离进程号,不同namespace 的进程可以使用相同的进程号。
当创建一个 PID namespace 时,第一个进程的PID 是1,即 init 进程。它负责回收所有孤儿进程的资源,所有发给 init 进程的信号都会被屏蔽。
Mount namespace
隔离文件挂载点,每个进程能看到的文件系统都记录在/proc/$$/mounts
里。在一个 namespace 里挂载、卸载的动作不会影响到其他 namespace。
Network namespace
隔离网络资源。每个 namespace 都有自己的网络设备、IP、路由表、/proc/net 目录、端口号等。网络隔离可以保证独立使用网络资源,比如开发两个web 应用可以使用80端口。
新创建的 Network namespace 只有 loopback 一个网络设备,需要手动添加网络设备。
User namespace
隔离用户和用户组。它的厉害之处在于,可以让宿主机上的一个普通用户在 namespace 里成为 0 号用户,也就是 root 用户。这样普通用户可以在容器内“随心所欲”,但是影响也仅限在容器内。最后,回到 Docker 上,经过上述讨论,namespace 和 cgroup 的使用很灵活,需要注意的地方也很多。 Docker 通过 Libcontainer
来做这些脏活累活。用户只需要使用 Docker API 就可以优雅地创建一个容器。docker exec
的底层实现就是上面提过的 setns
。
原文:https://www.cnblogs.com/yds941268778/p/12688363.html