本文摘自“ Docker in Action ”一书,在此文中,我将向您展示如何打开对容器之间共享内存的访问。
Linux向在同一台计算机上运行的进程之间提供了一些共享内存的工具。进程间通信(IPC)的这种形式的性能是由存取速率决定的。当与网络或基于管道的IPC相关联的延迟会使软件性能低于要求时,我们通常会用到它。基于共享内存的IPC使用的最好例子是科学计算和一些流行的数据库技术,如PostgreSQL。
Docker默认为每个容器创建一个唯一的IPC命名空间。Linux IPC命名空间分割共享内存的原语,如命名共享内存块和信号量,以及消息队列。如果你不确定这些是什么,这也没什么关系。只要知道它们是Linux程序用于协调处理的工具。IPC命名空间可防止一个容器中的进程访问主机或其他容器中的内存。
我创建了一个名为allingeek / ch6_ipc的镜像,它包含一个服务提供方和一个服务调用方。他们使用共享内存进行通信。表1将借助在单独的容器中运行实例来帮助您理解这个问题。
#启用服务提供者
docker -d -u nobody --name ch6_ipc_producer \
allingeek/ch6_ipc -producer
#启用服务调用方
docker -d -u nobody --name ch6\_ipc\_consumer \
allingeek/ch6\_ipc -consumer
表1启动了两个容器。第一个容器创建一个消息队列,并开始在其上播放消息。第二个应该从消息队列中拉出消息并将其写入日志。你可以通过使用以下命令来查看每个日志的执行情况:
docker logs ch6_ipc_producer
docker logs ch6_ipc_consumer
如果您执行了表1中的命令,您应该会发现某些东西是错误的,那就是服务调用发永远不会看到队列中的任何消息。每个进程使用相同的密钥来标识共享内存资源,但他们引用的内存不同。原因就在于每个容器都有它自己的共享内存命名空间。
如果您需要运行在不同容器中的通过共享内存进行通信的程序,那就需要使用--ipc标志来加入它们的IPC命名空间。--ipc标志有一个容器模式,将在与另一个目标容器相同的IPC命名空间中创建一个新的容器。
# 移除原有的服务调用方Docker
rm -v ch6_ipc_consumer
# 用一个已加入的IPC命名空间来启用一个新的服务调用方Docker
docker -d --name ch6_ipc_consumer \
--ipc container:ch6_ipc_producer \
allingeek/ch6_ipc -consumer
表2重建了服务调用者容器并重新使用了ch6_ipc_producer容器的IPC命名空间。这一次服务调用者应该能够访问服务器正在写入的同一个内存位置。通过使用以下命令来检查日志,您可以查看生效情况:
docker logs ch6_ipc_producer
docker logs ch6_ipc_consumer
在继续之前,记得要清理你的正在运行的容器。
# 记住 : v选项将会清理掉卷
# 如果容器正在运行中,f选项将会关闭容器
# rm命令会将容器列成表
docker rm -vf ch6_ipc_producer ch6_ipc_consumer
重用容器的共享内存命名空间存在着明显的安全隐患。但是如果你依旧需要如此的话,这个选项还是可行的。至少在容器之间共享内存比与主机共享内存更安全。