06 | 白话容器基础(二):隔离与限制

06 | 白话容器基础(二):隔离与限制

朗读人:张磊    16′36′′ | 7.61M

你好,我是张磊。我今天和你分享的主题是:白话容器基础之隔离与限制。

在上一篇文章中,我详细介绍了 Linux 容器中用来实现“隔离”的技术手段:Namespace。而通过这些讲解,你应该能够明白,Namespace 技术实际上修改了应用进程看待整个计算机“视图”,即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容。但对于宿主机来说,这些被“隔离”了的进程跟其他进程并没有太大区别。

说到这一点,相信你也能够知道我在上一篇文章最后给你留下的第一个思考题的答案了:在之前虚拟机与容器技术的对比图里,不应该把 Docker Engine 或者任何容器管理工具放在跟 Hypervisor 相同的位置,因为它们并不像 Hypervisor 那样对应用进程的隔离环境负责,也不会创建任何实体的“容器”,真正对隔离环境负责的是宿主机操作系统本身:

所以,在这个对比图里,我们应该把 Docker 画在跟应用同级别并且靠边的位置。这意味着,用户运行在容器里的应用进程,跟宿主机上的其他进程一样,都由宿主机操作系统统一管理,只不过这些被隔离的进程拥有额外设置过的 Namespace 参数。而 Docker 项目在这里扮演的角色,更多的是旁路式的辅助和管理工作。

我在后续分享 CRI 和容器运行时的时候还会专门介绍到,其实像 Docker 这样的角色甚至可以去掉。

这样的架构也解释了为什么 Docker 项目比虚拟机更受欢迎的原因。

这是因为,使用虚拟化技术作为应用沙盒,就必须要由 Hypervisor 来负责创建虚拟机,这个虚拟机是真实存在的,并且它里面必须运行一个完整的 Guest OS 才能执行用户的应用进程。这就不可避免地带来了额外的资源消耗和占用。

根据实验,一个运行着 CentOS 的 KVM 虚拟机启动后,在不做优化的情况下,虚拟机自己就需要占用 100~200 MB 内存。此外,用户应用运行在虚拟机里面,它对宿主机操作系统的调用就不可避免地要经过虚拟化软件的拦截和处理,这本身又是一层性能损耗,尤其对计算资源、网络和磁盘 I/O 的损耗非常大。

而相比之下,容器化后的用户应用,却依然还是一个宿主机上的普通进程,这就意味着这些因为虚拟化而带来的性能损耗都是不存在的;而另一方面,使用 Namespace 作为隔离手段的容器并不需要单独的 Guest OS,这就使得容器额外的资源占用几乎可以忽略不计。

所以说,“敏捷”和“高性能”是容器相较于虚拟机最大的优势,也是它能够在 PaaS 这种更细粒度的资源管理平台上大行其道的重要原因。

不过,有利就有弊,基于 Linux Namespace 的隔离机制相比于虚拟化技术也有很多不足之处,其中最主要的问题就是:隔离得不彻底。

首先,既然容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。

尽管你可以在容器里通过 Mount Namespace 单独挂载其他不同版本的操作系统文件,比如 CentOS 或者 Ubuntu,但这并不能改变共享宿主机内核的事实。这意味着,如果你要在 Windows 宿主机上运行 Linux 容器,或者在低版本的 Linux 宿主机上运行高版本的 Linux 容器,都是行不通的。

而相比之下,拥有硬件虚拟化技术和独立 Guest OS 的虚拟机就要方便得多了。最极端的例子是,Microsoft 的云计算平台 Azure,实际上就是运行在 Windows 服务器集群上的,但这并不妨碍你在它上面创建各种 Linux 虚拟机出来。

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

这就意味着,如果你的容器中的程序使用 settimeofday(2) 系统调用修改了时间,整个宿主机的时间都会被随之修改,这显然不符合用户的预期。相比于在虚拟机里面可以随便折腾的自由度,在容器里部署应用的时候,“什么能做,什么不能做”,就是用户必须考虑的一个问题。

此外,由于上述问题,尤其是共享宿主机内核的事实,容器给应用暴露出来的攻击面是相当大的,应用“越狱”的难度自然也比虚拟机低得多。

