docker隔离机制
rootfs
rootfs 是Docker 容器在启动时内部进程可见的文件系统,即Docker容器的根目录。rootfs通常包含一个操作系统运行所需的文件系统,例如可能包含经典的类Unix操作系统中的目录系统,如/dev、/proc、/bin、/etc、/lib、/usr、/tmp及运行Docker容器所需的配置文件、工具等。
在传统的linux操作系统内核启动时,首先挂载一个只读(read-only)的rootfs,当系统检测器完整性之后,再将其切换为读写(read-write)模式。而在Docker架构中,当Docker daemon 为Docker容器挂载rootfs时,沿用的Linux内核启动时的方法,即将rootfs设为只读模式。在挂载完毕之后,利用联合挂载(union mount)技术在已有的只读rootfs上再挂载一个读写层。这样,可读写层处于Docker容器文件系统的最顶层,其下可能联合挂载了多个只读层,只有在Docker容器运行过程中文件系统发生变化时,才会把变化的文件内容写到可读写层,并且隐藏只读层中的老版本文件。
rootfs只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在Linux操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。正是由于rootfs的存在,容器才有了一个被反复宣传至今的重要特性:一致性。由于rootfs里打包的不只是应用,而是整个操作系统的文件和目录,也就意味着,应用以及它运行所需要的所有依赖,都被封装在了一起。
有了容器镜像“打包操作系统”的能力,这个最基础的依赖环境也终于变成了应用沙盒的一部分。这就赋予了容器所谓的一致性:无论在本地、云端,还是在一台任何地方的机器上,用户只需要解压打包好的容器镜像,那么这个应用运行所需要的完整的执行环境就被重现出来了
Linux Namespace
namespace 是什么
namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个 namespace中。 Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。
namespace 解决了什么问题
Linux 内核实现 namespace 的一个主要目的就是实现轻量级虚拟化(容器)服务。在同一个namespace 下的进程可以感知彼此的变化,而对外界的进程一无所知。这样就可以让容器中的进程产生错觉,认为自己置身于一个独立的系统中,从而达到隔离的目的。也就是说 linux 内核提供的 namespace 技术为 docker 等容器技术的出现和发展提供了基础条件。
namespace有哪些
Mount Namespace隔离了一组进程所看到的文件系统挂载点的集合,因此,在不同MountNamespace的进程看到的文件系统层次结构也不同 UTS Namespace隔离了uname()系统调用返回的两个系统标示符nodename和domainname,在容器的上下文中,UTS Namespace允许每个容器拥有自己的hostname和NIS domain name,这对于初始化和配置脚本是很有用的,这些脚本根据这些名称来定制它们的操作 IPC Namespace隔离了某些IPC资源(interprocess community,进程间通信)使划分到不同IPC Namespace的进程组通信上隔离,无法通过消息队列、共享内存、信号量方式通信 PID Namespace隔离了进程ID号空间,不同的PID Namespace中的进程可以拥有相同的PID。PID Namespace的好处之一是,容器可以在主机之间迁移,同时容器内的进程保持相同的进程ID。PID命名空间还允许每个容器拥有自己的init(PID 1),它是 "所有进程的祖先",负责管理各种系统初始化任务,并在子进程终止时收割孤儿进程 Network Namespace提供了网络相关系统资源的隔离,因此,每个Network Namespace都有自己的网络设备、IP地址、IP路由表、/proc/net目录、端口号等。 User Namespace隔离了用户和组ID号空间,一个进程的用户和组ID在用户命名空间内外可以是不同的,一个进程可以在用户命名空间外拥有一个正常的无权限用户ID,同时在命名空间内拥有一个(root权限)的用户ID
ls /proc/{PD}/ns
$ docker run -it busybox /bin/sh
Cgroup
什么是Cgroup
Cgroup 解决了什么问题
cgroup子系统有哪些
cpu子系统:该子系统为每个进程组设置一个使用CPU的权重值,以此来管理进程对cpu的访问。 cpuset子系统:对于多核cpu,该子系统可以设置进程组只能在指定的核上运行,并且还可以设置进程组在指定的内存节点上申请内存。 cpuacct子系统:该子系统只用于生成当前进程组内的进程对cpu的使用报告 memory子系统:该子系统提供了以页面为单位对内存的访问,比如对进程组设置内存使用上限等,同时可以生成内存资源报告 blkio子系统:该子系统用于限制每个块设备的输入输出。首先,与CPU子系统类似,该系统通过为每个进程组设置权重来控制块设备对其的I/O时间;其次,该子系统也可以限制进程组的I/O带宽以及IOPS devices子系统:通过该子系统可以限制进程组对设备的访问,即该允许或禁止进程组对某设备的访问 freezer子系统:该子系统可以使得进程组中的所有进程挂起 net-cls子系统:该子系统提供对网络带宽的访问限制,比如对发送带宽和接收带宽进程限制
mount -t cgroup
运行一个docker容器,查看容器的cgroup 和 linux namespace
docker pull nginx
docker run -p 80:80 -d nginx
cd /sys/fs/cgroup //查看cgroup 子系统变化 并找到其对应的PID
cd /proc/{PID}/ns //查看命名空间