摘自“Docker in Action”一书,在本文中,我将展示如何在容器之间共享内存空间。
Linux为在同一台计算机上运行的进程之间提供了一些共享内存的工具。进程间通信(IPC)这种形式的性能表现基于存取速率。当与网络或基于管道的IPC相关等延时拖累的软件性能低于要求时,我们才经常使用它。基于共享内存的IPC应用中最好例子是科学计算和一些流行的数据库技术,如PostgreSQL。
Docker默认为每个容器创建一个专属的IPC命名空间。Linux IPC命名空间分区共享内存原语,如命名共享内存块和信号量,以及消息队列。如果你不懂这些是什么,也没关系。只要知道这些是Linux程序用于协调处理的工具就好了。IPC命名空间可防止一个容器中的进程访问主机或其他容器中的内存。
#在容器之间共享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
重用容器的共享内存命名空间有明显的安全隐患。但是如果你还是需要这样的做话,这是可行的。并且在容器之间共享内存比与主机共享内存更安全。