Dockerfile 中的 运行 和 docker-compose.yml 文件中的命令之间的区别

The difference between RUN in a Dockerfile and command in a docker-compose.yml file

这个问题一直困扰着我,因为我想遵循最佳实践,如果不知道每个命令的用途,我可能会犯架构错误。那么,谁能向我解释一下何时在 Dockerfile 中使用 RUN 命令与在 docker-compose.yml 文件中使用 command 指令?

据我了解,Dockerfile 应该包含构建映像的说明,因此通过逻辑命令(例如迁移数据库)应该在此处。 docker-compose.yml 文件包含构建环境的说明。不过,我感到困惑的是为什么似乎有选项可以在两个文件中放置 运行 命令的说明。

Dockerfile 是关于如何构建新的 image 的收据,例如docker build,而 docker-compose 用于编排启动(多个)容器

Dockerfile 中的 RUN 指令在映像的构建阶段执行,其结果将提交给映像。 docker-compose.yml 中的 command 属性对应于 CMD directive in a Dockerfile and to the optional command parameter of docker run 并指定在 启动 基于给定图像的新容器时要执行的命令。

另请参阅:

假设您想将申请的副本发送给同事。他们不需要整个源代码树,因为他们只是想 运行 应用程序。您可以想象 运行 使用一些命令来构建和安装应用程序,创建结果的 tar 文件,然后将该 tar 文件发送给它们。那些“构建和安装”命令应该是 Dockerfile RUN 命令。

I'm confused about [...] why there seem to be options to put instructions for running commands in both [Dockerfile and docker-compose.yml].

举一个非常典型的例子,假设您有一个 Python Django 应用程序,它也恰好能够 运行 使用 Celery 框架在后台执行一些任务。主 Web 服务器和后台工作程序都具有完全相同的源代码;这只是启动容器时 运行ning 什么命令的问题。

在这种情况下,您的 Dockerfile 会声明一些有用的默认值 CMD,对 运行 Django 应用程序说:

FROM python:3.10
...
CMD ./manage.py runserver 0.0.0.0:8000

在您的 docker-compose.yml 文件中,您可以 运行 此图像 两次 ,但对于第二个,您将覆盖 command: .

version: '3.8'
services:
  app:
    build: .
    ports: ['8000:8000']
    # using the default Dockerfile CMD
  worker:
    build: .
    command: celery -A proj worker

特别是如果您的应用程序只需要一个命令 运行,最好在 Dockerfile 中声明它。我猜 90% 以上的案例不需要 Compose command:。没有理由在 Compose 文件中重复相同的命令。

我会避免在 CMDcommand: 中编写扩展的 multi-line 命令。相反,编写一个 shell 脚本来完成您需要做的所有事情,COPY 将脚本放入图像中,并将该脚本设置为您的 CMD。 (还有一种模式我喜欢使用 ENTRYPOINT 来完成设置任务并以 exec "$@" 到 运行 结束 CMD。)

... a Dockerfile should contain [...] commands which for instance migrate a database ...

这实际上行不通。记住我假设的tar问题:如果构建指令的一部分 运行 数据库迁移,然后您只将文件系统的 tar 文件发送给您的同事,他们的数据库不会有 运行 迁移。出于几个原因,如果您的数据库也在容器中,图像构建序列将无法联系数据库(如果它根本 运行ning)。

例如, 中有更多关于此主题的讨论。请注意,那里的答案有 multi-line Compose command:;如上所述,我可能会把它写成一个脚本,并让脚本成为图像的 CMD