更为棘手的是,尽管在实践中我们确实可以使用 Seccomp 等技术,对容器内部发起的所有系统调用进行过滤和甄别来进行安全加固,但这种方法因为多了一层对系统调用的过滤,一定会拖累容器的性能。何况,默认情况下,谁也不知道到底该开启哪些系统调用,禁止哪些系统调用。

所以,在生产环境中,没有人敢把运行在物理机上的 Linux 容器直接暴露到公网上。当然,我后续会讲到的基于虚拟化或者独立内核技术的容器实现,则可以比较好地在隔离与性能之间做出平衡。

在介绍完容器的“隔离”技术之后,我们再来研究一下容器的“限制”问题。

也许你会好奇,我们不是已经通过 Linux Namespace 创建了一个“容器”吗,为什么还需要对容器做“限制”呢?

我还是以 PID Namespace 为例,来给你解释这个问题。

虽然容器内的第 1 号进程在“障眼法”的干扰下只能看到容器里的情况,但是宿主机上,它作为第 100 号进程与其他所有进程之间依然是平等的竞争关系。这就意味着,虽然第 100 号进程表面上被隔离了起来,但是它所能够使用到的资源(比如 CPU、内存),却是可以随时被宿主机上的其他进程(或者其他容器)占用的。当然,这个 100 号进程自己也可能把所有资源吃光。这些情况,显然都不是一个“沙盒”应该表现出来的合理行为。

Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。

有意思的是,Google 的工程师在 2006 年发起这项特性的时候,曾将它命名为“进程容器”(process container)。实际上,在 Google 内部,“容器”这个术语长期以来都被用于形容被 Cgroups 限制过的进程组。后来 Google 的工程师们说,他们的 KVM 虚拟机也运行在 Borg 所管理的“容器”里,其实也是运行在 Cgroups“容器”当中。这和我们今天说的 Docker 容器差别很大。

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。

此外,Cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。在今天的分享中,我只和你重点探讨它与容器关系最紧密的“限制”能力,并通过一组实践来带你认识一下 Cgroups。

在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。在 Ubuntu 16.04 机器里,我可以用 mount 指令把它们展示出来,这条命令是:

$ mount -t cgroup
cpuset on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cpu on /sys/fs/cgroup/cpu type cgroup (rw,nosuid,nodev,noexec,relatime,cpu)
cpuacct on /sys/fs/cgroup/cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct)
blkio on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
memory on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
...
复制代码

它的输出结果,是一系列文件系统目录。如果你在自己的机器上没有看到这些目录,那你就需要自己去挂载 Cgroups,具体做法可以自行 Google。

可以看到,在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是我这台机器当前可以被 Cgroups 进行限制的资源种类。而在子系统对应的资源种类下,你就可以看到该类资源具体可以被限制的方法。比如,对 CPU 子系统来说,我们就可以看到如下几个配置文件,这个指令是:

$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
复制代码

如果熟悉 Linux CPU 管理的话,你就会在它的输出里注意到 cfs_period 和 cfs_quota 这样的关键词。这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。

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

你需要在对应的子系统下面创建一个目录,比如,我们现在进入 /sys/fs/cgroup/cpu 目录下:

root@ubuntu:/sys/fs/cgroup/cpu$ mkdir container
root@ubuntu:/sys/fs/cgroup/cpu$ ls container/
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
复制代码

这个目录就称为一个“控制组”。你会发现,操作系统会在你新创建的 container 目录下,自动生成该子系统对应的资源限制文件。

现在,我们在后台执行这样一条脚本:

$ while : ; do : ; done &
[1] 226
复制代码

显然,它执行了一个死循环,可以把计算机的 CPU 吃到 100%,根据它的输出,我们可以看到这个脚本在后台运行的进程号(PID)是 226。

这样,我们可以用 top 指令来确认一下 CPU 有没有被打满:

$ top
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
复制代码

在输出里可以看到,CPU 的使用率已经 100% 了(%Cpu0 :100.0 us)。

而此时,我们可以通过查看 container 目录下的文件,看到 container 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100 ms(100000 us):

$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
-1
$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_period_us
100000
复制代码

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

