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 namespaces Linux 2.4.19 文件系统挂接点 每个容器能看到不同的文件系统层次结构
UTS namespaces Linux 2.6.19 nodename 和 domainname 每个容器可以有自己的 hostname 和 domainame
IPC namespaces Linux 2.6.19 特定的进程间通信资源,包括System V IPC 和  POSIX message queues 每个容器有其自己的 System V IPC 和 POSIX 消息队列文件系统,因此,只有在同一个 IPC namespace 的进程之间才能互相通信
PID namespaces Linux 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-:/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-:/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-:/sys/fs/cgroup/cpu# mkdir container
//自动生成该子系统对应的资源限制文件
root@ht-:/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-:/sys/fs/cgroup/cpu# cat cpu.cfs_quota_us
- //-1表示没有任何限制
root@ht-:/sys/fs/cgroup/cpu# cat cpu.cfs_period_us
//默认100ms(100000us)
echo  > /cpu.cfs_quota_us   //该控制组限制的进程只能使用20ms的CPU时间,即只能使用到20% 的CPU带宽  

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

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

6、总结

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

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

[Docker]容器的隔离与限制的更多相关文章

  1. Docker 容器的隔离性

    Docker 容器的隔离性 就是 使用Linux namespace 来隔离运行环境和成 cgroup 限制容器使用的资源.  namespace 可以顾名思义 命名空间:所以可以理解为每个独立的容器 ...

  2. Docker 容器资源隔离 namespace(十)

    目录 一.简介 Linux Namespace的6大类型 二.Mount Namespace 三.IPC Namespace 四.Network Namespace 五.UTS Namespace 六 ...

  3. 理解Docker(4):Docker 容器使用 cgroups 限制资源使用

    本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  4. Kubernetes & Docker 容器网络终极之战(十四)

    目录 一.单主机 Docker 网络通信 1.1.host 模式 1.2 Bridge 模式 1.3 Container 模式 1.4.None 模式 二.跨主机 Docker 网络通信分类 2.1 ...

  5. CentOSLinux安装Docker容器

    Docker 使用 环境说明 CentOS 7.3(不准确地说:要求必须是 CentOS 7 64位) 不建议在 Windows 上使用 Docker 基本概念 官网:https://www.dock ...

  6. 隔离 docker 容器中的用户

    笔者在前文<理解 docker 容器中的 uid 和 gid>介绍了 docker 容器中的用户与宿主机上用户的关系,得出的结论是:docker 默认没有隔离宿主机用户和容器中的用户.如果 ...

  7. 通过命令验证docker容器相当一个轻量级的Linux运行环境,且每个容器内都有一个属于自己的文件系统,容器之间相互隔离

    一.docker的三个重要概念 1.镜像:打包项目带上环境,即镜像 Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包含了一些为运行时准备的配置参数.镜像 ...

  8. 在Linux和Windows的Docker容器中运行ASP.NET Core

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott H ...

  9. Docker容器是否可以改变世界?

    Docker容器是否可以改变世界? 2016-01-15 杜亦舒 2016年了,很多大牛开始预测技术趋势,其中一个普遍的观点我也很认同: Docker会更加流行,会改变程序世界 2015年的上半年我接 ...

随机推荐

  1. MySQL5.5升级到5.6

    5.6的新的特性 .支持GTIDs,Failover.多线程复制. 新增binlog_row_image只记录row格式下所用字段的修改(而不是像以前一样记录全部列),节省空间等资源: master. ...

  2. Lambda表达式。

    函数式编程思想: 面向对象思想:做一件事,先找能解决这件事的对象,然后调用该对象相应方法. 面向过程思想:只要能获取到结果,怎么做的不重要,重视结果,不重视过程. 冗余的代码: public stat ...

  3. 【学习笔记】block、inline(替换元素、不可替换元素)、inline-block的理解

    本文转载 总体概念 block和inline这两个概念是简略的说法,完整确切的说应该是 block-level elements (块级元素) 和 inline elements (内联元素).blo ...

  4. vue中引入字体图标报错,找不到字体文件

    在用vue + webpack进行开发的时候,在引用字体图标遇到字体无法加载的问题: 报以下错误 搞了好久没搞定,最后才找到解决方法(还是没有找到原因) 修改字体图标的css中引入字体文件的路径 以前 ...

  5. VCS 查看代码覆盖率

    代码覆盖率 代码覆盖率测试一般包括行覆盖,条件覆盖,FSM覆盖,翻转覆盖率等.在不同的代码级别有不同的覆盖率,Behavioral code包含line+condition+path(branch)+ ...

  6. IE8 window.open 不支持此接口 的问题解决

    在使用vs2010调试代码时,突然出现 window.open 不支持此接口的提示,开始认为是不是vs的问题,后来上网查询说是系统问题.我不想重装系统,之后发现是IE的问题,使用其他浏览器浏览系统不会 ...

  7. tween.js下面的轮播(饿了么点餐的那种效果)

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  8. 51nod 1096 距离之和最小(水题日常)

    基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 X轴上有N个点,求X轴上一点使它到这N个点的距离之和最小,输出这个最小的距离之和.   Input 第1行:点的数量 ...

  9. codevs 1043 方格取数 2000年NOIP全国联赛提高组

    时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description 设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而 ...

  10. 在云环境上使用SLF4J对Java程序进行日志记录

    我开发了一个Java应用,部署到云环境上之后,用postman测试发现不能按照我期望的工作,但是返回的消息对我没有任何帮助. 因为部署在云端的应用很难像本地Java应用一样调试,所以我打算用SLF4J ...