首页 > 解决方案 > 在不同的 docker-compose 文件之间共享的命名容器

问题描述

我见过一些类似的问题,但没有找到适合自己的解决方案。

我有 2 个 docker-compose 文件,我创建了一个命名卷,我目前正在像这样使用它:

app:
    ...
    volumes:
      - volume_static:/path/to/container
    ...
...
volumes:
  ...
  volume_static:
    external:
      name: static
  ...
...

在构建过程中,脚本会在此卷中添加一些新文件,但随后以完全相同的方式挂载卷的第二个 docker-compose 无法访问新数据,我需要重新启动它让它工作。

这是正确的方法吗?

我只需要从一个 docker-compose 将一些新文件推送到卷中,然后直接在第二个 docker-compose 上查看它们(是的,我知道,docker,但是说指定 compose 可以更好地了解我的问题)而无需重新启动并建立服务

这可能吗?

谢谢!

标签: dockerdocker-composevolumes

解决方案


Docker 认为命名卷用于保存用户数据以及其他不属于正常容器生命周期的内容。

如果你用一个空卷启动一个容器,只有在你第一次运行它时,Docker 才会将镜像中的内容加载到卷中。Docker 没有为此提供更新机制:由于该卷可能包含用户数据,因此 Docker 不能冒着用更新后的映像中的内容覆盖文件来破坏它的风险。

这里最好的方法是完全避免共享文件。如果文件类似于后端应用程序的静态资产,您可以COPY --from使用后端应用程序的图像名称和标签 ( ) 将后端图像中的这些文件转换为代理图像COPY --from=my/backend ...。这完全避免了对音量的需求。

如果您确实必须在卷中共享文件,那么提供文件的容器需要在启动时自行负责复制文件。入口点脚本是最容易做到这一点的地方;它为您提供了一个挂钩,可以在容器启动(并且卷存在并已安装)但在运行主容器进程之前运行事物。

#!/bin/sh
set -e

# Populate (or update) the shared static tree
cp -r ./app/assets /static

# Now run the image CMD
exec "$@"

将此脚本ENTRYPOINT放在您的 Dockerfile 中;它必须使用 JSON 数组语法。你可以CMD保持不变。如果您已将解释器和文件名拆分为单独的ENTRYPOINTCMD您可以将它们组合成CMD一行(并且可能无论如何都应该这样做)。

...
ENTRYPOINT ["entrypoint.sh"]
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

在构建生命周期方面,镜像是在没有任何周围 Compose 生态系统的情况下构建的;他们不知道网络环境、卷、环境变量、绑定挂载;因此,当您重建映像时,您会构建一个新的更改映像,但根本不修改卷。第一次运行整个文件时,由于命名卷是空的,它会填充卷中的内容,但这只会在你第一次运行时发生。

重建镜像和重启容器在 Docker 中是非常常规的,我不会试图避免这种情况。docker-compose up -d(如果需要更改设置,重新运行将删除并重新创建现有容器。)


推荐阅读