[Docker]容器的隔离与限制

1、Docker事实

  1)容器技术的兴起源于Pass技术的普及

  2)Docker公司发布的Docker项目具有里程碑式的意义

  3)Docker项目通过容器镜像解决了应用打包这个根本性难题

  4)容器本身没有价值,有价值的是容器编排

  5)容器是一个单进程模型

 

2、容器的隔离

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

  那这个边界是如何实现的呢?

  程序运行起来后计算机执行环境的总和,就是进程。

  容器技术的核心功能就是通过约束和修改进程的动态表现,从而为其创造出一个边界,Cgroup技术是用来制造约束的主要手段,而namespace是用来修改进程视图的主要方法

docker run -it busybox /bin/sh    //-it 告诉Docker启动容器后需要分配一个文本输入/输出环境
//启动一个容器,在容器里执行/bin/sh,并且分配一个命令行终端跟这个容器交互

  每当在宿主机上运行一个/bin/sh程序,操作系统都会给它分配一个进程编号,如PID=100,这个编号是进程的唯一标识。而现在通过Docker把/bin/sh程序运行在一个容器中,Docker会让这些进程只能看到重新计算过的进程编号,比如PID=1,可实际上它们在宿主机的操作系统中,还是原来的第100号进程。这种技术就是Linux里面的Namespace机制

  Namespace只是Linux创建新进程的一个可选参数,在Linux系统中创建线程的系统调用时clone()

int pid = clone(main_function, stack_size, SIGCHLD, NULL);//创建一个新的进程并且返回它的进程号pid

  当用clone()系统调用创建一个新的进程时,就可以在参数中指定CLONE_NEWPID参数

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);//创建一个新的进程并且返回它的进程号pid

  这时新创建的进程就会看到一个全新的进程空间,在这个进程空间里,它的PID是1。之所以说看到,因为这其实只是一个障眼法,在宿主机真实的进程空间里,这个进程的PID还是真实的数值100

  还可以多次执行上面的clone() 调用,这样就会创建多个PID NameSpace,而每个Namespace里的应用进程,都会认为自己是当前容器里的第1号进程,它们既看不到宿主机里真正的进程空间,也看不到其他PID Namespace里面的具体情况

  Docker实际上是在创建容器进程时,指定了这个进程所需要启用的一组Namespace参数,这样容器就只能看到当前Namespace所限定的资源、文件、设备、状态。而对于宿主机以及其他不相干的程序,就完全看不见了

  常见的Namespace及其作用见下表

namespace引入的相关内核版本被隔离的全局系统资源在容器语境下的隔离效果
Mount namespacesLinux 2.4.19文件系统挂接点每个容器能看到不同的文件系统层次结构
UTS namespacesLinux 2.6.19nodename 和 domainname每个容器可以有自己的 hostname 和 domainame
IPC namespacesLinux 2.6.19特定的进程间通信资源,包括System V IPC 和  POSIX message queues每个容器有其自己的 System V IPC 和 POSIX 消息队列文件系统,因此,只有在同一个 IPC namespace 的进程之间才能互相通信
PID namespacesLinux 2.6.24进程 ID 数字空间 (process ID number space)每个 PID namespace 中的进程可以有其独立的 PID; 每个容器可以有其 PID 为 1 的root 进程;也使得容器可以在不同的 host 之间迁移,因为 namespace 中的进程 ID 和 host 无关了。这也使得容器中的每个进程有两个PID:容器中的 PID 和 host 上的 PID。
Network namespaces始于Linux 2.6.24 完成于 Linux 2.6.29网络相关的系统资源每个容器用有其独立的网络设备,IP 地址,IP 路由表,/proc/net 目录,端口号等等。这也使得一个 host 上多个容器内的同一个应用都绑定到各自容器的 80 端口上。
User namespaces始于 Linux 2.6.23 完成于 Linux 3.8)用户和组 ID 空间 在 user namespace 中的进程的用户和组 ID 可以和在 host 上不同; 每个 container 可以有不同的 user 和 group id;一个 host 上的非特权用户可以成为 user namespace 中的特权用户;

 

