• 容器两大核心技术资源隔离、资源限制


    我们只要提起容器技术就都会想到Docker,Docker是原dotCloud公司的项目,Docker项目出现了一个简单不起眼的技术叫容器镜像,而Docker项目的出现解决了应用打包这个原容器技术的中的难题,这就是为什么Docker项目刚刚开源不久,就带领dotCloud公司在PaaS领域脱颖而出。而dotCloud公司在2013年底改名为Docker公司,而Docker也成为了容器的代理名词。

    docker安装

    # step 1: 安装必要的一些系统工具
    sudo yum install -y yum-utils device-mapper-persistent-data lvm2
    # Step 2: 添加软件源信息
    sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    # Step 3: 更新并安装 Docker-CE
    sudo yum makecache fast
    sudo yum -y install docker-ce
    # Step 4: 开启Docker服务
    sudo service docker start
    
    # 注意:
    # 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,你可以通过以下方式开启。同理可以开启各种测试版本等。
    # vim /etc/yum.repos.d/docker-ce.repo
    #   将 [docker-ce-test] 下方的 enabled=0 修改为 enabled=1
    #
    # 安装指定版本的Docker-CE:
    # Step 1: 安装指定版本的docker-ce-selinux
    # yum install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm
    # Step 2: 查找Docker-CE的版本:
    # yum list docker-ce.x86_64 --showduplicates | sort -r
    #   Loading mirror speeds from cached hostfile
    #   Loaded plugins: branch, fastestmirror, langpacks
    #   docker-ce.x86_64            17.03.1.ce-1.el7.centos            docker-ce-stable
    #   docker-ce.x86_64            17.03.1.ce-1.el7.centos            @docker-ce-stable
    #   docker-ce.x86_64            17.03.0.ce-1.el7.centos            docker-ce-stable
    #   Available Packages
    # Step 3: 安装指定版本的Docker-CE: (VERSION 例如上面的 17.03.0.ce.1-1.el7.centos)
    # sudo yum -y install docker-ce-[VERSION]

    认识容器技术

    容器的核心技术就是通过约束和修改进程的动态表现,对于Docker等大数容器技术来说,都是通过Cgroup技术是用来制造约束的主要手段,而Namespace技术则是用来修改进程试图的主要方法。

    Namespace 技术

    Namespace技术其实只是Linux创建新进程的一个可选参数。在Linux创建线程的系统调用是clone(),例如:

    int pid = clone(main_function,...

    极客时间版权所有: https://time.geekbang.org/column/article/14642

    int pid = clone(main_function,...

    极客时间版权所有: https://time.geekbang.org/column/article/14642

    int pid = clone(main_function, stack_size, SIGCHLD, NULL);

    而用clone()创建新进程的时候,就可以在参数中指定CLONE_NEWPID参数,例如:

    int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

    这时候,我们可以看到一个全新的进程空间,在这个进程空间里,它的PID是1,但是在宿主机的真实进程空间里,这个进程的PID还是真实数值,这就是Namespace的“障眼法”。而除了我们刚刚用到的PID Namespace,Linux还提供了Mount、UTS、IPC、Network 和User 这些Namespace。这就是Linux容器的基本实现原理了。

    Docker听起来很高大上,实际上是容器进程时,指定了一组Namespace参数,这样容器内只能看到当前Namespace所限定的资源、文件、设备、状态等。而宿主机相关资源是看不到的。所以说容器其实是一种特殊的进程而已。

    我们通过下面的指令验证一下

    $ docker run -it busybox /bin/sh 
    Unable to find image 'busybox:latest' locally
    latest: Pulling from library/busybox
    8c5a7da1afbc: Pull complete 
    Digest: sha256:cb63aa0641a885f54de20f61d152187419e8f6b159ed11a251a09d115fdff9bd
    Status: Downloaded newer image for busybox:latest
    / # ps 
    PID   USER     TIME  COMMAND
        1 root      0:00 /bin/sh
        7 root      0:00 ps
    / # 

    上面指令的意思就是我们通过busybox镜像启动一个容器 并执行/bin/sh命令,我们在容器里执行一下ps指令,可以看到在Docker里最开始执行的/bin/sh,就是这个容器内的1号进程,而这个容器里一共只有两个进程运行,这意味着这两个进程已经被Docker隔离在与宿主机不同的世界里。

    Cgroup 技术

    Linux Cgroups是Linux内核中用来为进程设置资源限制的重要功能,但是我们为什么要做资源限制呢?我们通过Namespace创建的容器通过障眼法的把PID在容器看到的是1号进程,但是在宿主机上的实际进程是100号,但是100号进程与宿主机其他所有进程是平等竞争的关系。这就意味着容器里的1号进程可以把所有宿主机资源吃光,也可以被宿主机上其他其他进程占用。显然这样的设计是不合理的。所以我们通过Cgroup来限制进程对资源的使用情况进行限制,主要作用就是限制一个进程组能够使用的资源上线,例如:CPU、内存、磁盘、网络带宽等。下面我们通过一组实例来验证一下限制功能。

    在Linux中,Cgroup给用户暴露出来的操作接口是文件系统,既它以文件和目录的方式组织操作系统 /sys/fs/cgroup 路径下。通mount -t cgroup来显示出来

    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/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
    cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
    cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
    cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
    cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
    cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
    cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
    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/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)

    可以看到在/sys/fs/cgroup下面有cpu、memory、blkio等这样的子目录,这都是能被Cgroup进行资源限制的资源类型,而这些子目录下就是这些类型的限制方法,例如:对CPU子目录来说,我们可以看到如下几个配置文件

    $ ls  /sys/fs/cgroup/cpu
    cgroup.clone_children  cpuacct.usage         cpuacct.usage_percpu_sys   cpuacct.usage_user  cpu.rt_period_us   cpu.stat
    cgroup.procs           cpuacct.usage_all     cpuacct.usage_percpu_user  cpu.cfs_period_us   cpu.rt_runtime_us  notify_on_release
    cpuacct.stat           cpuacct.usage_percpu  cpuacct.usage_sys          cpu.cfs_quota_us    cpu.shares         tasks

    我们可以用cpu.cfs_quota_us和cpu.rt_period_us来配合使用限制CPU使用情况,可以用来限制进程在长度为cpu.rt_period的一段时间,只能被分配到总量为cpu.cfs_quota的CPU时间。我们通过下面例子展示。首先我们需要在对应的子目录下创建一个目录,我们进入/sys/fs/cgroup/cpu,执行如下指令:

    $  cd /sys/fs/cgroup/cpu
    $  mkdir container 
    $  ls container/
    cgroup.clone_children  cpuacct.usage         cpuacct.usage_percpu_sys   cpuacct.usage_user  cpu.rt_period_us   cpu.stat
    cgroup.procs           cpuacct.usage_all     cpuacct.usage_percpu_user  cpu.cfs_period_us   cpu.rt_runtime_us  notify_on_release
    cpuacct.stat           cpuacct.usage_percpu  cpuacct.usage_sys          cpu.cfs_quota_us    cpu.shares         tasks

    我们可以看到在创建的container目录下会自动生成该cpu子目录下的资源限制文件。

    下面我们执行一个死循环脚本,让他把CPU资源吃到100%,根据输出,我们可以看到这个脚本的PID是17436

    $ while : ; do : ; done &
    [1] 17436

    通过top命令查看cpu资源使用情况

    $ top
    ....
    %Cpu13 :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    .....

    我们看一下container目录下的cpu.cfs_quota_us和cpu.rt_period_us的值

    $  cd container/
    $  cat cpu.cfs_quota_us 
    -1
    $  cat cpu.cfs_period_us 
    100000

    接下来,我们可以通过修改这些文件的内容来设置限制

    极客时间版权所有: https://time.geekbang.org/column/article/14653

    给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式...

    极客时间版权所有: https://time.geekbang.org/column/article/14653

    接下来我们通过修改这两个文件的内容来设置CPU限制。

    container目录下的cpu.cfs_quota_us文件中写入20ms (20000 us)

    $  echo 20000 > cpu.cfs_quota_us 

    上述命令意味着在每100ms的时间里,被该控制组限制的进程只能使用20ms的CPU时间,也就是说这个进程只能使用到20% 的CPU带宽。

    接下来,我们把被限制的进程的PID写入container目录下tasks文件,上面设置就对该PID生效。

    $  echo 17436 > /sys/fs/cgroup/cpu/container/tasks 

    我们用top指令看一下

    $  top
    ....
    %Cpu13 : 20.3 us,  0.0 sy,  0.0 ni, 79.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    ....

    可以看到CPU资源讲到20%

    除了CPU子系统外,Cgroup对其他子系统都有资源限制的方法,例如:

    • blkio 为块设备设置I/O限制,一般用户磁盘等设备
    • cpuset 为进程分配单独的CPU核和对应的内存节点
    • memory 为进程设定内存使用限制
  • 相关阅读:
    Design + Code (iOS)
    Objective-C Programming (2nd Edition)
    iOS Programming The Big Nerd Ranch Guide (4th Edition)
    反射
    面向对象
    人狗大战
    数据结构初识(三级菜单)
    面向对象(组合)
    练习
    re模块
  • 原文地址:https://www.cnblogs.com/xzkzzz/p/9705766.html
Copyright © 2020-2023  润新知