将多个 .yml 文件传递给 docker-compose

15

我是一个 Docker 新手。在我的 Docker 文件夹中有两个文件 docker-compose.build.yml 和 docker-compose.up.yml。以下是这两个文件的内容。

docker-compose.build.yml

version: "3"
services:

    base:
        build:
          context: ../
          dockerfile: ./docker/Dockerfile.base
          args:
            DEBUG: "true"
        image: ottertune-base
        labels:
          NAME: "ottertune-base"

    web:
        build:
          context: ../
          dockerfile: ./docker/Dockerfile.web
        image: ottertune-web
        depends_on:
          - base
        labels:
          NAME: "ottertune-web"
        volumes:
          - ../server:/app

    driver:
        build:
          context: ../
          dockerfile: ./docker/Dockerfile.driver
        image: ottertune-driver
        depends_on:
          - base
        labels:
          NAME: "ottertune-driver"

docker-compose.up.yml

version: "3"
services:

    web:
        image: ottertune-web
        container_name: web
        expose:
          - "8000"
        ports:
          - "8000:8000"
        links:
          - backend
          - rabbitmq
        depends_on:
          - backend
          - rabbitmq
        environment:
          DEBUG: 'true'
          ADMIN_PASSWORD: 'changeme'
          BACKEND: 'postgresql'
          DB_NAME: 'ottertune'
          DB_USER: 'postgres'
          DB_PASSWORD: 'ottertune'
          DB_HOST: 'backend'
          DB_PORT: '5432'
          DB_OPTS: '{}'
          MAX_DB_CONN_ATTEMPTS: 30
          RABBITMQ_HOST: 'rabbitmq'
        working_dir: /app/website
        entrypoint: ./start.sh
        labels:
          NAME: "ottertune-web"
        networks:
          - ottertune-net


    driver:
        image: ottertune-driver
        container_name: driver
        depends_on:
          - web
        environment:
          DEBUG: 'true'
        working_dir: /app/driver
        labels:
          NAME: "ottertune-driver"
        networks:
          - ottertune-net

    rabbitmq:
        image: "rabbitmq:3-management"
        container_name: rabbitmq
        restart: always
        hostname: "rabbitmq"
        environment:
           RABBITMQ_DEFAULT_USER: "guest"
           RABBITMQ_DEFAULT_PASS: "guest"
           RABBITMQ_DEFAULT_VHOST: "/"
        expose:
           - "15672"
           - "5672"
        ports:
           - "15673:15672"
           - "5673:5672"
        labels:
           NAME: "rabbitmq"
        networks:
          - ottertune-net

    backend:
        container_name: backend
        restart: always
        image: postgres:9.6
        environment:
          POSTGRES_USER: 'postgres'
          POSTGRES_PASSWORD: 'ottertune'
          POSTGRES_DB: 'ottertune'
        expose:
          - "5432"
        ports:
          - "5432:5432"
        labels:
          NAME: "ottertune-backend"
        networks:
          - ottertune-net

networks:
   ottertune-net:
      driver: bridge

这些docker文件没有问题,我只是对这种方法有一些疑问。

  1. 使用多个文件的目的是什么,而不是只有一个docker-compose.yml文件?
  2. 当与多个文件一起使用时,docker-compose如何工作?
  3. 当我执行 docker-compose -f docker-compose.build.yml build --no-cache 时,会发生什么?
Building base
Step 1/1 : FROM ubuntu:18.04
---> 775349758637
[Warning] One or more build-args [DEBUG] were not consumed
Successfully built 775349758637
Successfully tagged ottertune-base:latest
Building web
Step 1/1 : FROM ottertune-base
---> 775349758637
Successfully built 775349758637
Successfully tagged ottertune-web:latest 
Building driver
Step 1/1 : FROM ottertune-base
---> 775349758637
Successfully built 775349758637
Successfully tagged ottertune-driver:latest 

然后运行 "docker-compose up",我遇到了错误。
rabbitmq is up-to-date                                                                                                                                                                       
backend is up-to-date                                                                                                                                                                        Starting web ... error                                                                                                                                                                                                                                                                                                                                                                    
ERROR: for web  Cannot start service web: OCI runtime create failed: container_linux.go:346: 
starting container process caused "exec: \"./start.sh\": stat ./start.sh: no such file or 
directory": unknown                                                                                                                                                                                                                                                                                                                                                                             
ERROR: for web  Cannot start service web: OCI runtime create failed: container_linux.go:346: 
starting container process caused "exec: \"./start.sh\": stat ./start.sh: no such file or 
directory": unknown                                                                                                                                                                                
ERROR: Encountered errors while bringing up the project.