3、使用Namespace进行容器的隔离有什么好处呢?

  由上面的内容可以得到用户运行在容器里的应用进程跟宿主机的其他进程一样,都是由宿主机操作系统统一管理,只不过这些被隔离的进程拥有额外设置过的Namespace参数

 

  虚拟机技术作为应用沙盒,必须要由Hypervisor来负责创建虚拟机,这个虚拟机里面必须运行一个完整的Guest OS才能执行用户的应用进程,这就不可避免地带来了额外的资源消耗和占用。此外用户应用运行在虚拟机里面,它对宿主机操作系统的调用就不可避免地要经过虚拟化软件的拦截和处理,对计算资源、网络和I/O的损耗非常大

  而容器化后的应用依然是宿主机上的一个普通进程,那虚拟化带来的性能损耗是不存在的,并且使用Namespace作为隔离手段的容器并不需要单独的Guest OS ,这使得容器额外的资源占用可忽略不计

 

4、使用Namespace进行容器的隔离有什么缺点呢?

  最大的缺点就是隔离不彻底

  1)容器知识运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核

  2)在Linux内核中,有很多资源和对象是不能被Namespace化的,最典型的例子是:时间

    即如果某个容器修改了时间,那整个宿主机的时间都会随之修改

  3)容器给应用暴露出来的攻击面比较大,在生产环境中,没有人敢把运行在物理机上的Linux容器暴露在公网上

 

 

5、为什么需要对容器进行限制呢?

  虽然容器内的第1号进行在障眼法的干扰下只能看到容器里的情况,但是宿主机上,它作为第100号进程与其他进程之间依然是平等竞争关系,即第100号进程表面上虽然被隔离气力啊,但是它所能够使用的资源却是随时可以被宿主机上的其他进程或容器占用的,这个进程也可能自己把所以的资源吃光

  Linux Cgroups(Linux Control Group,限制一个进程组能够使用的资源上限)是Linux内核中用来为进程设置资源限制的一个重要功能

root@ht-1:/proc# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event,release_agent=/run/cgmanager/agents/cgm-release-agent.perf_event)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids,release_agent=/run/cgmanager/agents/cgm-release-agent.pids)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
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,clone_children)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
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/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb)

  在/sys/fs/cgroup下面有很多如cpu、memory这样的子目录,也叫子系统,这些都是这台机器当前可以被Cgroup进行限制的资源种类,而在子系统对应的资源种类下,你就可以看到该类资源具体可以被限制的方法

  对CPU来说可以看到如下几个配置文件 

root@ht-1:/sys/fs/cgroup/cpu# ls
cgroup.clone_children  cgroup.sane_behavior  cpuacct.usage         cpu.cfs_period_us  cpu.shares  docker      kubepods    notify_on_release  system.slice  user.slice
cgroup.procs           cpuacct.stat          cpuacct.usage_percpu  cpu.cfs_quota_us   cpu.stat    init.scope  kube-proxy  release_agent      tasks

  这样的配置文件如何用呢?

//新建一个目录,这个目录称为控制组
root@ht-1:/sys/fs/cgroup/cpu# mkdir container
//自动生成该子系统对应的资源限制文件
root@ht-1:/sys/fs/cgroup/cpu# ls container/
cgroup.clone_children  cpuacct.stat   cpuacct.usage_percpu  cpu.cfs_quota_us  cpu.stat           tasks
cgroup.procs           cpuacct.usage  cpu.cfs_period_us     cpu.shares        notify_on_release
root@ht-1:/sys/fs/cgroup/cpu# cat cpu.cfs_quota_us 
-1                       //-1表示没有任何限制
root@ht-1:/sys/fs/cgroup/cpu# cat cpu.cfs_period_us 
100000            //默认100ms(100000us)   
        
echo 20000 > /cpu.cfs_quota_us   //该控制组限制的进程只能使用20ms的CPU时间,即只能使用到20% 的CPU带宽  

  Cgroups也有不完善的地方,最大的缺点就是/proc文件系统(存储记录当前内核运行状态的一系列特殊文件)的问题,当在容器里执行top指令,显示的信息是宿主机的信息

  造成这个问题的原因是,/proc文件系统不了解Cgruops限制的存在

6、总结

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

  容器的本质是一个进程,用户的应用进程实际上就是容器里PID=1的进程,也是其他后续创建的所有进程的父进程,这意味着没有办法同时运行两个不同的应用,除非你能事先找到一个公共的PID=1的程序来充当两个不同应用的父进程

转载于:https://www.cnblogs.com/yuxiaoba/p/9577905.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值