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. 525 Contiguous Array 连续数组

    给定一个二进制数组, 找到含有相同数量的 0 和 1 的最长连续子数组.示例 1:输入: [0,1]输出: 2说明: [0, 1] 是具有相同数量0和1的最长连续子数组. 示例 2:输入: [0,1, ...

  2. 160 Intersection of Two Linked Lists 相交链表

    编写一个程序,找到两个单链表相交的起始节点.例如,下面的两个链表:A:           a1 → a2                            ↘                   ...

  3. java中stringBuilder的用法

    java中stringBuilder的用法 String对象是不可改变的.每次使用 System.String类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间.在需 ...

  4. Oozie的架构

    Oozie的架构图,如下: 从oozie的架构图中,可以看到所有的任务都是通过oozie生成相应的任务客户端,并通过任务客户端来提交相应的任务. 继续...

  5. mysql索引命中规则

    转于:https://blog.csdn.net/claram/article/details/77574600 首先明确:为什么要用联合索引? 对于查询语句“SELECT E.* FROM E WH ...

  6. Mysql框架---HMySql

    Java 数据库框架 在我学习java数据库框架的时候,第一个用的是Hibernate,但是到现在,我可能已经快忘记它了,毕竟快两年没有碰的东西,后来一直再用MyBatis.因为它简单. 但是本文不会 ...

  7. 解决Android Studio安装过程中“SDK tools directory is missing”的问题

    "SDK tools directory is missing",这是因为安装时你的计算机无法连接到google的服务器(对google服务器的域名地址解析出问题了),无法从goo ...

  8. BOM学习-javascript计时器小结

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  9. 项目适配iOS9遇到的一些问题及解决办法 ,以及URL 白名单配置方法

    1.网络请求报错.升级Xcode 7.0发现网络访问失败.输出错误信息 The resource could not be loaded because the App Transport Secur ...

  10. mysql use index() 优化查询

    mysql use index() 优化查询 FORCE INDEX/IGNORE INDEX 的语法: SELECT *** FROM TABLE [{USE|IGNORE|FORCE} INDEX ...