为什么建议在容器中仅运行一个进程?


79

在许多博客文章和一般意见中,有一种说法是“每个容器一个过程”。

为什么存在此规则?为什么不在需要所有进程都可以工作的单个容器中运行ntp,nginx,uwsgi和更多进程?

提到此规则的博客文章:


但是-具有一个非常“胖”的容器并包含数十个进程,以便分阶段推出和运行仍然没有Docker的企业服务器,可以吗?
彼得

@ J.Doe可能不行。容器与虚拟机不同,即使对于小型应用程序,也存在多个小问题-对于企业首次推出,这将是一个为期两年的项目,首先要使其全部在容器中运行。
Evgeny

Answers:


65

让我们暂时忘记高层的建筑和哲学争论。尽管在某些情况下单个容器中的多个功能可能有意义,但出于非常实际的原因,您可能需要考虑遵循“每个容器一个功能”的经验法则:

  • 如果将容器隔离为单个功能,则水平缩放容器要容易得多。需要另一个apache容器吗?在其他地方旋转一个。但是,如果我的apache容器中还装有我的DB,cron和其他碎片,这会使事情变得复杂。
  • 每个容器具有单一功能,可以轻松地将该容器重新用于其他项目或目的。
  • 对于开发人员来说,从生产中拉下组件以进行本地故障排除,而不是整个应用程序环境故障排除,这也使其更加可移植和可预测。
  • 修补程序/升级(包括操作系统和应用程序)可以以更隔离和受控的方式进行。杂乱地处理容器中的多个点不仅可以得到更大的图像,还可以将这些组件捆绑在一起。为什么只需要关闭应用程序X和Y即可升级Z?
    • 以上对于代码部署和回滚也适用。
  • 从安全和隔离的角度来看,将功能拆分为多个容器可以提供更大的灵活性。您可能希望(或要求)在网络级别上(物理上或在覆盖网络内)隔离服务,以保持强大的安全状态或遵守PCI之类的规定。
  • 其他更次要的因素,例如处理stdout / stderr以及将日志发送到容器日志,将容器保持短暂状态等。

请注意,我说的是功能,而不是过程。该语言已过时。官方搬运工文档已经搬走了从说“一个过程”,而不是建议每个集装箱“一和关怀”。


1
仍然,针对线程的低级论点似乎适合这里... web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf
jeffmcneill

很棒的综合答案!
罗伯·威尔斯

这个问题不是操作系统意义上的真正意义上的“过程”吗—码头工人和相关著作使用了不同的术语,现在已经通过改用“功能”一词来阐明?因为否则,虽然我承认这是公认的且评分最高的答案,但我认为它不能回答所提出的问题。
汤姆

27

几天前杀死了“两个进程”容器后,我感到有些痛苦,这使我使用了两个容器而不是启动两个进程的python脚本:

  1. Docker擅长识别崩溃的容器。当主进程看起来不错时,它就无法做到这一点,但是其他一些进程却死于可怕的死亡。当然,您可以手动监视您的过程,但是为什么要重新实现呢?
  2. 当多个进程将其日志发送到控制台时,docker日志的有用性将大大降低。同样,您可以将进程名称写入日志,但是docker也可以这样做。
  3. 对容器进行测试和推理变得困难得多。

这应该是公认的答案。
ClintM '18

同意 虽然也有一些其他的答案与一些伟大的点,关键点是关于码头工人的操控PID 1
布雷特·瓦格纳

13

该建议来自操作系统级虚拟化的目标和设计

容器经过设计,可以通过为容器分配自己的用户空间和文件系统来使其隔离。
这是chroot提供一个隔离的文件系统的逻辑演变,下一步是将进程与其他进程隔离,以避免内存覆盖,并允许多个进程使用相同的资源(例如TCP端口8080)而不会发生冲突。

容器的主要目的是将其打包为过程所需的库,而不必担心版本冲突。如果您在同一用户空间和文件系统中运行多个需要相同库的两个版本的进程,则必须为每个进程至少调整LDPATH,以便首先找到合适的库,并且某些库无法通过这种方式进行调整,因为它们的路径是在编译时在可执行文件中硬编码的,所以请参见此SO问题以获取更多详细信息。
在网络级别,您必须配置每个进程,以避免使用相同的端口。

