Moby: 在 Compose v3 / docker stack deploy 中添加对 `extends` 功能的支持

创建于 2017-02-16  ·  165评论  ·  资料来源: moby/moby

https://github.com/docker/compose/issues/4315可以看出, docker-compose中存在的extends功能尽管存在缺陷,但似乎很受用户欢迎。 但是,到目前为止,它还没有被添加到引擎对 Compose 格式的实现中。 到目前为止,我们已经建议用户在使用 v3 时简单地扁平化他们的 Compose 文件结构,但这是我们想要采用的长期解决方案吗? 我们如何为已经依赖此功能的用户提供清晰的升级路径?

抄送@dnephin @vdemeester

arestack kinfeature

最有用的评论

不仅如此,更改日志还说“这已被删除,有关详细信息,请参阅‘如何升级’”。 我查看“如何升级”以了解有关如何升级的详细信息,以及“有关详细信息,请参阅‘扩展服务’”的内容。 我转到“扩展服务”,认为我最终会看到一种扩展文件的方法,只是看到“这已被删除,有关详细信息,请参阅更改日志”。

在这一点上,这似乎是文档作者正在玩的一个残酷的笑话。

所有165条评论

我已经添加了一些注释https://github.com/docker/compose/issues/4315#issuecomment -280617251 给我带回扩展,因为它存在直到 docker compose 文件 2.1 版本不是一个好主意,但我的主要功能错过是能够声明抽象服务(永远不应该运行,但为了方便起见,可以用来对服务的公共属性进行分组)。

同意 docker/compose#4315 的评论,即extends工作方式有点简陋。

我不会推荐一个解决方案,但是 FWIW,为了显示滥用的程度,这里是装饰我们撰写文件顶部的约定:

#
# Docker Compose configuration
#
# Due to lack of "expressivity" in Compose, we define our own couple of service
# "pseudo-types":
#
#   - image-only services (name: *-image)
#
#     The only goal of these is to build images. No other services build images.
#
#     These have entrypoint overridden to exit immediately.
#
#   - base services (name: *-base)
#
#     These contain common configuration and are intended to be extended.
#
#     Their command (not entrypoint, to keep the original one) is overridden to
#     exit immediately. Service must support a command to exit immediately.
#
#   - task services (name: *-task)
#
#     These are intended for running one-off commands.
#
#     Their default command is overridden to exit immediately. Service must
#     support a command to exit immediately.
#
#   - "real" services
#
#     These are actual services that stay up and running.
#
version: '2'
services:
  ...

我认为 v2.1 中的 extends 是一个不错的选择。 Extends 其实简单易懂,这对于每个环境来说都是一个很好的实践,在 dev、prod 和 env 之间进行一点可读的转换。

其实我有

  • 一个常见的 docker-compose 文件,它显示了基本规则
  • 一个 dev docker compose 扩展它并为开发人员提供设施
  • 一个临时的 docker compose 也扩展了 common 并带有适用于这种环境的设施
  • 生产 docker compose 也扩展了 common 并具有用于该环境的设施,特别是容器复制,有关重新启动的规则等...

这是有效的,我不明白为什么我们应该在这张票中搜索一个完整的重写,但更多的是保留一个有趣的功能。 对于其他技术无法轻松解决的特殊用例,扩展是一个很好的部分。 我对扩展的可能性感到满意。

也阻止我们升级到 v3.x 格式。

我们将 docker 容器定义保存在每个实例文件夹的布局中,其中每个文件夹都包含一个docker-compose.yml ,用于定义手头容器实例的 env 细节。 为了找出常见的东西 (DRY),我们在父文件夹中使用基本服务定义并使用extend

所以当我需要管理一个特定的容器实例时,我只需要将cd放入正确的文件夹中,然后可以直接运行 docker-compose 命令而无需进一步配置(团队成员不需要-f标志需要查找或知道,只需按预期开箱即用)。

我被禁止使用版本 3 撰写文件。

我使用services.yml来定义我的服务的基本布局,然后使用dev.services.yml为我的开发环境扩展它(主要是添加卷),但我喜欢扩展时的(干)可重用性添加。 这不是一个交易破坏者,但它会阻止我转向第 3 版,除非有必须具备的功能。

不过,我不反对用更合适的方法改进 v2.1 的“扩展”解决方案。 抽象服务之类的东西使用起来更安全,功能也更强大。

例如(因为它是抽象的)我可以想象支持抽象卷/挂载点/网络,其中抽象基本服务定义本地挂载点或服务所需的网络,而不定义主机部分 - 这意味着派生服务可以定义/将安装/卷和网络的主机部分映射到他的主机/阶段环境中的适当内容。

据我所知,这是我们现在不能用“扩展”来做的事情的一个例子,并且会打开一些有趣的可能性。

取消扩展功能根本没有帮助。 我们有很多 Web 服务以相同的卷映射、环境变量和标签集启动。 他们也有相同的健康检查政策。 更不用说端口了。 如果您在同一主机中处理多个项目,则使用多个 -f 选项组合撰写文件既乏味又容易出错。

@shin- 这会在 3.2 模式中恢复吗?

我真的,真的很想将extends恢复为文件格式。 我一直在使用它来进一步完善一些项目的抽象服务。 我知道多个-f选项几乎符合要求,但并不总是有效。 例如,我宁愿经常将抽象服务的名称更改为在手头项目的上下文中更有意义的名称。 这是多个-f选项不支持的覆盖。

不过,我不介意丢失确切的extends ,只要它们是在文件中“实例化”抽象服务的其他方式。

我有一个带有通用服务文件和扩展它的一堆服务的设置,主要更改卷,所以我会说我依赖extends功能并且看不到其他好方法来描述我的设置。

--frustrated

+1
我可以看到扁平化 docker-compose 文件的建议背后的逻辑,但我不喜欢在多个项目中复制定义我们的开发服务拓扑的代码的想法。 我们现在将使用 -f 解决方法,使用 shell 脚本,这样开发人员就不必记住在哪些情况下要包含哪些服务。

我希望可以在这里找到一个令人满意的解决方案,以便更好地分解组合结构!

在我的用例列表的顶部是 DRYup 我的配置管理的服务囤积。 我想我可以利用 v3.x 的“扩展”。 我不想回到 v2 ......而且我不想遇到必须使用 -f 进程变通方法的特殊情况。

嘿,有人开始研究这个吗? 我找不到 PR 来跟踪。 它也会为我们在这里简化很多事情(用例与上面描述的非常相似)。

由于版本 3 已冻结并且我需要一种共享通用配置的方法,因此我破解了一个小的解决方法,我想我可以在这里分享(我不确定这是否是正确的地方,但请随时告诉我我还能在哪里分享此信息:))

我不打算在这里详细说明,因为 repo 中有一个自述文件。
祝大家玩得开心☮️

编辑:

对不起,这是链接:D

+1

+1

+1

感谢您的 +1 💃
与此同时,我发现了另一个 docker noop image ,它小了 10^3 倍(由于实际的 noop 是用汇编编写的)。

不幸的是,该存储库中没有许可证。 我已经在facebk上给业主写了一条消息,但他还没有回复。 如果更多人向他询问,他可能会添加许可证:)

可能有助于某些扩展用例(单个文件中的用例)的东西是对 YAML 锚点的支持: https :

看来 JSON Schema 可能无法对它们service must be a mapping, not a NoneType.进行验证。

嘿, @grayside ,yaml 锚确实有效,至少对我而言。 请参阅我上面的评论以了解我如何使用它们。

好的,但是使用一些 noop 服务太难过了不是吗?

特别是对于 env vars,这些 env vars 处理什么样的值? 如果是关于秘密的,请使用群秘密功能(或任何其他秘密解决方案)。 如果是关于设置,我们认为大部分时间设置都是特定于应用程序/服务的,而不是在服务之间共享的。

如果您需要在服务之间共享设置,大多数情况下是在您启动相同的容器映像但用于不同的运行时目的/任务(消费者、生产者、http 工作者等)时。

如果是关于设置,我们认为大部分时间设置都是特定于应用程序/服务的,而不是在服务之间共享的。

我倾向于不同意。 在我目前正在进行的项目中,我将它用于例如卷:

# Volume paths
environment:
  - &volume_a        volume-a:/usr/share/my_project/volumes/volume-a
  - &volume_b        volume-b:/usr/share/my_project/volumes/volume-b
  - &volume_c        volume-c:/usr/share/my_project/volumes/volume-c
  - &volume_d        volume-d:/usr/share/my_project/volumes/volume-d

现在我可以像这样指定这些卷:

volumes:
  - volume-a:
  - volume-b:
  - volume-c:
  - volume-d:

services:
  some-service:
    image: some-image
    volumes:
      - *volume_a
      - *volume_b

  some-other-service:
    image: some-other-image
    volumes:
      - *volume_b
      - *volume_c

  some-third-service:
    image: yet-another-image
    volumes:
      - *volume_a
      - *volume_b
      - *volume_c
      - *volume_d

这使得导航不同的卷变得更容易,而无需考虑您在哪个容器中。恕我直言,这是使您的 docker-compose 设置更加一致、更易于使用和维护的一种方法。

