美文网首页
容器的本质

容器的本质

作者: 郭青耀 | 来源:发表于2020-10-10 11:14 被阅读0次

    容器的本质就是一组特殊的进程,它使用namespace做隔离,用cgroup做限制。

    • 这里的容器可以是docker ,rkt等
    • 因为容器是一组特殊的进程,所以他们是跑在同一个内核上的,隔离性没有虚拟机好。
    • 还因为进程带来的性能损耗比虚拟机小很多,它也是特别轻量的虚拟化。

    如何使用namespace对容器做隔离的

    容器是如何使用namespace做隔离的,因为namespace的种类也很多(pid,mount,network,ipc,user,UTS),这里以PID namespace为例。
    首先看一下关于PID 的一个小实验:
    环境说明:

    • 宿主机ubuntu 20.04
    • docker 容器
    • docker 加入了root组,所以不用输入sudo,容器启动的进程也是在root组中

    实验步骤:

    1. 启动一个centos的交互终端
      docker run -it centos /bin/bash
    2. 看看容器内部bash进程的pid


      bash_pid.png
    3. 看看宿主机上bash进程的pid,用户是root的那个pid.


      宿主机pid.png

    由上面的例子可以看到,容器启动的bash在容器内部看到的pid是1,在数组上看到的PID是31840,这是怎么做到的,其实很简单:
    正常我们clone一个进程使用下面代码,
    int pid = clone(child_main, stack_size, SIGCHLD, NULL);
    如果要想这个新进程只能看到自己,以及由自己clone出来的进程(在上面的例子中就是容器内执行的ps进程),不能看到其他进程,使用这段代码
    int pid = clone(child_main, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
    唯一的区别就是加入了CLONE_NEWPID,其他的namespace隔离也是使用相同的方式
    int pid = clone(child_main, stack_size, CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | SIGCHLD, NULL);
    这就是同时对,UTS, IPC,PID同时做namespace的隔离。

    这里有点不同是mount namespace ,因为mount namespace一定是伴随着mount动作才会生效。mount namespace由chroot 命令发展而来,chroot: change root file system,将根目录"/",挂载到指定的位置。通常我们说的容器镜像,就是挂载在根目录的文件系统,它为隔离后的容器提供文件系统,专业称之为"rootfs".

    如何使用cgroup 对资源做限制

    cgroup是一个内核功能,它能限制一个或者一组进程对进程资源(cpu,内存,网络等)的使用量不超过被分配的量。cgroup 给用户暴露出来的的操作系统接口是文件系统
    mount -t cgroup
    可以看到有哪些可以做cgroup限制的类型。

    cgroup_type.png

    下面演示一个对cpu类型的cgroup做限制的实例。
    环境说明:

    • 宿主机ubuntu 20.04
    • docker 容器
    • docker 加入了root组,所以不用输入sudo,容器启动的进程也是在root组中

    实验步骤:

    1. 启动一个centos的交互终端
      docker run -it centos /bin/bash
    2. 查看cpu 限制文件参数
    [root@f7ab6d1d8b37 /]# ls /sys/fs/cgroup/cpu
    cgroup.clone_children  cpu.shares      cpuacct.stat      cpuacct.usage_percpu_sys   notify_on_release
    cgroup.procs           cpu.stat        cpuacct.usage         cpuacct.usage_percpu_user  tasks
    cpu.cfs_period_us      cpu.uclamp.max  cpuacct.usage_all     cpuacct.usage_sys
    cpu.cfs_quota_us       cpu.uclamp.min  cpuacct.usage_percpu  cpuacct.usage_user
    

    这些文件中重要的有,cpu.cfs_period_us和cpu.cfs_quota_us ,表示在时间长度为cpu.cfs_period_us的时间内,可以分配到的CPU时间是cpu.cfs_quota_us ,单位都是us;
    默认是没有限制的

    [root@f7ab6d1d8b37 /]# cat  /sys/fs/cgroup/cpu/cpu.cfs_quota_us 
    -1
    [root@f7ab6d1d8b37 /]# cat  /sys/fs/cgroup/cpu/cpu.cfs_period_us 
    100000
    
    
    1. 写一个死循环,并放到后台执行,记下后台进程的PID
    [root@f7ab6d1d8b37 /]# sh deadloop.sh &
    [1] 39
    [root@f7ab6d1d8b37 /]# cat deadloop.sh 
    while true :;
    do :;
    done
    [root@f7ab6d1d8b37 /]# 
    

    后台进程的PID=39

    1. 使用top查看刚才死循环的CPU使用率100%


      cpu_100.png

    1. 现在使用限制cpu方式启动容器,
      设置cpu 100ms(即100000us)可以使用30ms(即30000us)
      docker run -it --cpu-period=100000 --cpu-quota=30000 centos /bin/bash
    2. 查看cgroup中的参数设置


      cgroup30.png
    3. 运行同样的死循环程序
    [root@c10f06c1832b /]# sh deadloop.sh  &
    [1] 17
    [root@c10f06c1832b /]# cat deadloop.sh 
    while true :;
    do :;
    done
    

    后台进程的PID=17

    1. 使用top查看刚才死循环的CPU使用率约等于30%,说明CPU使用率设置生效。


      top30.png

    其他类型的Cgroup也是使用类似的方式做资源限制的。

    相关文章

      网友评论

          本文标题:容器的本质

          本文链接:https://www.haomeiwen.com/subject/cppdpktx.html