比如,向 container 组里的 cfs_quota 文件写入 20 ms(20000 us):

$ echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
复制代码

结合前面的介绍,你应该能明白这个操作的含义,它意味着在每 100 ms 的时间里,被该控制组限制的进程只能使用 20 ms 的 CPU 时间,也就是说这个进程只能使用到 20% 的 CPU 带宽。

接下来,我们把被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:

$ echo 226 > /sys/fs/cgroup/cpu/container/tasks
复制代码

我们可以用 top 指令查看一下:

$ top
%Cpu0 : 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%(%Cpu0 : 20.3 us)。

除 CPU 子系统外,Cgroups 的每一项子系统都有其独有的资源限制能力,比如:

  • blkio,为​​​块​​​设​​​备​​​设​​​定​​​I/O 限​​​制,一般用于磁盘等设备;
  • cpuset,为进程分配单独的 CPU 核和对应的内存节点;
  • memory,为进程设定内存使用的限制。

Linux Cgroups 的设计还是比较易用的,简单粗暴地理解呢,它就是一个子系统目录加上一组资源限制文件的组合。而对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。

而至于在这些控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定了,比如这样一条命令:

$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
复制代码

在启动这个容器后,我们可以通过查看 Cgroups 文件系统下,CPU 子系统中,“docker”这个控制组里的资源限制文件的内容来确认:

$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_period_us
100000
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_quota_us
20000
复制代码

这就意味着这个 Docker 容器,只能使用到 20% 的 CPU 带宽。

总结

在这篇文章中,我首先介绍了容器使用 Linux Namespace 作为隔离手段的优势和劣势,对比了 Linux 容器跟虚拟机技术的不同,进一步明确了“容器只是一种特殊的进程”这个结论。

除了创建 Namespace 之外,在后续关于容器网络的分享中,我还会介绍一些其他 Namespace 的操作,比如看不见摸不着的 Linux Namespace 在计算机中到底如何表示、一个进程如何“加入”到其他进程的 Namespace 当中,等等。

紧接着,我详细介绍了容器在做好了隔离工作之后,又如何通过 Linux Cgroups 实现资源的限制,并通过一系列简单的实验,模拟了 Docker 项目创建容器限制的过程。

通过以上讲述,你现在应该能够理解,一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。

这也是容器技术中一个非常重要的概念,即:容器是一个“单进程”模型。

由于一个容器的本质就是一个进程,用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。

但是,在后面分享容器设计模式时,我还会推荐其他更好的解决办法。这是因为容器本身的设计,就是希望容器和应用能够同生命周期,这个概念对后续的容器编排非常重要。否则,一旦出现类似于“容器是正常运行的,但是里面的应用早已经挂了”的情况,编排系统处理起来就非常麻烦了。

另外,跟 Namespace 的情况类似,Cgroups 对资源的限制能力也有很多不完善的地方,被提及最多的自然是 /proc 文件系统的问题。

众所周知,Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。

但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。

造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统不了解 Cgroups 限制的存在。

在生产环境中,这个问题必须进行修正,否则应用程序在容器里读取到的 CPU 核数、可用内存等信息都是宿主机上的数据,这会给应用的运行带来非常大的困惑和风险。这也是在企业中,容器化应用碰到的一个常见问题,也是容器相较于虚拟机另一个不尽如人意的地方。

思考题

  1. 你是否知道如何修复容器中的 top 指令以及 /proc 文件系统中的信息呢?(提示:lxcfs)

  2. 在从虚拟机向容器环境迁移应用的过程中,你还遇到哪些容器与虚拟机的不一致问题?

感谢你的收听,欢迎给我留言一起讨论,也欢迎分享给更多的朋友一起阅读。

版权归极客邦科技所有,未经许可不得转载

