0

在 RHEL上运行带有主机安装卷的 docker 容器时docker,我观察到在容器启动之前docker-compose有大量磁盘 I/O(使用)。dstatI/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并欢迎任何额外的建议或解释。

4

1 回答 1

1

有几种可能性,根据您的问题尚不清楚。

如果它是覆盖文件系统,那将是出乎意料的,因为没有文件复制来设置它。这也不能反映您的描述,因为它只发生在卷上,并且每个容器都有一个覆盖文件系统(假设图形驱动程序设置为覆盖)。

对于无根 docker 守护程序(dockerd 不是以 root 身份运行),您可以看到图形驱动程序切换到本地,这确实意味着它为每个层和容器复制图像文件系统,这非常昂贵。但是您都会注意到这一点,因为使用了大量的磁盘空间,并且在没有卷的情况下也会发生这种情况。

对于命名卷,当该卷为空并且使用命名卷创建容器时,docker 将使用映像的内容初始化命名卷。这包括所有文件、权限、所有权和其他元数据。当命名卷已经有数据时,会跳过这个初始化步骤,而主机卷不会发生这种情况。

如果您的问题特定于主机卷,那么我唯一能想到的就是使用卷上的“z”选项设置的 selinux 标签。否则,默认情况下,命名卷和主机卷都是 Linux 绑定挂载,这些通常是非常快速的操作。

最后,不清楚“容器启动之前”是否包括容器内的应用程序进入就绪状态所花费的时间。要将 docker 步骤与容器内的应用程序分开,请将应用程序更改为简单的东西,例如--entrypoint true这将导致容器在创建后立即退出。如果它需要 30 秒才能退出,你知道 docker 很慢,但如果它立即进入退出状态,那么问题与 docker 无关,问题在于你在容器内运行什么。

于 2021-05-24T21:43:22.053 回答