在这篇摘自 《Docker in Action》 一书的文章中,我将向您展示如何在容器之间打开对共享内存的访问。
Linux 提供了一些工具用于在同一台计算机上运行的进程之间共享内存。这种形式的进程间通信 (IPC) 以内存速度执行。当与基于网络或管道的 IPC 相关的延迟拖累软件性能低于要求时,通常会使用它。基于共享内存的 IPC 使用的最佳示例是科学计算和一些流行的数据库技术,如 PostgreSQL。
Docker 默认为每个容器创建一个唯一的 IPC 命名空间。 Linux IPC 命名空间对共享内存原语(如命名共享内存块和信号量)以及消息队列进行分区。如果您不确定这些是什么也没关系。只知道它们是 Linux 程序用来协调处理的工具。 IPC 命名空间可防止一个容器中的进程访问主机或其他容器中的内存。
在容器之间共享 IPC 原语
我创建了一个名为 allingeek/ch6_ipc 的图像,其中包含生产者和消费者。他们使用共享内存进行通信。清单 1 将帮助您理解在单独的容器中运行它们的问题。
清单 1:启动一对通信程序
# start a producer
docker -d -u nobody --name ch6_ipc_producer \
allingeek/ch6_ipc -producer
start the consumer
docker -d -u nobody --name ch6_ipc_consumer \
allingeek/ch6_ipc -consumer
清单 1 启动了两个容器。第一个创建消息队列并开始在其上广播消息。第二个应该从消息队列中拉出并将消息写入日志。您可以使用以下命令检查每个日志来查看每个日志在做什么:
# start a producer
docker -d -u nobody --name ch6_ipc_producer \
allingeek/ch6_ipc -producer
start the consumer
docker -d -u nobody --name ch6_ipc_consumer \
allingeek/ch6_ipc -consumer
如果您执行清单 1 中的命令,应该会出现错误。消费者永远不会在队列中看到任何消息。每个进程使用相同的密钥来标识共享内存资源,但它们引用不同的内存。原因是每个容器都有自己的共享内存命名空间。
如果您需要运行与不同容器中的共享内存通信的程序,那么您将需要使用 --ipc 标志加入它们的 IPC 命名空间。 --ipc 标志有一个容器模式,它将在与另一个目标容器相同的 IPC 命名空间中创建一个新容器。
清单 2:加入共享内存命名空间
# start a producer
docker -d -u nobody --name ch6_ipc_producer \
allingeek/ch6_ipc -producer
start the consumer
docker -d -u nobody --name ch6_ipc_consumer \
allingeek/ch6_ipc -consumer
清单 2 重建消费者容器并重用 ch6_ipc_producer 容器的 IPC 名称空间。这次消费者应该能够访问服务器正在写入的相同内存位置。您可以通过使用以下命令检查每个日志来查看此工作:
# start a producer
docker -d -u nobody --name ch6_ipc_producer \
allingeek/ch6_ipc -producer
start the consumer
docker -d -u nobody --name ch6_ipc_consumer \
allingeek/ch6_ipc -consumer
请记住在继续之前清理正在运行的容器:
# start a producer
docker -d -u nobody --name ch6_ipc_producer \
allingeek/ch6_ipc -producer
start the consumer
docker -d -u nobody --name ch6_ipc_consumer \
allingeek/ch6_ipc -consumer
重用容器的共享内存命名空间有明显的安全隐患。但如果您需要,此选项可用。在容器之间共享内存比与主机共享内存更安全。