好的,我明白@JanNash,但在下面的示例中,您没有任何 noop 服务,对吗?

但是对于很多情况,anchor 是不够的。

我的案例涉及为同一个项目支持多个环境。 您可以在此处查看我们项目的脚手架

开发时使用devel.yaml ,但在生产中使用prod.yaml 。 还有test.yaml 。 它们都继承自common.yaml并从.env文件中获取一些公共变量。

每一种都有自己的特点:

  • devel 环境旨在提高开发速度,因此它使用生成更快构建的构建参数,使用来自开发人员计算机的应用程序代码安装卷,并添加一些将应用程序与外部世界隔离的虚拟服务。
  • prod 的目标是稳定性,因此它下载并编译所有代码,并将其捆绑在映像本身中,而不是使用卷。 构建速度较慢,但​​更安全。
  • test 的目标和 prod 完全一样,但与外部服务隔离,以避免污染外部世界。

这种简单的分离允许拥有一个非常敏捷和灵活的 DevOps 管道,每个人在不同的阶段使用相同的代码,只需根据使用的环境稍作调整。

我试图移动到撰写文件格式 v3,但不仅extends不支持,而且.env ,所以现在这将是一个维护噩梦(更多是因为缺少.env ,老实说)。 在决定 Swarm 和 DRY 时,我们暂时选择了 DRY,但总有一天我们会需要 Swarm,我希望那一天能再次支持这两个功能...... ☺️

...或者至少我们有一种方法可以从 DRY-ful 解决方案中生成有效的 DRY-less 格式。 我认为docker-compose bundle是为了那个,但现在似乎注定要弃用......

...或者我们有一个不同的工具来制作一切(我也在关注ansible-container )。 但这肯定不是“修复”。

https://github.com/moby/moby/issues/31101#issuecomment -301212524 中的链接包含带有 YAML 锚点工作示例的自述文件。 今天看了一下,再试一次,效果很好。 不知道我在做什么不同。

@ JanNash👍

@Yajo我听到你说的,这是一种解决方法,如果有一个由 docker/moby/docker-compose 提供的好的内置 DRY 解决方案,它会更好一个数量级(无论是正确的参考) . 让我们都希望很快就会到来,因为除此之外,我对 docker compose 很满意👍

~为了缺少 .env 支持,我还破解了一个解决方法(我的项目尚未投入生产,所以我的演讲有点廉价,我知道 :))。 为了在不同的环境中支持不同的环境变量集(例如依赖和图像版本/标签)(对我来说,现在是本地开发和一个小型开发服务器),我使用了两个文件, local.envdevelopment.env ,而不是仅通过docker-compose <command>运行我的命令,我要么将相应的 .env 文件输入到我的 shell 中,要么像这样运行它: (. local.env && docker-compose <command>) 。 仍然是一个黑客,但就目前而言,我对此很满意。~

祝大家玩得开心🚶

甚至可能是两个数量级 :D

@JanNash等等! .env不再支持3吗?

我实际上不知道,我只是在评论中看到它不是。
我一直在使用 local.env 和 development.env 程序,主要是因为我在实现它时不知道 autoenv :D
很抱歉可能造成混淆。

啊, @ Yajo 在此评论中提到缺少 .env 支持。
你能详细说明一下吗,@Yajo?

哦对不起,我的错。 并不是它不起作用,只是您必须用env_file: .env指定它,而不是像以前那样自动检测。 让我们回到最初的问题。

是否讨论将extends丢弃在任何地方? 我很乐意在给出我们的用例之前通读它,因为我认为它是一个非常常用的功能,这很容易理解。

你好,我有一个问题——什么时候? “扩展”支持何时会在 v3 中恢复?

@JanNash你可以得到比那个小得多的方式。 我刚刚在 github 中针对你的 repo 提交了一个问题,我的机器上的 noop 从 750k 减少到 1200 字节。

我看到我现在不能在 swarm 中使用扩展。
任何想法如何使用相同的发布端口启动相同的服务,并在具有 1 个额外环境变量的服务上使用一个容器?

+1 用于扩展对 swarm 堆栈部署的支持

你好,
我们正在运行一个微服务应用程序,该应用程序分布在多个 git 存储库中(每个存储库都有其 docker-compose 文件)。
部署由一个扩展每个服务的“根”docker-compose 文件引导:对我们来说,堆栈部署确实需要这个extends特性。
因此,+1 还可以扩展对 swarm 堆栈部署的支持
谢谢。

您可以使用 YAML 简单继承(请参阅&default<<: *default )作为临时解决方案:

version: '3'
services:
  worker: &default
    build: .
    command: bundle exec rake jobs:work
    env_file:
      - .env
    volumes:
      - .:/app
    depends_on:
      - db
      - redis
    links:
      - db:postgres
  web:
    <<: *default
    command: bundle exec puma -C config/puma.rb -p 3000
    ports:
      - "3000:3000"
  spring:
    <<: *default
    command: bundle exec spring server

当然, extends功能更好

当你扩展一个不同的文件时怎么样?

Yaml 没有文件扩展功能:(

Docker 的贡献者是否对此功能有任何更新? 是否计划重新引入? 如果没有,是否有类似的计划? 如果没有,为什么不..?

@quolpr ,恐怕您的“YAML 简单继承”代码在大多数情况下不会替换extends ,因为“原型”(即&default )将始终被 Docker Compose 解释为名为worker 。 因此,哪些服务 a) 需要明确定义,b) 可能是不需要的。

无论如何,绝对是一个有趣的功能。

@laugimethods您还可以使用 YAML 引用:

version: '3'
services:
  spring:
    build: ./app
    command: /bin/sh -c "bundle exec spring server"
    volumes: &default_volumes
      - ./app:/app:delegated
      - bundle:/bundle:nocopy
  worker:
    build: ./app
    command: bundle exec sidekiq -v -C config/sidekiq.yml
    volumes: *default_volumes