精选留言

  • blackpiglet
    1 之前遇到过,但是没有考虑如何解决,临时抱佛脚,查了 lxcfs,尝试回答一下。top 是从 /prof/stats 目录下获取数据,所以道理上来讲,容器不挂载宿主机的该目录就可以了。lxcfs就是来实现这个功能的,做法是把宿主机的 /var/lib/lxcfs/proc/memoinfo 文件挂载到Docker容器的/proc/meminfo位置后。容器中进程读取相应文件内容时,LXCFS的FUSE实现会从容器对应的Cgroup中读取正确的内存限制。从而使得应用获得正确的资源约束设定。kubernetes环境下,也能用,以ds 方式运行 lxcfs ,自动给容器注入争取的 proc 信息。
    2 用的是vanilla kubernetes,遇到的主要挑战就是性能损失和多租户隔离问题,性能损失目前没想到好办法,可能的方案是用ipvs 替换iptables ,以及用 RPC 替换 rest。多租户隔离也没有很好的方法,现在是让不同的namespace调度到不同的物理机上。也许 rancher和openshift已经多租户隔离。
    2018-09-05
    作者回复

    课代表出现了!

    2018-09-05

  • monkey
    对cgroup有了更深的了解,作者能帮所有订阅的同学建个微信群方便大家交流心得吗?买的其他课程很多老师都建了交流群氛围挺好的哈。
    2018-09-05
    作者回复

    我跟编辑沟通一下

    2018-09-05

  • 天秤vs永恒
    对 Namespace 和 Cgroups 的理解又加深了很多!
    2018-09-05
  • Jeff.W
    可怜的容器,被Namespace欺骗,又被Cgroups限制,在这样的环境下,还发挥着自己生命的意义-与应用程序同生命周期,同生共死~
    2018-09-13
  • snakorse
    不太明白,既然都是用的宿主内核,那容器内还有不同的操作系统(centos,ubuntu)之分吗?如果有,那是如何做到的呢?
    2018-09-05
  • atompi
    1. 把宿主机的 /var/lib/lxcfs/proc/* 文件挂载到容器的/proc/*
    2. 既然有人提到了Windows运行容器的疑问,那就从这里说开。虚拟机可以通过vbox、VMware、Hyper-V直接运行在各种支持虚拟化的操作系统上,而 Linux 容器只能运行在Linux内核的操作系统之上,而且内核版本也有所限制(详见namespace、Cgroups在Linux内核中的发展史)。对于前面仁兄所说的Docker可以在Windows10上运行,并不是直接运行在Windows操作系统中,而是通过Hyper-V的支持,借助docker-machine,相当于是在Linux内核的虚拟机上运行的容器,实际上还是跑在Linux内核之上。
    2018-09-05
  • 这篇文章写的真不错,终于明白cgroup是干嘛的了。再有,我能在这里打招聘广告吗?
    2018-09-05
    作者回复

    不太好,这里还是交流技术为主

    2018-09-05

  • 岁月~静好
    相对于虚拟机来说,容器没有专门的cpu内存等,没有虚拟的操作系统,只是通过namespace重命名的进程运行买物理机上,没有实质性的隔离,会发生容器内的应用越狱等情况。但可以通过cgroup来限制容器的cpu内存等的使用,现有问题是top,/pro下查看到的还是物理界机的相关信息。不知道理解的是否正确?
    2018-09-05
    作者回复

    是的呢

    2018-09-05

  • 叫我胖柴柴😊
    /proc文件系统的问题我好像遇到过这个坑..当时在容器上运行的java应用,由于当时jvm参数没正确配置上,就用默认的,而容器设置的内存为4g,最后oom了,当时用命令查看容器的内存占用情况,竟然发现内存竟然有60多g。 那应该显示的是宿主机的内存了,jvm按照宿主机内存大小分配的默认内存应该大于4g 所以还没full gc 就oom了
    2018-09-10
    作者回复

    这个问题确实很普遍

    2018-09-10

  • Django
    想问下,windows10中的linux子系统是如何实现的?
    2018-09-05
    作者回复

    应该是API翻译,即,把linux syscall翻译成windows syscall

    2018-09-05

  • 把复杂的问题讲得如此简单易懂,这才叫专家,👍
    2018-09-14
  • 暮雨
    容器内部还能再做namespace和cgroup么?也就是容器中再做docker
    2018-09-08
    作者回复

    没问题。但是要挂载对应的文件系统,开启需要的权限。

    2018-09-08

  • paingain
    是不是可以理解:一个docker里面跑的进程都是docker这个进程的子进程?
    2018-09-07
    作者回复

    不。是entrypoint进程的子进程。docker基本上是旁路控制的作用。

    2018-09-07

  • microshaoft
    讲讲端口,环境变量,网络如何复用隔离的,容器内执行关机命令是如何被限制的
    2018-09-07
  • Cloud*
    通过 lxcfs 来实现隔离,具体是 lxcfs 在宿主机上维护进程组信息,然后容器启动的时候通过 -v 参数将 lxcfs /proc目录挂载到容器的 /proc 目录,当容器中获取 /proc 信息时,实际上是宿主机上对该容器的进程组信息 …/PID/proc 进行操作。
    2018-09-05
  • 晓聪
    cgroups原来是这样的,之前看着这名字都头疼。
    最近使用docker-compose有一个mongdb的容器,程序运行起来后,大概率会导致本地都连不上宿主机。看来可能是某个容器资源占用太大了,需要限制一下
    2018-09-05
  • Oracleblog
    容器的本质是一个进程,那所有的容器的image是不是都基于一个比较小的linux内核?因为进去容器之后能看到类似文件系统目录,还能执行很多操作系统命令。
    2018-09-05
    作者回复

    没有内核。详见下一节镜像的讲解。

    2018-09-05

  • pytimer
    为什么容器不添加磁盘限制?
    2018-09-05
    作者回复

    技术上没有问题,但对上层编排系统的挑战比较大

    2018-09-05

  • gotojeff
    Linux container 不是可以跑在windows10上面吗?请问文章里是这是行不通的是什么意思?
    2018-09-05
    作者回复

    它实际上是跑在一个虚拟机里的

    2018-09-05

  • 彼岸
    老师好,想问下,linux中的非容器进程与容器进程,实际根本没啥区别,只是通过cgroup与namspace的限制后,使得进程满足了容器制定的规范后,我们就可以把此进程称为容器了。其容器本质还是进程,只是是个有限定的特殊进程而已
    2018-09-13
  • 欢喜哥
    老师您好,对linux不是很熟悉,能不能推荐一下k8s对应的linux的预备知识?目前工作也考虑使用k8s,就是怕自己知识差,解决问题慢,影响生产
    2018-09-12
    作者回复

    推荐:鸟哥的Linux私房菜

    2018-09-13

  • Ariel
    老师,云主机有共享和独享,独享的就是实打实分配指定的cpu和内存,不会受其他租户影响。而容器能这样分配吗?
    2018-09-06
    作者回复

    其实,无论虚拟机还是容器,都不可能实打实。当然,容器的更 虚。

    2018-09-07

  • 余泽锋
    MacBook Pro,运行了四个docker,开vscode,感觉还行,不卡
    2018-09-06
  • Bob
    请教个问题,cgroups除了限制资源上限,能否锁定下限?如果不能,那不是很容易被抢资源?
    2018-09-06
    作者回复

    只有上限。所以才需要kubernetes 来帮你做调度嘛。

    2018-09-06

  • 余泽锋
    老师您好,“这意味着,如果你要在 Windows 宿主机上运行 Linux 容器,或者在低版本的 Linux 宿主机上运行高版本的 Linux 容器,都是行不通的。”这段话有些不解,我的macbook pro可以运行最新版本的linux的docker,感觉是不是跟您这句话有冲突
    2018-09-05
    作者回复

    mac docker其实是个虚拟机。你不觉得它卡吗?哈哈。

    2018-09-06

  • kyleqian
    既然容器都运行在同一个内核,我在两个容器里挂载了同一个本地目录 ,然后在一个容器里的该目录下建立一个子目录,用mount命令成功挂载远程的nfs到这个子目录上,但是在另一个容器里看还是空子目录,没有nfs服务里的内容。这该怎么解决?是不是我的方法就不对?
    2018-09-05
    作者回复

    你的mount操作都被隔离在一个容器里了,另一个怎么能看到呢?

    2018-09-06

  • Liam
    如果docker run时没有指定cpu quota,默认是不限制的吧 (-1)
    2018-09-05
    作者回复

    2018-09-06

  • 栖枝
    精彩,简单通俗易懂
    2018-09-05
  • Kaer
    docker的实现原理也仅仅是调用了底层的namespace和cgroup吗,然后加上一些其他的优化和特性。
    2018-09-05
    作者回复

    准确的说,是调用containerd + runc。runc干你说的这些事儿。

    2018-09-05

  • A:春哥大魔王
    感觉理解了namespace和cgroup,自己也可以搞一个进程容器了
    2018-09-05
    作者回复

    所以docker公司其实一直很担心,他知道自己门槛不高

    2018-09-05

  • 明珠
    老师,讲的太好了,言简易懂,每天都在期待新的一节课。 请教一个问题我们通常dockerpull下来的基础镜像比如:centos 7,这个镜像里面没有内核信息是吧?但是封装了systemd等进程管理工具,使得产生的新的进程都是一号进程的子进程,执行ping netstat命令,也会是这个容器一号进程的子进程? 老师这样理解对吗?
    2018-09-05
    作者回复

    没毛病

    2018-09-05

  • asdf100
    由于一个容器的本质就是一个进程,用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。

    这里的应用指的是容器里的apache redis mysql这类的应用吗?
    2018-09-05
    作者回复

    对的

    2018-09-05

  • huan
    2. 进程运行用户一般不用root,到了docker运行都是root用户和权限,也算一种不一致
    2018-09-05
  • Hurt
    第一个不会呀 遇到网络不同步的问题
    2018-09-05
  • C+c
    2. 习惯了虚机甚至物理机场景的业务软件,希望能够通过systemd进行进程管理,希望容器迁移时IP地址不变。
    2018-09-05
  • 故事的小黄花
    其实,虚拟机对于宿主机来说也是进程,限制虚拟机的资源使用也可以用cgroup.
    2018-10-18
    作者回复

    不。宿主机看到的qemu进程,而不是应用的进程。这是有本质区别的。

    2018-10-18

  • Lost In The Echo。
    cgroups目录留下的文件如何有效的清理呢?
    2018-10-14
    作者回复

    umount后删了即可

    2018-10-15

  • 阳雨杭
    运行了docker run -it --cpu-period=100000 --cpu-quota=20000 busybox /bin/sh之后,并没有在/sys/fs/cgroup中找到名字为docker的限制组文件夹啊。 我的系统是CentOS Linux release 7.5.1804 (Core)
    2018-10-12
    作者回复

    可以google一下centos下的cgroups文件路径

    2018-10-12

  • aze
    非常浅显易懂!先记录一下疑问:1如何实现不同容器不同操作系统?2容器磁盘无法限制(IOPS与大小)?3容器的文件在宿主机的文件目录?
    2018-10-07
    作者回复

    你应该很快就能明白了

    2018-10-08

  • 凯文1985
    一个容器本质上只是一个进程,那么不能同时启动两个应用?这个能解释一下吗? 如果我打包一个docker镜像 里面安装了redis和tomcat 那就不能跑在容器里了?
    2018-10-06
    作者回复

    能。但至少一个进程会无法管理。

    2018-10-06

  • 广宇
    评论比文章更精彩
    2018-10-05
  • 可以讲讲network namespace吗?
    2018-10-04
    作者回复

    见network部分

    2018-10-04

  • yyarrow
    "用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程",这里不是很懂,为啥找到一个公共的pid=1的夫进程就行了呢?即使找到了,两个子进程也不能作为同一个容器管理吧?还有这个公共的pid=1中所谓的“公共”指的是在容器中还是在宿主机中的公共呀?求指导~
    2018-10-01
    作者回复

    当然是容器里。比如用systemd当公共父进程

    2018-10-02

  • 小豪
    张老师,请问利用cgroup做内存限制,如果容器内的进程消耗的内存比较高,会导致容器进程假死吗?有什么更好的解决方法呢?谢谢
    2018-09-29
    作者回复

    会的,做好健康检查

    2018-09-30

  • Chumper
    也就是对于/etc/hosts这个文件而言,同一个pod中不同container修改权限时是修改的宿主机的文件权限,而修改hosts文件内容时,修改的是各自的文件么?

    2018-09-27

     作者回复

    不是……hosts跟volume是一样的,所有容器共同mount了同一份。但是这个文件的内容,是kubelet维护的,在每个容器创建的时候,kubelet会重写它里面的内容。这就是为啥我说不让你手动改hosts……

    经磊哥一讲解,比之前豁然开朗了许多,但是同一个pod中不同container hosts权限问题呢,一个容器中改了权限,不是生效在该容器的读写层么,宿主机上对应的文件权限不会变化吧?如果不变化,那么同pod中下一个容器mount的时候不是应该权限和宿主机最初的hosts权限一致么
    2018-09-27
    作者回复

    注意,这个文件是个volume,不是可读写层的一部分。可以看看我讲volume部分的内容。

    2018-09-27

  • Chumper
    也就是对于/etc/hosts这个文件而言,同一个pod中不同container修改权限时是修改的宿主机的文件权限,而修改hosts文件内容时,修改的是各自的文件么?
    2018-09-27
    作者回复

    不是……hosts跟volume是一样的,所有容器共同mount了同一份。但是这个文件的内容,是kubelet维护的,在每个容器创建的时候,kubelet会重写它里面的内容。这就是为啥我说不让你手动改hosts……

    2018-09-27

  • Chumper
    请问宿主机的/etc/hosts文件也和/proc类似么,最近遇到个问题,在init-container里修改了hosts文件的权限,在同一个pod中的container中hosts权限也发生了改变,但是在init-container中修改hosts文件内容的话,同一个pod中的container中的hosts文件内容却没有发生改变,这怎么解释?
    2018-09-26
     作者回复
    不通同容器的文件系统是隔离的啊。至于权限,你想想它该归哪个namespace 管呢?

    2018-09-27

    还有有点不太明白,我理解同一个pod中的container只有网络命名空间是共享的啊,难道容器镜像init层的文件也位于同一个volume命名空间吗
    2018-09-27
    作者回复

    你的实验不是已经验证了,容器之间的文件系统就是隔离的啊。但是,既然要共享network ns,那多个容器的hosts文件得一样啊。所以,pod里的hosts其实是一个宿主机上的文件,容器一起bind mount这个文件即可。service account的道理也是类似的。

    2018-09-27

  • Chumper
    请问宿主机的/etc/hosts文件也和/proc类似么,最近遇到个问题,在init-container里修改了hosts文件的权限,在同一个pod中的container中hosts权限也发生了改变,但是在init-container中修改hosts文件内容的话,同一个pod中的container中的hosts文件内容却没有发生改变,这怎么解释?
    2018-09-26
    作者回复

    不通同容器的文件系统是隔离的啊。至于权限,你想想它该归哪个namespace 管呢?

    2018-09-27

  • 洛子墟
    docker使用cgroup限制资源和K8s提供限制资源的功能有什么区别呢?
    2018-09-26
    作者回复

    一个东西啊,为啥会觉得kubernetes 不用docker呢?

    2018-09-26

  • leslie89xlxiao
    参照老师的教程在 /sys/fs/cgroup/cpu 下建立了 container 目录,做完实践想删除该文件夹。
    执行:rm -rf container/
    报错:cannot remove ‘container/cpu.rt_period_us’: Operation not permitted
    执行:lsattr
    报错:lsattr: Inappropriate ioctl for device While reading flags on ./container
    请教下老师,该如何删除该目录。为什么现在 root 权限也删除不了该目录呢
    2018-09-21
  • leslie89xlxiao
    请问下 mkdir container 之后,container 目录无法删除么
    2018-09-20
    作者回复

    可以啊

    2018-09-20

  • 甄心cherishm
    Windows 10也可以运行docker,又是啥原理呢?这篇文章换成Windows视角就不能理解了。
    2018-09-18
    作者回复

    windows是虚拟机容器

    2018-09-19

  • 西堤小筑
    我们会
    2018-09-16
  • 皮卡熊
    必须叫container组吗?这个是怎么关联起来的?
    2018-09-16
    作者回复

    这个随便

    2018-09-16

  • Cloudcat
    不好意思,前面的留言有些错误,我的意思是Dockerfile中一条CMD运行一个脚本,脚本里有两条运行进程的指令,前一条后台运行,第二条前台运行,这样应该可以实现容器在建立的时候运行两个进程了吧?还是说脚本执行的时候其实是一个父进程fork出了两个子进程?正好符合了你说的第二句话“除非你能事先找到一个公共的PID=1的程序来充当两个不同应用的父进程”
    2018-09-13
    作者回复

    都是子进程。但后台运行的那个进程要管理起来就麻烦了。

    2018-09-14

  • 欢喜哥
    鸟哥linux私房菜 老师能画出一些重点和容器相关的章节吗?
    2018-09-13
    作者回复

    基础操作 文件系统 网络

    2018-09-14

  • A 断了线的风筝
    2.虚拟机中可以运行多个进程、而容器中只运行了一个进程、
    2018-09-09
  • A 断了线的风筝
    namespace 可以使容器主机隔离、
    linux 的cgroups 可以对容器使用的资源做限制、
    2018-09-09
  • A 断了线的风筝
    对容器资源的限制、是通过linux cgroups 来实现的、
    容器中运行一个java 进程、要限制java 的 xms 、xmx等参数、是直接进入到容器中对相关参数进行修改吗?
    2018-09-09
  • 在路上
    echo 226>tasks,在我ubuntu16.04怎么执行不了,报错,write error: no such process?
    2018-09-08
    作者回复

    看看进程号是多少啊,咱俩的环境肯定不一样

    2018-09-10

  • kyleqian
    在这种隔离机制下,在k8s的同一个pod里,能不能实现一个容器挂载类似glusterfs,nfs这样的文件系统,另一个直接就可以使用了呢?效果类似是用一个容器管理另外一个第三方应用的容器的文件系统,有什么办法做到呢?
    2018-09-08
    作者回复

    听起来做不到

    2018-09-08

  • jssfy
    试想一下,你这么运行起来的后台进程异常退出后,你如何知晓?由于没有真正的init进程,贸然这么运行起来的孤儿进程是非常棘手的

    1. 正常是如何知晓的呢,应用退出直接导致容器退出?
    2. 正常情况下我们在容器里可以随便启动各种后台进程,所以那是不建议的?
    3. 请问对富容器有何看法呢?
    2018-09-08
    作者回复

    容器直接退出并且可以收到报错。不建议。属于过渡时期遗留环境下的特殊方案。

    2018-09-08

  • maojing
    生产环境用了3年docker,读了作者的文章之后又收获了许多
    2018-09-07
  • 小崔
    systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程
    这样启动的容器,Cgroup限制的只是supervisord的资源呢?还是容器内所有进程的总资源?
    2018-09-07
    作者回复

    看你设置的被限制进程号了

    2018-09-08

  • 煎饼
    简单明了
    2018-09-07
  • V V
    为什么说容器中无法同时运行两个不同的应用?实际上可以的。设置CMD参数为一个脚本,脚本中启动多个不同的进程。或者通过exec执行bash进入容器后,手动启动多个在后台运行的进程。
    2018-09-07
    作者回复

    试想一下,你这么运行起来的后台进程异常退出后,你如何知晓?由于没没有真正的init进程,贸然这么运行起来的孤儿进程是非常棘手的

    2018-09-07

  • 阿鹏
    请教一下,我们现在是一台服务器上跑好几个应用的,迁移或者扩展的时候直接拷贝一个原系统的镜像然后环境就都有了,对于这种情况需要再把每个应用跑在docker里吗,有什么利弊?
    2018-09-06
  • cxyfreedom
    1. 所以除了时间,还有什么比较常见是不能被Namespace化的呢?
    2. 所以平时我们 docker run 的时候,是默认本身就有一些 Cgroups 的限制,还是我们指定了参数才会收到限制?
    2018-09-05
    作者回复

    再比如kernel keyring。指定了才有限制。

    2018-09-06

  • silencedoctor
    我看到docker可以Windows上运行linux容器,在linux上运行Windows容器的情况,如果本质上都是使用宿主机的内核请问它是怎样做到的呢
    2018-09-05
    作者回复

    其实是个虚拟机

    2018-09-06

  • eason2017
    精彩,谢谢大师👍
    2018-09-05