zoukankan      html  css  js  c++  java
  • 容器进阶:隔离与限制

    Blog:博客园 个人

    参考:深入剖析Kubernetes LINUX NAMESPACE(上) cgroup 原理分析

    容器其实是一种沙盒技术。顾名思义,沙盒就是能够像一个集装箱一样,把你的应用“装”起来的技术。这样,应用与应用之间,就因为有了边界而不至于相互干扰;而被装进集装箱的应用,也可以被方便地搬来搬去。

    容器如何去实现这个边界来避免应用之间的互相干扰?这就涉及到Linux的两个技术:Cgroups技术Namespace技术

    • Cgroups技术:用来制造约束
    • Namespace技术:用来修改进程视图

    Namespace技术介绍

    先说结论,Docker 容器这个听起来玄而又玄的概念,实质是指定了容器进程所需要启用的一组Namespace参数。这样,容器就只能“看”到当前 Namespace 所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了。也就是说,容器是一种特殊的进程。

    Namespace种类

    Linux Namespace 有如下种类

    分类 系统调用参数 隔离内容 相关内核版本
    Mount CLONE_NEWNS 挂载点(文件系统) Linux 2.4.19
    UTS CLONE_NEWUTS 主机名和域名 Linux 2.6.19
    IPC CLONE_NEWIPC 信号量、消息队列和共享内存 Linux 2.6.19
    PID CLONE_NEWPID 进程编号 Linux 2.6.24
    Network CLONE_NEWNET 网络设备、网络栈、端口等 始于Linux 2.6.24 完成于 Linux 2.6.29
    User CLONE_NEWUSER 用户和用户组 始于 Linux 2.6.23 完成于 Linux 3.8)
    Cgroup CLONE_NEWCGROUP Cgroup根路径 Linux 4.6

    相关系统调用

    • clone():实现线程的系统调用,用来创建一个新的进程,并可以通过设计上述参数达到隔离。
    • unshare() :使某进程脱离某个namespace
    • setns():把某进程加入到某个namespace
    • ioctl_ns:查看namespace的信息

    在 Linux 系统中创建线程的系统调用是clone(),当我们用clone()系统调用创建一个新进程时,就可以在参数中指定 CLONE_NEWPID参数。这时,新创建的这个进程将会“看到”一个全新的进程空间,在这个进程空间里,它的PID是1。但是这个进程既看不到宿主机里真正的进程空间,也看不到其他 PID Namespace 里的具体情况。

    缺点

    基于 Linux Namespace 的隔离机制相比于虚拟化技术也有很多不足之处,其中最主要的问题就是:隔离得不彻底

    原因如下:

    • 运行在同一个宿主机上的容器共用一个操作系统内核(宿主机内核);
    • 有很多资源和对象是不能被 Namespace 化的 ,比如时间,若在某个容器中修改系统时间,则宿主机及宿主机所运行的所有容器的时间都被修改;
    • 应用“越狱”的难度比虚拟机低得多 ;

    Cgroups技术介绍

    一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受Cgroups配置的限制。

    Cgroups 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process groups) 所使用的物理资源 (如 cpu memory i/o 等等) 的机制。2007 年进入 Linux 2.6.24 内核,CGroups 不是全新创造的,它将进程管理从 cpuset 中剥离出来,作者是 Google 的 Paul Menage。CGroups 也是 LXC 为实现虚拟化所使用的资源管理手段。

    术语

    • task(任务):cgroups 的术语中,task 就表示系统的一个进程。
    • cgroup(控制组):cgroups 中的资源控制都以 cgroup 为单位实现。cgroup 表示按某种资源控制标准划分而成的任务组,包含一个或多个子系统。一个任务可以加入某个 cgroup,也可以从某个 cgroup 迁移到另外一个 cgroup。
    • subsystem(子系统):cgroups 中的 subsystem 就是一个资源调度控制器(Resource Controller)。比如 CPU 子系统可以控制 CPU 时间分配,内存子系统可以限制 cgroup 内存使用量。
    • hierarchy(层级树):hierarchy 由一系列 cgroup 以一个树状结构排列而成,每个 hierarchy 通过绑定对应的 subsystem 进行资源调度。hierarchy 中的 cgroup 节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个 hierarchy。

    作用

    • 资源限制(Resource Limitation):cgroups 可以对进程组使用的资源总额进行限制。如设定应用运行时使用内存的上限,一旦超过这个配额就发出 OOM(Out of Memory)。
    • 优先级分配(Prioritization):通过分配的 CPU 时间片数量及硬盘 IO 带宽大小,实际上就相当于控制了进程运行的优先级。
    • 资源统计(Accounting): cgroups 可以统计系统的资源使用量,如 CPU 使用时长、内存用量等等,这个功能非常适用于计费。
    • 进程控制(Control):cgroups 可以对进程组执行挂起、恢复等操作。

    在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。

    [root@test ~]# mount -t cgroup
    cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
    cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
    cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
    cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
    cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
    cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
    cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
    cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
    cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
    cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
    cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
    

    总结

    容器实质是一个“单进程”模型。

    Namespace 的作用是“隔离”,它让应用进程只能看到该Namespace 内的“世界”;而 Cgroups 的作用是“限制”,它给这个“世界”围上了一圈看不见的墙。这么一折腾,进程就真的被“装”在了一个与世隔绝的房间里,而这些房间就是 PaaS 项目赖以生存的应用“沙盒”。
    由于一个容器的本质就是一个进程,用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。

  • 相关阅读:
    20150226 IMX257 总线设备驱动模型编程之驱动篇
    20150226 IMX257 总线设备驱动模型编程之设备篇
    20150226 IMX257 总线设备驱动模型编程之总线篇(二)
    python 打印9*9乘法表
    redis设置最大内存上限对置换策略的解读
    redis3.0.6版本的info信息解读
    web访问流程
    WEB请求流程
    linux下mysql-5.6忘记root密码,重置root密码详细过程
    tomcat7+jdk1.8一键安装脚本
  • 原文地址:https://www.cnblogs.com/Rohn/p/14505338.html
Copyright © 2011-2022 走看看