我见过一些类似的问题,但找不到自己的解决方案。
我有 2 个 docker 撰写文件,我创建了一个命名卷,我目前正在像这样使用它:
app:
...
volumes:
- volume_static:/path/to/container
...
...
volumes:
...
volume_static:
external:
name: static
...
...
在构建过程中,碰巧脚本向该卷添加了一些新文件,但是,以完全相同的方式挂载卷的第二个docker-compose无法访问新数据,我需要重新启动它才能使其工作。
这是正确的方法吗?
我只需要从一个 docker-compose 推送卷中的一些新文件,并直接在第二个 docker-compose 上查看它们(是的,我知道,docker,但说指定 compose 可以更好地了解我的问题是什么(,而无需重新启动和构建服务
这可能吗?
谢谢!
Docker认为命名卷用于保存用户数据,以及其他不属于正常容器生命周期的内容。
如果启动一个具有空卷的容器,则仅在第一次运行它时,Docker 才会将内容从映像加载到卷中。 Docker 没有为此提供更新机制:由于卷可能包含用户数据,因此 Docker 不会通过用更新映像中的内容覆盖文件来破坏它。
这里最好的方法是完全避免共享文件。 如果文件类似于后端应用程序的静态资产,则可以使用后端应用程序的映像名称和标记 (COPY --from=my/backend ...
( 将这些文件从后端映像COPY --from
到代理映像中。 这完全避免了对卷的需求。
如果确实必须在卷中共享文件,则提供文件的容器需要在启动时负责复制文件本身。 入口点脚本是最简单的位置;它为您提供了一个钩子,可以在容器启动(并且卷存在并已挂载(时但在运行主容器进程之前运行内容。
#!/bin/sh
set -e
# Populate (or update) the shared static tree
cp -r ./app/assets /static
# Now run the image CMD
exec "$@"
使此脚本成为 Dockerfile 中的ENTRYPOINT
;它必须使用 JSON 数组语法。 您可以保持CMD
不变。 如果您已将解释器和文件名拆分为单独的ENTRYPOINT
和CMD
则可以将它们合并为一个CMD
行(无论如何可能都应该如此(。
...
ENTRYPOINT ["entrypoint.sh"]
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
在构建生命周期方面,构建映像时没有任何周围的 Compose 生态系统;它们不知道网络环境、卷、环境变量、绑定挂载等;因此,当您重建映像时,您构建一个新的更改映像,但根本不修改卷。 第一次运行整个文件时,由于命名卷为空,因此会填充卷中的内容,但这仅在您第一次运行它时发生。
在 Docker 中,重建映像和重新启动容器是非常常规的,我不会试图避免这种情况。 (这是例行公事,如果需要更改设置,重新运行docker-compose up -d
将删除并重新创建现有容器。