Docker隔离机制一探| 青训营

2023年 8月 28日 50.3k 0

docker隔离机制

  • 在容器进程启动之前重新挂载它的整个根目录“/”,用来为容器提供隔离后的执行环境文件系统(rootfs)。
  • 通过Linux Namespace 创建隔离,决定进程能够看到和使用哪些东西。
  • 通过control groups 技术来约束进程对资源的使用
  • 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全称是control groups
  • control groups:控制组,被整合在了linux内核当中,把进程(tasks)放到组里面,对组设置权限,对进程进行控制。可以理解为用户和组的概念,用户会继承它所在组的权限。
  • cgroups是linux内核中的机制,这种机制可以根据特定的行为把一系列的任务,子任务整合或者分离,按照资源划分的等级的不同,从而实现资源统一控制的框架,cgroup可以控制、限制、隔离进程所需要的物理资源,包括cpu、内存、IO,为容器虚拟化提供了最基本的保证,是构建docker一系列虚拟化的管理工具
  • Cgroup 解决了什么问题

  • 资源控制:cgroup通过进程组对资源总额进行限制。如:程序使用内存时,要为程序设定可以使用主机的多少内存,也叫作限额
  • 优先级分配:使用硬件的权重值。当两个程序都需要进程读取cpu,哪个先哪个后,通过优先级来进行控制
  • 资源统计:可以统计硬件资源的用量,如:cpu、内存…使用了多长时间
  • 进程控制:可以对进程组实现挂起/恢复的操作
  • 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 //查看命名空间
    

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论