这个入口点 start.sh 在 docker-compose.up.yml 文件中定义,但我没有将其作为参数传递给 docker-compose build。所以,为什么 docker-compose up 会尝试从一个在构建过程中甚至没有被传递的 yml 文件中运行这个入口点呢?对此感到非常困惑,在谷歌和stackoverflow上也没有找到太多相关信息。
2个回答

29
如果您使用docker-compose -f a.yml -f b.yml ...Docker Compose会合并这两个YAML文件。如果您查看了您发布的这两个文件,一个文件包含所有的运行时设置(如ports:, environment:, ...),如果您已经拥有镜像,那么运行应用程序就足够了。第二个文件仅包含构建时的设置(如build:),但需要本地检出源代码树才能运行。
您可能需要在每次docker-compose调用中都指定这两个文件。
docker-compose -f docker-compose.build.yml -f docker-compose.up.yml up --build

看起来这些文件的作者打算将它们分别运行

docker-compose -f docker-compose.build.yml build
docker-compose -f docker-compose.up.yml up

但请注意,构建文件中的某些运行时选项,比如隐藏镜像中构建的应用程序的volumes:,将永远不会生效。

(您应该能够在“up”YAML文件中删除大量设置,这些设置要么重复了镜像中的内容,要么Docker Compose可以为您提供:container_name:expose:links:working_dir:entrypoint:networks:和(可能)labels:都是不必要的,可以删除。)


谢谢您的回答,这确实解决了我的困惑。volumes:选项不起作用也是一个问题。请详细说明为什么会被忽略以及如何使用volumes:选项。 - corvo
它只在docker-compose up步骤期间起作用,因此如果您单独运行build,则它在那里没有任何效果。它的真正作用是隐藏镜像中的代码,并用来自主机系统的任意内容替换它;我建议完全删除它。 - David Maze
实际上,volumes:选项在原始文件中并不存在,我后来添加了它,因为我想将其用作开发环境。我将其与所有其他运行时选项一起添加到了docker-compose.up.yml中,然后执行以下操作: 'docker-compose -f docker-compose.build.yml build docker-compose -f docker-compose.up.yml up`,它可以正常工作。谢谢。 - corvo

7

与只有一个docker-compose.yml相比,拥有多个文件有什么用途呢?

你可以在不同环境之间共享配置。例如,我将常见的网络和服务器配置保存在一个名为 docker-compose.yml 的文件中。我将开发环境的特定配置,如启用自动重新加载和调试功能的服务器,保存在一个名为 docker-compose.override.yml 的文件中。我将生产环境的特定配置保存在一个名为 docker-compose.prod.yml 的文件中。然后我可以在我的开发环境下使用 docker-compose up --build 运行(默认情况下 Docker Compose 使用 docker-compose.ymldocker-compose.override.yml)。而我可以使用 docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build 来运行生产环境。你可以在专门的文档页面中阅读更多内容。

使用多个文件时,docker-compose是如何工作的?

它以第一个文件作为基础文件,并添加或替换来自后续文件的配置到基本文件中。请参阅相关的文档

当我执行docker-compose -f docker-compose.build.yml build --no-cache ...时

至于你的最后一个问题,根据我所见,很难回答。但与需要两个命令(docker builddocker run)来构建 Dockerfile 不同,docker-compose 只需要一个命令。因此,当你运行 docker-compose up 时,它会查找名为 docker-compose.yml 的文件(如果有的话还会查找 docker-compose.override.yml 文件)。


由于我的 Docker 文件都没有命名为 docker-compose.yml 或 docker-compose.override.yml,那么我该如何从这些文件构建并启动容器呢?目前我的做法是 docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build 然后再运行 docker-compose up。那么我是否也应该将 yml 文件传递给 docker-compose up 呢? - corvo
你只需要运行一次命令(即 docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build)。你目前所做的是两次运行 Docker Compose,一次只使用 docker-compose.prod.yml,然后再次使用 docker-compose.yml - Neel Kamath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接