在 RHEL上运行带有主机安装卷的 docker 容器时docker
,我观察到在容器启动之前docker-compose
有大量磁盘 I/O(使用)。dstat
I/O 与dockerd
进程相关联,我可以通过挂载或移除主机卷来明确增加或减少 I/O。如果我不挂载任何主机卷,容器会立即启动。如果我挂载的卷覆盖了文件系统的大部分,则 I/O 非常重要,在我的情况下,大约需要 20 Gb,这大约需要三分钟才能启动容器。在某些情况下,这会导致docker-compose up
编排简单地超时。
典型的运行命令如下所示
docker run -it --rm --name my_container \
-v /host/app/src:/app:ro,z \ # host volume defined here
-v my_ro_data:/data/read_only/files:ro,z \ # external named volume
-v /host/data/write:/data/container_output/files:z \ # another host volume
my/image:latest
无论卷是否是预定义的命名卷,以及是否使用语法将其标记为只读,都会发生 I/O。但是在定义外部命名卷时,它看起来像这样:
docker volume create \
--driver local \
--opt type=none \
--opt o=bind \
--opt device=/host/data/files \
my_ro_data
我假设 I/O 与覆盖文件系统有关,但我找不到任何关于正在写入的内容、写入位置以及如何优化配置以在容器启动之前需要更少 I/O 的明确解释. 明明不是整卷的内容,所以好像有什么区别?但是,想象一下我有某种大规模的数据管道,并且我想将我的容器指向包含 TB 文件的主机源或目标目录......如何安装主机卷而不影响容器启动延迟?
更新:
根据@BMitch 的指导,我专注于 SELinux 相关":z"
标签。
简要历史:
最初(大约在发布前一年)没有此标签的 RHEL w/SELinux 服务器上的 docker 容器无法访问已安装的卷。尽管--volumes-from
是一个不同的 cli 选项,但它具有其他来源在解决访问问题时所指的最佳解释:
像 SELinux 这样的标签系统要求在安装到容器中的卷内容上放置适当的标签。如果没有标签,安全系统可能会阻止在容器内运行的进程使用内容。默认情况下,Docker 不会更改操作系统设置的标签。要更改容器上下文中的标签,您可以将两个后缀 :z 或 :Z 添加到卷挂载中。这些后缀告诉 Docker 重新标记共享卷上的文件对象。z 选项告诉 Docker 两个容器共享卷内容。因此,Docker 使用共享内容标签来标记内容。共享卷标允许所有容器读/写内容。Z 选项告诉 Docker 使用私有非共享标签标记内容。
这个解释伴随着一个警告:其他地方:
使用 Z 选项绑定挂载系统目录(例如 /home 或 /usr)会使您的主机无法运行,您可能需要手动重新标记主机文件。
所以我用过":z"
,有时":ro,z"
一切都很好。
事实证明,这个标签导致了预启动磁盘 I/O。我不太了解 SELinux 的安全性和标签,但我想 I/O 是在挂载卷时实际更改文件标签,因此文件越多,磁盘 I/O 越长。
我的观察是删除标签,什么都不做,会导致相同的行为。这意味着 docker 引擎现在的默认行为是将 SELinux 挂载的卷视为标记为":z"
. 我相信这是过去一年可能引入的一种新行为……或其他一些系统更改……因为现在可以在没有标签的情况下访问卷(或者标签可能是永久性的,允许后续的 docker 访问)。
但是,删除:z
并不能解决 I/O 和较长的启动时间。然后我发现这个 github 对话声称 :z 和 :Z 都是潜在危险的选择和评论:
如果您的容器确实需要更广泛地访问系统目录,那么将“--security-opt label:disable”与“docker run”命令一起使用是更好的选择。请注意,使用上述选项将禁用对该容器的 SELinux 检查。
所以我添加了这个选项,事实上,卷是可访问的,并且磁盘 I/O和启动延迟为零(或最小)。
话虽如此,我真的不明白它的影响,--security-opt label:disable
并欢迎任何额外的建议或解释。