Docker设计:在容器之间交换数据还是将多个进程放入一个容器?

时间:2019-03-06 10:50:51

标签: docker architecture

在当前项目中,我必须执行以下任务(以及其他任务):

  • 从五个IP摄像机捕获视频帧并拼接全景图
  • 在全景图上运行基于机器学习的对象检测
  • 流式传输全景图,以便可以在用户界面中显示

当前,拼接和流式传输在一个docker容器中运行,而对象检测在另一个docker容器中运行,读取全景流作为输入。

由于我需要在保持UI的流分辨率的同时增加对象检测器的输入分辨率,因此我必须寻找从中获取拼接(全分辨率)全景(每帧约10 MB)的替代方法。装订器容器到检测器容器。

我对潜在解决方案的想法:

  • 共享量。潜在的缺点:每帧额外的一次读写可能太慢了?
  • 使用消息队列或Redis。潜在的缺点:体系结构中的另一个组件。
  • 合并两个容器。潜在的缺点:不仅感觉不正确,而且两个容器的基础映像和依赖项也完全不同。另外,我不得不担心并行化。

由于我不是Docker抽屉中最犀利的刀,所以我要问的是有关Docker容器之间快速数据交换的技巧,经验和最佳实践。

2 个答案:

答案 0 :(得分:1)

通常,Docker容器之间的大多数通信都是通过网络套接字进行的。当您在与关系数据库或HTTP服务器之类的内容进行通讯时,这很好。听起来您的应用程序更多是关于共享文件的,而Docker则不太擅长此事。

如果您只希望每个组件一个副本,或者仍在积极开发管道:我可能不会为此使用Docker。由于每个容器都有一个隔离的文件系统和自己的用户ID空间,因此共享文件可能会异常棘手(每个容器必须在数字用户ID上达成一致)。但是,如果您只是以相同用户的身份在主机上运行所有内容,并指向相同目录,则不会有问题。

如果要在生产中扩展规模:我将添加某种共享文件系统和消息队列系统,例如RabbitMQ。对于本地工作,这可以是Docker命名卷或绑定安装的主机目录。像Amazon S3这样的云存储也可以正常工作。设置如下:

  • 每个组件都知道共享存储并连接到RabbitMQ,但不知道其他组件。
  • 每个组件都从RabbitMQ队列中读取一条消息,该消息命名了要处理的文件。
  • 该组件读取文件并执行其工作。
  • 完成后,组件将结果文件写回到共享存储,并将其位置写到RabbitMQ交换器。

在此设置中,每个组件都是完全无状态的。例如,如果您发现它的机器学习组件最慢,则可以运行它的重复副本。如果出现问题,RabbitMQ会记住给定的消息尚未完全处理(已确认)。再次由于隔离,您可以在本地运行该特定组件以重现并解决问题。

该模型还可以很好地转换为基于大规模Docker的集群计算系统,如Kubernetes。

在本地运行此命令,我绝对将单独的关注放在单独的容器中(尤其是如果单独的图像处理和ML任务很昂贵的话)。我建议的设置既需要消息队列(以跟踪工作),也需要共享文件系统(因为消息队列往往没有针对10 MB以上的单个消息进行优化)。您可以在Docker命名卷和主机绑定挂载之间选择,后者是随时可用的共享存储。绑定挂载更易于检查和管理,但在某些平台上传说上很慢。我认为命名卷相当快,但是您只能从Docker容器访问它们,这意味着需要启动更多的容器来执行备份和修剪之类的基本操作。

答案 1 :(得分:0)

好的,让我们打开它的包装:

  • IMHO共享卷工作正常,但随着时间的流逝会变得太混乱。尤其是在处理状态服务时。
  • MQ:在我看来,这似乎是最佳选择。是的,它是体系结构中的另一个组件,但是拥有它而不是维护混乱的共享卷或处理大量容器映像(如果您设法合并两个容器映像)是有意义的
  • 是的,您可以这样做,但不是一个好主意。考虑到您的用例,我将继续进行假设,假设您拥有大量的依赖关系,这可能会导致冲突。同样,很多依赖关系=较大的图像=较大的攻击面-从安全角度来看,这不是一件好事。

如果您确实想在一个容器中运行多个进程,则可以。有多种实现方法,但是我更喜欢supervisord

https://docs.docker.com/config/containers/multi-service_container/