(注意&default_volumes*default_volumes

但我真的不明白为什么extends功能被删除了🤔

仅供参考,为了替换缺少的“扩展”功能,我现在正在使用.yaml文件的组合/合并:
https://github.com/Logimethods/smart-meter/blob/master/README.md#docker -compose

extends作品,简单而成熟,我认为如果有人将扩展视为某种反模式,那么就不要使用它,但请不要将其切断

我可以在不使用extends情况下要求明确解释预期的方法吗? 我广泛使用它,特别是从 Git 子模块中包含的文件继承时,允许定义处理跨应用程序网络布线等的元项目。虽然我很清楚我可以指定多个docker-compose.yml文件和让它们被覆盖,这是否意味着我需要在命令行中指定互连,而不是能够使用extends将它们检入源代码控制? 还是我错过了 v3 中某个地方的一些新功能?

我在多个项目中大量使用extends来为不同的环境和不同的主机继承一组通用的服务属性(阅读:我使用extends从不同的文件继承)。

在昏迷中阅读extends关键字的删除并试图找到不需要菊花链-f docker compose 文件的替代品后,我很好奇删除extends的原因是什么

我理解linksvolume-from但只是避免在基本 yml 文件中使用它们似乎是最好的做法。

不可能仅仅因为它_可能_习惯将汽车颠倒而卸下汽车的车轮......对吗?

PS:noop 和 anchors 看起来很有趣,但它为最简单的项目增加了不必要的复杂性......

作为一个非常非常简单的例子:

common/common.yml

services:
  web:
    image: alpine:3.6
    build: .
    environment:
      DOMAIN:
      PREFIX:

dev/docker-compose.yml

services:
  web:
    extends: ../common/common.yml
    service: web
  ports:
    - "8080:8080"

prod/docker-compose.yml

services:
  web:
    extends: ../common/common.yml
    service: web
  image: the-prod-image:latest-release
  ports:
    - "80:80"
    - "80:443"
  environment:
    NEW_RELIC_KEY:

你是如何在没有extends情况下保持 DRY 原则的?

目前我认为没有理由因此而从 2.1 版升级。

@teodorescuserban

菊花链 -f docker 撰写文件

这有什么问题? 您可以使用短别名创建自己的脚本来调用 docker-compose。

使用以下结构:

常见/common.yml

services:
  web:
    image: alpine:3.6
    build: .
    environment:
      DOMAIN:
      PREFIX:

开发/docker-compose.yml

services:
  web:
    ports:
      - "8080:8080"

prod/docker-compose.yml

services:
  web:
    image: the-prod-image:latest-release
    ports:
      - "80:80"
      - "80:443"
    environment:
      NEW_RELIC_KEY:

命令

docker-compose -f common/common.yml -f dev/docker-compose.yml -p myproject up --build
docker-compose -f common/common.yml -f prod/docker-compose.yml -p myproject up --build

我不知道这个功能。 虽然它使您的 CLI 成为一个 💩,但它可以工作。

我认为,如果这将成为extends官方替代品,那么应该有一种方法可以让它变得更容易。

例如:

docker-compose.yml

version: "3"  # or whatever
extend:
  - ./common/common.yml
  - ./dev/docker-compose.yml
services: # Not required now
  # etc.

通过这种方式,您可以指向一个docker-compose.yml文件,它可以满足您的所有需求。

一个有用的替代方法是在COMPOSE_FILE env var 中支持多个撰写文件。

@Yajo

一个有用的替代方法是在 COMPOSE_FILE 环境变量中支持多个撰写文件。

https://docs.docker.com/compose/reference/envvars/#compose_file

此变量支持由路径分隔符分隔的多个 Compose 文件(在 Linux 和 macOS 上,路径分隔符为: ,在 Windows 上为; )。 例如: COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml 。 也可以使用COMPOSE_PATH_SEPARATOR自定义路径分隔符。

@dermeister0您还可以使用https://github.com/ImmobilienScout24/yamlreader 等工具永久合并这些文件:

> yamlreader common/common.yml prod/docker-compose.yml > docker-compose-prod.yml
> docker-compose -f docker-compose-prod.yml -p myproject up --build

> cat docker-compose-prod.yml
services:
    web:
        build: .
        environment:
            DOMAIN: null
            NEW_RELIC_KEY: null
            PREFIX: null
        image: the-prod-image:latest-release
        ports:
        - 80:80
        - 80:443

@dermeister0很遗憾,感谢您的建议,这是一种笨拙的方法。 使用extends消除了实际知道如何以菊花链方式连接它们的需要。 虽然我可以忍受自己这样做,但我永远无法将此解决方案应用于我亲爱的开发人员。

但是,我不知道COMPOSE_FILE env 变量可以包含多个值。 谢谢@gsong ! 这很棒并且可以使用它(我在.env文件中定义了它)。 这里有一个问题:在基本/通用文件中,我可能还有一些我不需要的服务。

以定义数据库和 Web 容器的平面公共文件为例。 在登台时,您希望它们都聚集在一起,但在生产时,您需要单独的主机用于 db 和用于 Web。

此外,默认情况下会加载 docker-compose.override.yml。

https://docs.docker.com/compose/extends/#understanding -multiple-compose-files

我在 3.3 版中使用这种方法:

  • 将常用的配置选项和服务放在docker-compose.yml
  • docker-compose.override.yml用于特定的开发配置和服务(例如 xdebug);
  • docker-compose.staging.yml用于特定的暂存配置选项。

注意:我不在生产中运行 Docker。

使用这种方法,我可以使用docker-compose build轻松地在本地构建,当我在登台上部署时,我使用:

docker-compose -f docker-compose.staging.yml -f docker-compose.yml build

我正在使用 Apache,并且我没有用于开发和登台的单独虚拟主机文件。 我花了很多时间来避免使用不同的文件。 最后,我看到唯一有效的方法是使用<IfDefine>和环境变量(我在 yml 文件的环境部分设置),例如包含 ssl 配置。 我使用 TLD 和域前缀,所以我可以有类似www.example.local http://www.example.local/ :8080 和www.staging.example.com http://www.staging.example.com / . 在本地,网站在 http 下运行,并在 https 上登台。 使用这种方法,我不必维护不同版本的文件。 我认为在生产中也可以这样做,但正如我所说,我更喜欢避免在生产中使用 Docker,atm。

路径都是亲戚,所以容器可以在任何环境中工作。

我的 2 美分

-菲利波

就我而言,以前我使用过这样的东西:

  • 常见的.yml
  • devel.yml -> 扩展 common.yml
  • prod.yml -> 扩展 common.yml
  • docker-compose.yml -> 本地,git 忽略,符号链接到所需的环境(开发或生产)。

感谢https://github.com/moby/moby/issues/31101#issuecomment -329482917 和https://github.com/moby/moby/issues/31101#issuecomment -329512231,我不知道,现在我可以使用不同的模式移动到 v3:

  • docker-compose.yml -> 以前是 common.yml
  • devel.yml -> 覆盖 docker-compose.yml
  • prod.yml -> 覆盖 docker-compose.yml
  • docker-compose.override.yml -> 本地,git 忽略,符号链接到所需的环境(开发或生产)。

我还可以使用 env 变量进行任何需要的修改,因此在我的情况下,问题已解决。 谢谢! 🎉(对不起,我应该在抱怨之前正确阅读新文档)。

PS:仍然, extends将是一件好事,但至少我们有一个足够公平的选择。 😊

@shin- 首先,我很失望地看到3.0缺少extends功能,但是 YAML 锚点(例如:https://github.com/JanNash/docker-noop)将是一个绰绰有余的更换。

唯一的问题是,就像上面的例子一样,你需要把你的锚点放在docker-compose.yml文件的某个有效部分。

我们能否像 GitLab 一样获得(顶级) templates属性或隐藏键,以便在定义锚点的方式上更加灵活?

依赖 docker-compose.override.yml 的问题在于,它假定您只需要包含一种类型的覆盖和一层覆盖。

就我而言,我希望具有所有本地开发通用的某些行为,但如果开发人员运行的是 Windows、OSX 或 Linux,则可能需要它们略有不同。 为了在 docker-compose v3 上下文中保持这种可管理性,我让 Linux 用户在与登台环境相同的行为上进行操作,这可行,但意味着他们与其他开发人员略有不同。

我避免将-f用于本地开发,因为我发现它很容易出现人为错误,并且依赖它作为太多事情的切换会导致麻烦。 选择一个文件似乎是合理的,选择多个是我小心避免强加的事情。

仅供参考,我认为一旦使用上面提到的x-进行 hack,并且还使用.env项目文件中的COMPOSE_FILE变量菊花链 docker-compose 文件,添加 docker- compose.override.yml 应该可以解决我目前遇到的每个用例。

yml 锚也是我打算在不久的将来使用的一个很好的东西。

x- hack 美人不太满意,但我可以忍受。

谢谢你们的投入!

似乎extends的删除引起了很多心痛,并且要么阻止迁移到 v3,要么求助于黑客。 我喜欢定义一个“模板”(或抽象)服务的能力,它可以承载一些常见的东西(例如更新策略)

我正在开发一个简单的 golang 过滤器实用程序,它可以使用extends预处理 docker compose 文件并吐出一个干净的 v3 文件,扩展解析:
解析组合 docker stack deploy -c docker-compose.yaml
(或 docker-compose up)

这至少适用于您的某些用例/为什么会遇到问题?

@pnickolov那对我来说

我一直在寻找ansible-container (我个人使用 ansible,但还没有在工作中使用),看起来它可以完成我需要的一切,但是像你这样的脚本会更可取(减少流失)

只要它可以递归处理extends:键,我就会很高兴!

好的,看起来我们找到了extends替代品......👍

令人不安的是,Moby 的项目管理似乎并未将保持兼容性视为关键要素。 向前兼容性对于更广泛的采用至关重要,尤其是对于部署到生产中的大型应用程序。 在不能保证像extends这样的核心功能会保留的情况下,我们如何推动 Docker Swarm / Docker EE? 👎
好名声得来不易,失去容易……

就我个人而言,我更愿意依靠本机 YAML 功能来完成由extendsv2语法处理的任务,而不是自定义脚本或更大的解决方案,如 ansible。 我早些时候遇到了类似的问题,并在有使用多个 .yml 文件等解决方案之前开始编写自己的转换器。(https://github.com/schmunk42/yii2-yaml-converter-command) - 但它不是一个可行的解决方案。

对我来说,弃用功能也很好,如果这与版本控制策略一起完成; 你不能永远携带旧东西,即使这意味着我们需要做一些工作。

@schmunk42弃用功能很好,但仅限于:

  • 被移除的功能不再被真正使用,或者是进化的真正阻碍
  • 这是提前宣布的
  • 立即提供迁移路径

不幸的是,这些要求(在我的书中)都不适用于extends的弃用......

@laugimethods您需要使用v3什么?

@schmunk42因为 Swarm:

3.x 版本,最新的推荐版本,旨在交叉兼容 Compose 和 Docker Engine 的 swarm 模式。 这是使用版本:'3' 或版本:'3.1' 等指定的,位于 YAML 的根目录中。

docker stack deploy 命令支持任何版本“3.0”或以上的 Compose 文件

顺便说一句,我的评论不仅与extends ,而且与未来可能发生的任何(痛苦的)弃用有关......

是的,由于群体模式,我们面临着同样的问题。

我首先问自己,为什么 docker CLI 现在能够使用--composer-file输入。 但是从我们对docker/swarm学习来看,在(自我管理的)swarm 上运行堆栈看起来是一件非常复杂的事情,并且有几个很好的理由将其转移到引擎中。

只是要注意我在这里的一些发现......从v2过渡到v3.4远非易事。

我的一些问题:

  • 还有其他不受支持的选项,例如volumes_from ,很容易规避,因为无论如何我们都想删除它
  • .env文件(如docker-compose )对 Docker CLI 没有影响
  • 指定多个撰写文件( docker stack deploy -c docker-compose.yml -c docker-compose.override.yml doro )似乎无法正常工作,没有错误,但在我看来它们也没有正确合并 - 但也没有像docker-compose config这样的命令来检查它
  • docker-compose没有“易于安装”(预发布)的二进制文件,它支持v3.4语法; 像 Docker 边缘
  • 需要使用--scope swarm创建外部网络

抄送:@handcode

使用最新版本

  • 码头工人 17.09.0-ce
  • docker-compose 1.17.0dev

我现在使用这个配置管道来代替我对 _extend_ 和 _noop_ 的使用
保持干燥一点
希望这有助于某人

base.yml (共享定义,这是一个有效的 yaml 文档,因此可以使用 _docker-compose config_ 合并)

version: '3.4'
networks:
  net_back:
    external: true

base-inject.yml (共享锚定义,不幸的是不能添加到base.yml因为锚不能在不同的 yaml 文件中引用,而是将它们作为文本注入foo.yml ,不是一个理想的方式来做到这一点)

x-logging: &logging
  driver: json-file
  options:
    max-size: "50m"
    max-file: "2"

foo.yml (通用堆栈定义,引用base.yml 中的对象, base-inject.yml 中的锚点foo-dev.yml 中覆盖的对象)

version: '3.4'
[[base-inject]]
services:
  foo:
    image: ${DOCKER_REGISTRY}/foo:${IMAGE_VERSION}
    volumes:
      - type: volume
        source: "volfoo"
        target: "/foo"
    networks:
     - net_back
    logging:
      <<: *logging

foo-dev.yml (每个环境堆栈定义)

version: '3.4'
services:
  foo:
    ports:
      - "8080:80"
volumes:
  volfoo:
    name: '{{index .Service.Labels "com.docker.stack.namespace"}}_volfoo_{{.Task.Slot}}'
    driver: local

然后部署命令:

docker stack rm stack_foo && echo "waiting..." && sleep 3 &&
  cat foo.yml | sed -e '/base-inject/ {' -e 'r base-inject.yml' -e 'd' -e '}' > ./foo-temp1.yml &&
  export $(sed '/^#/d' ./dev.env | xargs) &&
  docker-compose -f base.yml -f ./foo-temp1.yml -f foo-dev.yml config > ./foo-temp2.yml
  docker stack deploy --with-registry-auth --prune --compose-file ./foo-temp2.yml stack_foo
  1. 删除旧堆栈
  2. 等待可移动堆栈传播
  3. 将锚点注入通用定义,保存到 tmp 文件
  4. 从文件读取+设置环境文件变量
  5. 使用 docker-compose 将三个文件合并在一起
  6. 部署合并文件

对于那些渴望在 compose 3+ 文件中使用extends ,我刚刚使用了一个名为baclinbaclin这些指令线性化,递归地替换所有extends指令的内容。 这是 alpha 软件,代码是我机器的一部分,因为我目前正在编写代码以支持 Swarm 模式和堆栈部署。 baclin早期版本的平台二进制文件可在此处获得。 请在此处报告任何评论或问题。

这真是令人困惑!
阅读最新 docker 版本 ( v17.09 ) 的文档以及v17.06版本文档,此功能应该可用。

$ head -n1 docker-compose.yml
version: '3'

但是compose up收益

ERROR: The Compose file './docker-compose.yml' is invalid because:
Unsupported config option for services.admin_application: 'extends'

使用extends关键字时。
另外,我在compose更改日志中找不到关于extends删除的任何信息。

现在是哪个?!
像这样的关键信息不应该很难找到或隐藏在一些晦涩的 github 问题中。


$ docker --version
Docker version 17.09.0-ce, build afdb6d4

$ docker-compose --version
docker-compose version 1.16.1, build 6d1ac21

@jottr请参阅文档

extends 关键字在 Compose 文件版本 2.1 之前的早期 Compose 文件格式中受支持(请参阅在 v1 中扩展和在 v2 中扩展),但在 Compose 版本 3.x 中不受支持。

所以如果你想使用extends你需要坚持使用version: '2.1'

我的错。 它应该仍然位于文档的顶部,并带有一个红色的弃用警告标志。

我的错。 它应该仍然位于文档的顶部,并带有一个红色的弃用警告标志。

@jottr只需使用 Github 为其创建一个单独的问题,甚至为此创建一个 PR。 刚刚创建了问题 hiere: https :

在我的情况下,我有docker-compose-override.yml如下:
yaml version: "3.4" services: common: extra_hosts: - "host1:172.28.5.1" - "host2172.28.5.2" - "host3:172.28.5.3" networks: default: external: name: "common-network"
我还有其他几个docker-compose.yml文件需要共享网络和 extra_hosts。 如何使用没有扩展功能来做到这一点?

yaml version: "3.4" services: mongo: image: "mongo" container_name: "mongo" hostname: "mongo" volumes: - "/opt/docker/mongo/default.conf:/usr/local/etc/mongo/mongod.conf" - /opt/data/mongo:/data/db" ports: - "27017:27017" command: "mongod --config /usr/local/etc/mongo/mongod.conf" networks: default: ipv4_address: "172.28.5.4"
如果 docker-compose 支持 yaml 锚点和不同文件之间的引用,那就太好了。 也许,在合并文件后应用锚点和引用。
例如:
yaml version: "3.4" services: common: &common extra_hosts: ... networks: ...
yaml version: "3.4" services: mongo: <<: *common image: "mongo" container_name: "mongo" ...
结果应该是:
yaml version: "3.4" services: mongo: image: "mongo" container_name: "mongo" extra_hosts: // EXTRA HOSTS HERE networks: ...

@sandro-csimas 这可以通过: https: //docs.docker.com/compose/compose-file/#extension -fields
@shin- 可以关闭这张票吗?

@rdxmb我不这么认为。 据我所知,你不能从另一个 docker-compose 文件扩展

我认为这是https://github.com/docker/compose/issues的问题是否正确?

一些调试:

# cat docker-compose.yml 
version: "3.4"
services:
  foo-not-bar:
    << : *common
  foo-bar:
    << : *common
    environment:
      - FOO=BAR 

x-common-definitions-for-all-our-services:
  &common
    image: phusion/baseimage
    environment:
      - FOO=NOTBARBYDEFAULT

这是与
docker stack deploy -c docker-compose.yml test

使用 docker-compose 时:

# docker-compose up 
ERROR: yaml.composer.ComposerError: found undefined alias 'common'
  in "./docker-compose.yml", line 4, column 10

将 yml 文件更改为:

version: "3.4"

x-common-definitions-for-all-our-services:
  &common
    image: phusion/baseimage
    environment:
      - FOO=NOTBARBYDEFAULT

services:
  foo-not-bar:
    << : *common
  foo-bar:
    << : *common
    environment:
      - FOO=BAR

也适用于 docker-compose。

所以认为这也应该适用于多个文件,但事实并非如此:

# docker-compose -f compose-services.yml -f compose-default.yml config > docker-compose.yml
ERROR: yaml.composer.ComposerError: found undefined alias 'common'
  in "./compose-services.yml", line 5, column 10
t# docker-compose -f compose-default.yml -f compose-services.yml config > docker-compose.yml
ERROR: yaml.composer.ComposerError: found undefined alias 'common'
  in "./compose-services.yml", line 5, column 10
# cat compose-services.yml 
version: "3.4"

services:
  foo-not-bar:
    << : *common
  foo-bar:
    << : *common
    environment:
      - FOO=BAR 

# cat compose-default.yml 
x-common-definitions-for-all-our-services:
  &common
    image: phusion/baseimage
    environment:
      - FOO=NOTBARBYDEFAULT

然而,当然,通过简单地使用cat合并它是可能的:

# cat compose-default.yml compose-services.yml > docker-compose.yml && docker-compose up -d
WARNING: The Docker Engine you're using is running in swarm mode.

Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.

To deploy your application across the swarm, use `docker stack deploy`.

Creating network "test_default" with the default driver
Creating test_foo-bar_1 ... 
Creating test_foo-not-bar_1 ... 
Creating test_foo-bar_1
Creating test_foo-bar_1 ... done

使用以下版本在 xenial 上运行:

# docker --version
Docker version 17.11.0-ce, build 1caf76c
# docker-compose --version
docker-compose version 1.17.0, build ac53b73

@rdxmb ,谢谢!
所以我应该使用“cat”命令合并撰写文件并执行最终文件。

我也使用docker-compose config来做到这一点。 环境特定设置的示例:

这是由 CI 管道运行的: docker-compose -f docker-compose.yml -f docker-compose.override.prod.yml config > docker-compose.prod.yml然后我使用docker stack deploy -c .\docker-compose.prod.yml my-stack

为此投票,扩展对 v3 非常有用。

在 v2 中经常使用它,确实非常有用!
+1

我很想在 v3 中看到extends支持。 它会帮助我清理我的docker-compose.yml文件很多。

自从这个问题被提出以来已经快一年了,很明显有很多人需要这个功能。 然而,我根本没有读到 Docker 开发人员对此请求的回应,也没有解释为什么在发布之前它没有包含在 docker-compose v3 中。

如果我们甚至无法为相信新技术的客户沟通或维护功能,那么软件的可悲状态。

对这种情况的一种可能的解释(也可能是当前线程的摘要)是这样的:

  • YAML 锚点/引用加上3.4 的扩展字段实现几乎相同。
  • 可以使多文件工作。 请参阅此线程中的简单cat高级方法。 简单的方法注释显示了 docker-compose 在最后加载多个文件的问题(是否有人为此创建了问题?)。 如果在 docker-compose 中修复了该问题,您甚至根本不需要合并文件。 所以对我来说,希望多文件支持的人应该按照@rdxmb 的建议在/compose/issues继续
  • 考虑过带回extends (请参阅GitHub 项目事件,Docker 团队在这里提供了很好的透明度,谢谢!)并且您可能会将结果解释为“有很多其他东西对他们来说在战略上更重要”,但您可以我猜仍然为extends写一个拉取请求。

对我来说,这是一个完全可以理解的观点。

@aCandidMind同意。

恕我直言,尽管@aCandidMind提到的方法有效,但它们为extends提供的更简单和更清晰的机制增加了复杂性。
也许是我,但是将适度复杂的扩展配置移动到扩展字段变得更加难以阅读和维护。
在阅读了许多评论和帖子后,我仍然不清楚为什么扩展被删除以及这种能力回归的优势是什么。

使用一点点 bash 魔法是可能的,我提出了一个测试回购,这样你就可以自己尝试了。

只需像这样构建您的stack deploy命令:

docker stack deploy --compose-file=<(docker-compose -f docker/prod.yml -f docker/dev.yml config) <stackname>

@tylerbuchea - 这种 bash 魔法的唯一缺点是你可能会得到一个WARNING: Some services (<service-name(s)>) use the '<key>' key, which will be ignored. Compose does not support '<key>' configuration 。 这可能会引起一些混乱。 但是,嘿,它有效👍

@dnmgns你说得对! 感谢您指出了这一点。 就像@joaocc所说的,没有什么比原生支持

@tylerbuchea一种肮脏的方法是将 stderr 重定向到 /dev/null :)
docker stack deploy --compose-file=<(docker-compose -f docker/prod.yml -f docker/dev.yml config 2> /dev/null) <stackname>

一点都不丢人😄

我认为文档应该更明确地说明extend周围的这种混淆。
extend将用户重定向到 how-to-upgrade 文档,how-to-upgrade 文档指向extend的描述extend的决定背后有一个明确的想法。

看:
https://docs.docker.com/compose/extends/#extending -services
https://docs.docker.com/compose/compose-file/compose-versioning/#upgrading

关于@tylerbuchea伟大的基于单行 bash 的解决方案,
遗憾的是,它不支持某些高级 Docker 堆栈功能:

WARNING: Some services (web) use the 'deploy' key, which will be ignored. Compose does not support 'deploy' configuration - use `docker stack deploy` to deploy to a swarm.
WARNING: Some services (web) use the 'configs' key, which will be ignored. Compose does not support 'configs' configuration - use `docker stack deploy` to deploy to a swarm.

不是因为https://github.com/docker/cli/pull/569合并,从 18.03 开始​​, docker stack deploy将支持将多个撰写文件合并为一个。 它没有完全替换 composefile 格式 v2 中的extends键,希望它涵盖更多用例👼

我自己的解决方法是使用yq (如果使用 Bash,可以组合成一行):

yq merge --overwrite docker-stack.yml docker-stack.preprod.yml > merged-docker-stack.yml
docker stack deploy -c merged-docker-stack.yml preprod

@Lucas-C 他们只是警告输出仍将包含您的deployconfig键。 如果您运行docker-compose -f docker/prod.yml -f docker/dev.yml config您可以验证这一点

它用于撰写文件 v3.4 及更高版本。 它支持跨 yaml 引用(部分)。 我完成了这个 zsh 别名/perl 脚本:

alias regen=$'perl -MFile::Slurp=read_file -MYAML=Load,Dump -MHash::Merge::Simple=merge -E \'
  local $YAML::QuoteNumericStrings = 1;
  $n=read_file("/data/docker-compose.yml");
  $s=Dump(merge(map{Load($n.read_file($_))}@ARGV));
  local $/ = undef;
  $s =~ s/\\bno\\b/"no"/g;
  say $s;
  \' $(find /data -mindepth 2 -maxdepth 4 -name docker-compose.yml) >! /data/x-docker-compose.yml'
regen
export COMPOSE_FILE=/data/x-docker-compose.yml
  1. 使用公共部分读取/data/docker-compose.yml。
  2. 递归查找所有 docker compose(例如这个项目中大约有 40 个不同的容器/docker-compose.yml 文件)
  3. 在每个 docker-compose.yml 前面加上 /data/docker-compose.yml 内容
  4. 合并
  5. 将结果保存到 /data/x-docker-compose.yml

优点:perl 是通用工具,所有 perl 模块也是如此,生成速度快。
缺点:我讨厌 hacks,但 DRY 没有其他方法。 最终的 docker-compose 大约有 900 行。 你真的希望我从一开始就支持它作为单个文件吗? 将二进制 docker 与 python docker-compose 与 perl hack 包装在一起是一种耻辱。

你怎么能去掉一个像扩展这样的功能? 这似乎是一个核心功能。

使用docker-compose config管道到docker stack deploy -c -的标准输入选项已经解决了我的问题:

docker-compose -f docker-compose.yml \
               -f docker-compose.extended.yml \
               config \
| docker stack deploy -c - my-stack

我还没有尝试过这个,但我也在docker stack deploy文档中注意到了这一点:

如果您的配置在多个 Compose 文件之间拆分,例如基本配置和特定于环境的覆盖,您可以提供多个--compose-file标志。

以此为例:

docker stack deploy --compose-file docker-compose.yml -f docker-compose.prod.yml vossibility

https://docs.docker.com/engine/reference/commandline/stack_deploy/#compose -file

删除extends的理由是否记录在某处? 官方文档中似乎没有解释,例如这里: https: //docs.docker.com/compose/extends/#extending -services
如果用户能够理解其中的原理,那么用户就可以更好地了解如何应对删除。 谢谢。

@shaun-blake 我最终使用了多个撰写文件。 这似乎是人们使用的方法。 而不是继承,它更像是一种混合。 在构建或运行时,我将正确的环境 yaml 模板复制到 docker-compose.override.yml。

多个泊坞窗撰写的文件(例如: base.ymllocal.ymlprod.yml不允许从其他文件服务使用YAML锚所以因子分解的服务定义不能在多个YML文件中定义.
请注意,此问题是评论最多的第 13位: https : 3Aissue+ is% 3Acomments- desc第 3 位喜欢的

如果用户能够理解其中的原理,那么用户就可以更好地了解如何应对删除。 谢谢。

+1 关于首先删除extends理由的文档...

在将近 1 年半之后仍然没有 _extends_。 Cmon,开发人员,您不要在不提供替代方案的情况下删除某事。

他们做到了,他们提供了一种称为组合的替代方案。 请阅读我在线程中的回答。

-菲利波

年7月2018年,在09:41 30日,小慧刘[email protected]写道:

将近 1 年半之后仍然没有延长。 Cmon,开发人员,您不要在不提供替代方案的情况下删除某事。


您收到此消息是因为您发表了评论。
直接回复本邮件,在 GitHub 上查看https://github.com/moby/moby/issues/31101#issuecomment-408790200 ,或静音该线程https://github.com/notifications/unsubscribe-auth/AAS_0AOynjpfVnVo4ZqciMbmjBmkcLuJb4Nksmd

@dedalozzo ,“在线程中” == ?

请在此处查看我的评论:

https://github.com/moby/moby/issues/31101#issuecomment -329527600 https://github.com/moby/moby/issues/31101#issuecomment-329527600

基本上,您必须使用一系列 .yml 文件来覆盖或更改容器的配置。

请阅读“指定多个撰写文件”

您可以提供多个 -f 配置文件。 当您提供多个文件时,Compose 会将它们合并为一个配置。 Compose 按照您提供文件的顺序构建配置。 后续文件覆盖并添加到它们的前辈。

https://docs.docker.com/compose/reference/overview/ https://docs.docker.com/compose/reference/overview/

这种方法使用组合而不是继承来获得或多或少相同的结果。

年7月2018年,在15:23 30日,谢尔班Teodorescu [email protected]写道:

@dedalozzo https://github.com/dedalozzo ,“在线程中” == ?


你收到这个是因为你被提到了。
直接回复本邮件,在 GitHub 上查看https://github.com/moby/moby/issues/31101#issuecomment-408880809 ,或将线程静音https://github.com/notifications/unsubscribe-auth/AAS_0FZO30NplqHRid_Id8VBOJW7nk5Iks5Iks5Iks5

如果我们结合起来,难道我们不能获得相同的可扩展性吗?
yaml 扩展字段(撰写 2.1+/3.4+)
允许那些x-字段引用其他文件

所以我们可以允许一个根include列表来指定要加载的文件。
它们将被放入x-include并且可以通过标准 YAML 锚点和合并立即使用。



当前撰写 v2.1+
# /docker-compose.yml
version: '2.1'

volumes:
  nginx_file_sockets:
    external: false
    driver: local

services:
  reverse_proxy:
    extends:
      file: reverse_proxy/docker-compose.yml
      service: proxy
    restart: 'always'
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - nginx_file_sockets:/sockets/nginx

  reverse_proxy_test:
    extends:
      file: reverse_proxy/docker-compose.yml
      service: proxy
    restart: 'always'
    ports:
      - "8080:80"
      - "8443:443"
    volumes:
      - nginx_file_sockets:/sockets/nginx

  web:
    extends:
      file: webservice/docker-compose.yml
      service: app
    restart: 'always'
    environment:
      ENVIRONMENT: 'production'
      DB_USER: ${WEB1_DB_USER}
      DB_PASSWORD: ${WEB1_DB_PASS}
    volumes:
      - nginx_file_sockets:/sockets/nginx

  web_staging:
    extends:
      file: webservice/docker-compose.yml
      service: app
    restart: 'no'
    environment:
      ENVIRONMENT: 'staging'
      DB_USER: ${WEB1_DB_USER}
      DB_PASSWORD: ${WEB1_DB_PASS}
    volumes:
      - nginx_file_sockets:/sockets/nginx

# /proxy/docker-compose.yml
version: '2.1'
services:
  proxy:
    build: ./
    volumes:
      - /certs:/certs:ro
# /webservice/docker-compose.yml
version: '2.1'
services:
  app:
    build:
      context: ./folder
      args:
        LINUX_VERSION: 20.s
        LINUX_FLAVOR: dash
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - bootstrap.memory_lock=true
    ulimits:
      memlock:
        soft: -1
        hard: -1




撰写 v3.X 的想法
# /proxy/docker-compose.yml
version: '3.9'
services:
  proxy:
    &proxy
    build: ./
    volumes:
      - /certs:/certs:ro
# /webservice/docker-compose.yml
version: '3.9'
services:
  app:
    &app
    build:
      context: ./folder
      args:
        LINUX_VERSION: 20.s
        LINUX_FLAVOR: dash
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - bootstrap.memory_lock=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
# /docker-compose.yml
version: '3.9'
include:
  - /proxy/docker-compose.yml
  - /webservice/docker-compose.yml

volumes:
  nginx_file_sockets:
    external: false
    driver: local

services:
  reverse_proxy:
    << : *proxy
    restart: 'always'
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - nginx_file_sockets:/sockets/nginx

  reverse_proxy_test:
    restart: 'always'
    << : *proxy
    ports:
      - "8080:80"
      - "8443:443"
    volumes:
      - nginx_file_sockets:/sockets/nginx

  web:
    << : *app
    restart: 'always'
    environment:
      ENVIRONMENT: 'production'
      DB_USER: ${WEB1_DB_USER}
      DB_PASSWORD: ${WEB1_DB_PASS}
    volumes:
      - nginx_file_sockets:/sockets/nginx

  web_staging:
    restart: 'no'
    extends:
      file: web1/docker-compose.yml
      service: app
    environment:
      ENVIRONMENT: 'staging'
      DB_USER: ${WEB1_DB_USER}
      DB_PASSWORD: ${WEB1_DB_PASS}
    volumes:
      - nginx_file_sockets:/sockets/nginx




差异
@@ /proxy/docker-compose.yml @@
-version: '2.1'
+version: '3.9'
 services:
   proxy:
+    &proxy
     build: ./
     volumes:
       - /certs:/certs:ro
 ```

 ```diff
 @@ /webservice/docker-compose.yml @@
-version: '2.1'
+version: '3.9'
 services:
   app:
+    &app
     build:
       context: ./folder
       args:
         LINUX_VERSION: 20.s
         LINUX_FLAVOR: dash
     environment:
       - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
       - bootstrap.memory_lock=true
     ulimits:
       memlock:
         soft: -1
         hard: -1
 ```

 ```diff
 @@ /docker-compose.yml @@
-version: '2.1'
+version: '3.9'
+include:
+  - /proxy/docker-compose.yml
+  - /webservice/docker-compose.yml

 volumes:
   nginx_file_sockets:
     external: false
     driver: local

 services:
   reverse_proxy:
-    extends:
-      file: reverse_proxy/docker-compose.yml
-      service: proxy
+    << : *proxy
     restart: 'always'
     ports:
       - "80:80"
       - "443:443"
     volumes:
       - nginx_file_sockets:/sockets/nginx

   reverse_proxy_test:
-    extends:
-      file: reverse_proxy/docker-compose.yml
-      service: proxy
+    << : *proxy
     restart: 'no'
     ports:
       - "8080:80"
       - "8443:443"
     volumes:
       - nginx_file_sockets:/sockets/nginx

   web:
-    extends:
-      file: webservice/docker-compose.yml
-      service: app
+    << : *app
     restart: 'always'
     environment:
       ENVIRONMENT: 'production'
       DB_USER: ${WEB1_DB_USER}
       DB_PASSWORD: ${WEB1_DB_PASS}
     volumes:
       - nginx_file_sockets:/sockets/nginx

   web_staging:
-    extends:
-      file: webservice/docker-compose.yml
-      service: app
+    << : *app
     restart: 'no'
     environment:
       ENVIRONMENT: 'staging'
       DB_USER: ${WEB1_DB_USER}
       DB_PASSWORD: ${WEB1_DB_PASS}
     volumes:
       - nginx_file_sockets:/sockets/nginx
 ```
<hr>
Resulting in the final version, which should be already yaml parsable:

```yml
# /docker-compose.yml
version: '3.9'
#include:
#  - /proxy/docker-compose.yml
#  - /webservice/docker-compose.yml
x-include:
  /proxy/docker-compose.yml:
    version: '3.9'
    services:
      proxy:
        &proxy
        build: ./
        volumes:
          - /certs:/certs:ro
  /webservice/docker-compose.yml:
    version: '3.9'
    services:
      app:
        &app
        build:
          context: ./folder
          args:
            LINUX_VERSION: 20.s
            LINUX_FLAVOR: dash
        environment:
          - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
          - bootstrap.memory_lock=true
        ulimits:
          memlock:
            soft: -1
            hard: -1

volumes:
  nginx_file_sockets:
    external: false
    driver: local

services:
  reverse_proxy:
    << : *proxy
    restart: 'always'
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - nginx_file_sockets:/sockets/nginx

  reverse_proxy_test:
    << : *proxy
    restart: 'no'
    ports:
      - "8080:80"
      - "8443:443"
    volumes:
      - nginx_file_sockets:/sockets/nginx

  web:
    << : *app
    restart: 'always'
    environment:
      ENVIRONMENT: 'production'
      DB_USER: ${WEB1_DB_USER}
      DB_PASSWORD: ${WEB1_DB_PASS}
    volumes:
      - nginx_file_sockets:/sockets/nginx

  web_staging:
    << : *app
    restart: 'no'
    environment:
      ENVIRONMENT: 'staging'
      DB_USER: ${WEB1_DB_USER}
      DB_PASSWORD: ${WEB1_DB_PASS}
    volumes:
      - nginx_file_sockets:/sockets/nginx

AFAIK 这是一个 YAML 功能,内置在语言规范本身中,以避免在同一文件中重复部分。 当使用不同的文件时,这基本上是不可能的。

您应该向 YAML 规范本身提出该功能。

这个讨论归结为:

  • docker-compose -f file.yml怎么比docker-compose -f file.yml -f file_extension.yml好这么多?
  • 或者:在命令级别接线_vs_在文件级别接线。

只有在命令行上工作时,不便才会变得显着。 我们必须承认这一点。 无论如何,其他一切都是可编写脚本的。

如果是真正的参数,那么docker-compose up service具有优于语义docker-compose -f service.yml up :定义需要的地方发展(又名在命令行)一切docker-compose.override.yml

鉴于语义非常清晰且经过深思熟虑。 采用service.yml _作为命令行使用_可能意味着降低用户体验。 还有另一个论点:虽然乍一看很清楚, docker-compose.yml是什么, service.yml可以是任何东西,真的任何东西。

免责声明:一个挑衅性的意见。 :wink: 我没有考虑到所有可能的用例......

经过长时间的讨论,不确定它是否会成功。 恕我直言,extends 很酷,至少必须小心弃用,然后进行讨论,而不是简单地将其丢弃。

我认为我们可以做的一件事是改进关于 v2 与 v3 的文档故事。 许多人认为 v3取代了v2,但这并不完全正确。 两者都获得了专注于其用例的新功能。 这个 GH 问题已经开始,所以我们可以讨论未来需要哪些功能从 docker-compose 进入 Swarm,以及如何改进文档以使用 docker-compose、compose 文件格式和 Swarm 堆栈。 Extends 在最新的 v2.4 中仍然运行良好。 希望我能帮助提供有关我们今天有哪些解决方案的信息:

v2:仅适用于 docker-compose cli。 开发工作流程专注于单个机器和引擎。 也适用于 CI 构建/测试工作流程。 此版本分支最近在 2017 年 12 月在 v17.12 中收到了新功能

v3:非常适合 Swarm/Kube 堆栈,具有多节点概念并保持对大多数 docker-compose cli 功能的支持。

如果您使用 Swarm 或 Docker Enterprise Kubernetes 堆栈,则没有理由使用 v3 。 坚持使用 v2.4,您将获得所有 docker-compose cli 功能,包括extends、depends_on、扩展字段,甚至带有健康检查的depends_on(以避免等待脚本)。

创建 v3 是为了尝试将单个引擎 docker-compose cli 世界的功能与多节点集群世界合并。 并非所有 v2 功能(如depends_on)在集群中都有意义。 其他功能(如扩展)还没有进入 v3,可能是因为在 v3 存在之前,所有代码都在 docker-compose Python 中,而 v3.0 要支持 Swarm,他们不得不在 docker cli Go 中重写,现在他们在引擎守护进程中再次编写它以最终制作一个尚不存在的 Swarm 堆栈 API。

对于这个问题的新手,还要注意自 3.0 版本以来为解决各种配置、模板和团队工作流问题所做的大量工作:

https://docs.docker.com/compose/extends/#extending -services 上的文档应该以红色强调一个事实,即在 v3 中删除了 extends 关键字,因为它比_note_ 更重要。
我迁移并浏览了文档以了解它为什么不再工作,然后在结束之前遵循几个已解决的问题,然后回到原始文档并注意到措辞。

extends 关键字在 Compose 文件版本 2.1 之前的早期 Compose 文件格式中受支持(请参阅在 v1 中扩展和在 v2 中扩展),但在 Compose 版本 3.x 中不受支持。

可以改写为:

在 Compose 3.x 版中删除了 extends 关键字,但在 Compose 文件版本 2.1 之前的早期 Compose 文件格式中仍受支持(请参阅在 v1 中扩展和在 v2 中扩展)。

这是一个很小的差异,但在浏览文档时很容易被忽略。

@krisrp PR 开始 ^^^

谢谢@BretFisher

是否有计划将 v2 重命名为“version: docker-cli”,将 v3 重命名为“version: swarm/kube”?
考虑到 v3 如何在大多数其他版本控制方案中取代 v2,像这样区分它们会更有意义。 目前两者都在维护和发散,所以除非我弄错了,否则它们似乎都会存在一段时间。

@krisrp相反,增加主要版本号的原因是为了表明兼容性的差异。

@ cpuguy83我不是在暗示别的。 为没有更清楚或明确表示歉意。
多年前,IIRC Gnome 2 和 3 也有这种混乱,当时维护每个的独立分支。

我不想破坏这个线程来讨论版本控制的语义(糟糕的双关语),所以我将把它留在那里。 @BretFisher上周关于改进 v2 与 v3 文档的帖子会对我自己和其他人有所帮助。

@ shin- @cpuguy83一年多之后

我找不到太多关于它的信息,除了“我们可以做不同的事情”(但没有提供实际更好的解决方案)
有技术限制吗? 或者只是缺少拉取请求?

毕竟,我的 compose 2.1 文件仍然运行良好。

不仅如此,更改日志还说“这已被删除,有关详细信息,请参阅‘如何升级’”。 我查看“如何升级”以了解有关如何升级的详细信息,以及“有关详细信息,请参阅‘扩展服务’”的内容。 我转到“扩展服务”,认为我最终会看到一种扩展文件的方法,只是看到“这已被删除,有关详细信息,请参阅更改日志”。

在这一点上,这似乎是文档作者正在玩的一个残酷的笑话。

最终,“堆栈”格式在这里不受控制,它是 Docker CLI 的一部分。

我个人不知道它被排除在 v3 之外的原因......我也不认为我已经看到有人真正尝试将它添加进来。
最好在 docker/cli 中提出这个问题......甚至可能只是一个具有高级文档更改的 PR,就像该功能在那里一样,因此可以讨论它,并且一旦设计获得批准就可以添加实现.

基本上,如果有人想要它,就做一个 PR。 我建议更改文档只是为了确保您不会浪费大量时间以防万一它被拒绝......因为我再次不确定为什么它从 v3 中被省略。

和上面一样。 在再次使用 docker-compose 之前等待这个问题得到解决。

+1 请修复此问题,我们有基于扩展的撰写文件,因此无法将 compose 用于 swarm。

+1 扩展功能

有这方面的消息吗?

还在等它

同样在这里。 还在等。

任何更新?

是否有任何理由说明为什么将其取出?

在 2019 年 8 月 5 日星期一,Jaykishan 的 11:10, notifications @github.com 写道:

任何更新?


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/31101?email_source=notifications&email_token=ABOE6GA4CXY6ESMZMTDSFGDQC74CZA5CNFSM4DANZGS2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXWZFJK853LNMVXWZFJK83DNRL5WWZFJK853DNRL5
或静音线程
https://github.com/notifications/unsubscribe-auth/ABOE6GCEFFJ3SOLDWRWX2IDQC74CZANCNFSM4DANZGSQ
.

任何更新?

所以……快3年了……
但我仍然希望它能降落 :D

如果它不回来,需要有某种替代扩展。 为什么不允许抽象服务? 文件格式将是扁平的,所有服务声明都将在一个文件中。 您可以将抽象服务与 yaml 为节点添加别名的能力(通过& )结合使用,并通过<<:运算符重用这些别名。

为什么是三年!! 看起来你正在工作并且专注于没人关心的事情

这事有进一步更新吗?

这是可悲的。 Terraform 使用组合 - 所以它是可行的,为什么 compose 不能遵循这种良好的设计实践?!
Terraform 模块组成
Terraform 最佳实践

“可怜”,不错。

@Cristian-Malinescu 去吧,请实施它。
这是免费的开源软件。

而不是在这个聊天中像其他人一样抱怨。
真的,这在这里没有任何价值。
正如多次所说,到目前为止没有人想要实现这一点,
所以这只是其他人应该解决的问题,谢谢。

@luckydonald感谢以简单/被动-侵略性的答案推开@Cristian-Malinescu,就像总是没有帮助一样。 @Cristian-Malinescu 这是可行的,因为之前已经完成但已删除,必须(我希望)有一个原因。这个线程上是否有人实际上在 docker-compose 团队中,以便他/她可以阐明事情?

已经提到了略读线程并利用受支持的 YAML 功能。

认为这个例子可能会有所帮助。

@nomasprime谢谢你的发现! 我正在为我的项目在 v2 和 v3 之间做出决定,这解决了这个线程中的大难题。 令人惊讶的是,这些替代解决方案并未在扩展服务功能的官方文档中提及。

很好,听起来是使用文档页面右侧导航栏上的Request docs changes链接的好机会。

@nomasprime 是的,这个想法之前出现在这个线程中。

如果这可以与其他 yml 文件的文件加载机制相结合,那么这就是拥有所有旧的depends功能所真正需要的。

见上文,例如https://github.com/moby/moby/issues/31101#issuecomment -413323610

它不会_可读_,但至少_可能_。

@nomasprime谢谢你的发现! 我正在为我的项目在 v2 和 v3 之间做出决定,这解决了这个线程中的大难题。

@arseniybanayev medium 上的文章v2 也支持 anchors 和 extension fields 。 就我而言,我选择 v2(更具体地说是 2.4),因为我使用docker-compose而不是swarm (并且 v3 不支持 v2 的某些功能,例如限制容器内存

并且 v3 不支持 v2 的某些功能,例如限制容器内存

v3 确实支持限制内存,但该字段在deploy -> resources -> limits https://docs.docker.com/compose/compose-file/#resources 下

@thaJeztah我的意思是, docker-compose (因为我没有在我之前评论中提到的项目中使用 swarm)。 IIRC 部署仅适用于 swarm,不是吗?

为 swarm 和 local 做一个单独的配置有意义吗? 看来这两者是互相矛盾的。 可以理解,Docker 希望增加 swarm 的使用,但很多人只将 compose 用于本地开发。

我从来没有在 ECS、k8s 或 GAE 的生产环境中使用 swarm 和运行容器。

大多数选项对于 swarm/kubernetes 服务和通过 compose 部署的容器都应该是可翻译/可用的。 我必须检查为什么memory限制不适用于docker-compose

仍然缺少扩展功能,但对于我的主要用例,我通过COMPOSE_FILE env 切换到多个 docker compose 文件。 我主要使用它来为 dev 和 prod 使用相同的基本 docker-compose.yml ,并使用不同的密码或配置。

例子:

  • 在开发上: export COMPOSE_FILE= docker-compose.yml` # 默认
  • 产品: export COMPOSE_FILE= docker-compose。 yml:docker-compose.prod.yml ` # 使用两个 yaml 文件

docker-compose.prod.yml我只是用 prod 密码覆盖了环境变量。

这个设置很简单,我不需要总是在docker-compose命令中添加多个“-f”。 我只需要在开发计算机和服务器上设置不同的COMPOSE_FILE env var 并且 git 忽略 docker-compose.prod.yml 文件。

还在等:)

我一直在使用它作为扩展的一种方式:

docker-compose \
  -f ./docker/base.yml \
  -f ./docker/extended.yml \
  up

但是在文件中扩展会更好,不需要额外的 bash 脚本。

我也一直在使用它从 bash 脚本动态扩展:

extended_docker_compose="
  version: '3.5'
  services:
    my-service:
      restart: always
"

echo "$extended_docker_compose" | docker-compose \
  -f ./docker/base.yml \
  -f /dev/stdin \
  up

@dave-dm 那些是普通的旧覆盖!

我相信这是扩展的潜在有效用例

https://github.com/NerdsvilleCEO/devtools/blob/master/doctl/docker-compose.yml#L10

我有一个docker-compose包装器,用于服务环境https://github.com/nowakowskir/docker-compose-wrapper

编辑:另一个可能的用例是有人有一个 LAMP/LEMP 堆栈,他们想要扩展这些服务以用于特定服务,例如 wordpress

自 2017 年以来,在探索 docker compose 替代方案时仍在等待。

@nomasprime 是的,这个想法之前出现在这个线程中。

如果这可以与其他 yml 文件的文件加载机制相结合,那么这就是拥有所有旧的depends功能所真正需要的。

见上文,例如#31101(评论)

它不会_可读_,但至少_可能_。

@luckydonald感谢您指出。 奇怪的是没有内置的 YAML 包含功能,肯定会解决很多问题。

看起来实现第三方解决方案会很容易,但不确定为什么这还没有被带到 v3 🤷‍♂

一点提醒,很多人会喜欢这个功能:)

不将它移植到 v3 btw 的原因是什么?

我忘记了,但它被带走有真正的原因吗?

在 2020 年 5 月 6 日星期三 23:14 Julien Marechal, notifications@ github.com 写道:

一点提醒,很多人会喜欢这个功能:)


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/31101#issuecomment-624919070 ,或
退订
https://github.com/notifications/unsubscribe-auth/ABOE6GGDIVGATP734YJA4UTRQHOLJANCNFSM4DANZGSQ
.

extend相比,yaml 锚点处理这个用例的方式有点不方便。 在我看来,它的强大主要来自于元素的递归合并。 Anchors 可以让你完成 75% 的工作——它们不会递归地合并 yaml; 您的所有合并都发生在顶层。 引用锚定服务模板然后重新定义environment块将导致覆盖锚定服务的环境块而不是合并。 您需要在字典的递归树中锚定和引用每个字典,以匹配extend关键字的行为。

一个例子:

# anchors for the service, environment, deploy, and deploy.placement blocks
# you'll need an anchor for every dict that you want to merge into
x-common-app: &common-app
  image: app:1.0
  environment: &common-app-environment
    common_option: a
    overwrite_option: b
  deploy: &common-app-deploy
    max-replicas-per-host: 3
    placement: &common-app-deploy-placement
      constraints:
        - 'node.labels.app_host==true'

services:
  myapp: << *common-app
    environment: << *common-app-environment
      foo: bar
      baz: xyzzy
      overwrite_option: quz
    deploy: << *common-app-deploy
      replicas: 15
      placement: << *common-app-deploy-placement
        preferences:
          - spread: node.labels.region

# The above yields the following:
services:
  myapp:
    image: app:1.0
    environment:
      common_option: a
      overwrite_option: quz
      foo: bar
      baz: xyzzy
    deploy:
      replicas: 15
      max-replicas-per-host: 3
      placement:
        constraints:
          - 'node.labels.app_host==true'
        preferences:
          - spread: node.labels.region

在这个例子中它可能看起来不那么烦人,但如果你在一个扩展块中模板化多个(10+)服务,它会变得烦人并且可读性较差。

在我心目中理想的情况是YAML锚相结合的办法和extend方法-允许extend只有从顶层荷兰国际集团x-前缀扩展字段块,用更智能的合并特性。

在我的组织中,我们发现 yaml 锚点在语法上有点草率,因此我们基本上在外部 Python 脚本中重新实现了extend功能。 这对我们有用,但这是一种必须处理某些事情的蹩脚方式。 同样,我们必须创建自己的外部工具来处理 v3/Swarm 堆栈的depends_on删除。

最近做了很多gitlab CI YAML。 它正是具有这些功能,这些功能非常适合实现可读和可管理的模板和最终配置:

  • 您可以包含其他 YAML 文件(适用于模板)
  • 您可以扩展(甚至跨项目/通过 https 使用远程资源)。 扩展文档准确地描述了@a-abella 为撰写格式所描述的内容。
  • 你也可以“隐藏”不被认为是真实的东西。 在 compose 格式中它是x- ,在 gitlab CI 中它是一个初始的.

这是使这些文件可以忍受的确切功能集。

我是从 docker docs 发现这个问题的,在我的情况下,我想模板化我的docker-compose设置,作为“解决方法”,我遵循了上面的建议,并决定寻找现有的模板程序。 我不会把我们的时间拿回来,所以我详细介绍了我在这里找到的一些内容,不管关于这个实际功能请求的任何讨论,但是,涉及到的人可能会觉得使用基于 YAML 的模板系统来生成一个撰写文件而不是将此功能集成到docker-compose本身可能更适合封装和为工作选择正确的工具。

在某些情况下,我使用了一个基本的反向代理与 Let's Encrypt 和几个应用程序容器(现在是 Nextcloud,一个给我,一些单独的给朋友) - 在这种情况下,我想制作一个 Nextcloud 容器的模板,所以对于非常相似的设置,我可以避免错误和重复击键。 以下软件包是我尝试过的:

ytt 看起来非常全面,是本地使用 YAML 的唯一选择。 它看起来功能强大,是完成这项工作的正确工具,它使用 Starlark(Python 的超集)直接在 YAML 文件中执行处理。 然而没过多久,模板就变得很乱,乱七八糟的代码片段和YAML的片段,加上字典和数组等Python数据类型和YAML片段的混合(似乎有点像文本处理,有点像使用一个输出像字符串这样的标签的 HTML 模板引擎最终导致了太多的错误和太乱的文件。 Dhall 看起来也很全面,使用独特的母语,可以输出多种格式; 它看起来更像是一种元编程语言而不是模板系统,但是鉴于语法是功能性的并且它的类型非常严格,它很快变得比非结构化 YAML 的简单模板的价值更复杂。 看起来有点像 JSON 和 Haskell 的混合体,它需要太多的思考才能将我需要完成的工作融入到语言中。

有趣的是,Dhall 和 ytt 都很难使用参数化字段名称,否则两者都可以很好地工作,但是我需要让我的实例名称出现在服务名称和卷名称中,并且在这两者中都可以实现这有点难看; 使用散列中的值的参数很容易,但是在键名中使用这些参数很麻烦,或者我找不到如何巧妙地做到这一点,加上 Dhall 强制执行类型安全,这与该概念背道而驰。 使用 Jsonnet 很简单,只需将表达式放在方括号中即可。

CUE 和 Jsonnet 都是面向 JSON 的,但是通过转换器运行它们一点也不难,而且看起来和 Dhall 一样,CUE 有很多强大的功能,并且是从 Jsonnet 的缺点中诞生的,但是在文档中的一部分,很明显这已经是矫枉过正了; 也许有更多的时间来正确学习它会是更好的选择,但似乎 CUE 更倾向于验证和模式而不是简单的模板作业,所以我很快转移到 Jsonnet 并很快完成了这项工作。

最后,只有在我完成所有这些之后,我才意识到我一直在将这些工具与 Liquid 标签或类似 HTML 模板的简单性进行比较,我实际上可能一开始就简单地使用 Liquid。 我只在 Jekyll 站点的上下文中使用它,所以它从来没有发生过我没有获得独立的包,但是有了基本的循环和列表,以及将表达式直接评估为就地文本的能力,这可能会对这份工作也好得多; Jsonify 可能优于 JSON,但 Liquid 可以在纯 YAML 中运行,因此文件再次变得更具可读性。

+1 docker-compose 是我在工作中实施的定制解决方案背后的一个灵感,因为创建这张票是为了支持将大量测试环境迁移到 k8s。 我非常小心地避免花里胡哨,但很快就证明了一个类似的功能是合理的。 哲学讨论(组合与继承等)在我看来就像是对常识的分心(事后看来 - 近 3 年后仍未解决)。 显然,可能会继续使用 docker-compose 的人需要它。

+1:+1:

我之前在dev / test / ci环境中大量使用了此功能,我可以在其中从./config/{dev,test,ci}/compose.yaml子目录路径中的撰写文件进行扩展。 我会有一个.envCOMPOSE_ENV=dev ,但开发人员可以覆盖,显然我会覆盖ci

我对弃用该功能而不是用可以做类似事情的东西替换它感到震惊。 也许只是允许我们使用 jinja2 并做我们想做的事。 我希望 Docker-Compose 不那么反 DRY。 :'(

似乎docker-compose从 v1.27 开始支持extends (https://github.com/docker/compose/pull/7588)。

我大量使用该功能的一个用例是将 docker 图像版本化为代码。 我的 docker dev 和 prod compose 文件都从 docker-images.yml 扩展,其中只列出了基本服务和服务图像的标记版本。

在 v3 中没有找到一个简单的解决方法。

此页面是否有帮助?
0 / 5 - 0 等级