在同一个容器中运行多个进程需要进行一些大的调整,最终最终无法达到隔离的目的,如果可以在同一用户空间中运行多个进程,共享相同的文件系统和网络资源,那为什么不运行它们在主机本身上?

这是我能想到的大量调整/陷阱的非详尽清单:

  • 处理日志

    无论是已装入的卷,还是在stdout上交错插入,都会带来一些管理。如果使用已安装的卷,则您的容器应在主机上拥有自己的“位置”,否则两个相同的容器将争夺相同的资源。如果docker logs无法轻松识别源,则对stdout进行交错以利用它可能成为分析的噩梦。

  • 当心僵尸进程

    如果容器中的某个进程崩溃了,那么超级用户可能无法清理处于僵尸状态的子进程,并且主机初始化将永远不会继承它们。一旦用尽了可用的pid数(2 ^ 22大约为400万),一堆事情就会失败。

  • 关注点分离

    如果您在同一个容器中运行两个分开的东西,例如apache服务器和logstash,这可能会简化日志处理,但是您必须关闭apache来更新logstash。(实际上,您应该使用Docker的日志记录驱动程序)是否会优雅地停止等待当前会话结束?如果这是一个正常的停止,则可能需要一段时间并花费很长时间才能推出新版本。如果您采取了杀死措施,则会影响用户的日志发送者,因此应避免恕我直言。

最后,当您有多个进程时,您正在复制一个OS,在这种情况下,使用硬件虚拟化听起来更符合这种需求。


3
我认为这些论点令人信服。具有多个容器的进程与在主机上运行的进程之间存在巨大差异。尽管解释容器的初衷有些相关,但避免多进程容器并不是真正有说服力的理由。IOW,您正在用“为什么”回答“为什么不”,这并不是那么有用。在同一个容器中运行多个进程可能非常方便-这就是为什么。为什么不还有待解释。
阿萨夫·拉维

1
您尚未详细说明自己要进行的调整。而且,您并没有说过这种调整比设置多个容器还需要更多的工作。让我们举一个具体的例子:您经常看到打包好的docker映像,这些映像监督了一些主进程和一些辅助进程的运行。这很容易设置;可以说与分离容器一样容易。例如应用程序和日志托运人。因此,我相信,您有责任争论为什么事实并非如此。
阿萨夫·拉维

1
顺便说一句,我确实相信有反对多进程容器的有效论据,但您没有提及其中的任何一个。但是无论如何,这都不是一个明确的案例。在某些情况下,允许多个过程是完全可以接受的。哎呀,一些非常受欢迎的图像会产生几个子过程-那也很邪恶吗?我的意思是要权衡利弊,而您的回答只能描绘出缺乏细微差别和细节的单方面图片。
阿萨夫·拉维

1
有趣的……听起来我们对此有类似(相同)的看法。在这种情况下,也许您应该忽略它,因为它来自某个想要获得评论家徽章的人 ……并决定滥用您的答案来获得该徽章……
Pierre.Vriens

1
我不会“急于”得出结论……我只是建议您忽略它。但是,“您”无法改变自己对谁是答案的匿名否定者的看法。无论如何,是时候继续前进了……
Pierre.Vriens

6

在大多数情况下,这不是全部或全部。“每个容器一个过程”的指导源于容器应用于不同目的的想法。例如,容器不应同时是Web应用程序 Redis服务器。

在某些情况下,只要两个进程都支持单个模块化功能,就可以在单个容器中运行多个进程。


2

我将这里称为服务的过程是1个容器〜1个服务,如果我的任何服务失败,那么我只会旋转相应的容器,并在几秒钟之内再次恢复正常。因此,服务之间不会有任何依赖关系。最佳做法是使容器大小小于200 MB,最大小于500 MB(Windows本机容器的例外大于2 GB),否则,它将与虚拟机类似,但性能不完全相同。此外,还要考虑一些参数,例如扩展,如何使服务具有弹性,自动部署等。

而且,这纯粹是您的电话,您需要如何使用最适合您的环境并为您自动实现事物的容器技术,在polygot环境中创建诸如微服务之类的架构模式。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.