7

This is a bit of a follow up to Ben's post is there YAML syntax for sharing part of a list or map, although I am taking it one step farther and inheriting a third time after merging two arrays.

I am creating a docker-compose.yml file and want to do anchors and alias as such

x-template:
  base-template: &base-template
    environemt:
      FOO=BAR
  custom-template-1: &custom-template1
    <<: *base-template
    environment+:
      FOO2=BAR2

services:
  service-1:
    <<: *custom-template1

but I get the error

Unsupported config option for services.service-1: 'environment+'

If I do not use the environment+: at the custom-tamplate-1: level, or if I define environment+: at the service-1: level it works.

I'd like the result to be

services:
  service-1:
    environment:
      FOO:BAR
      FOO2:BAR2

is it possible to achieve what I want?

Anthon
  • 69,918
  • 32
  • 186
  • 246
scott
  • 241
  • 2
  • 10

1 Answers1

20

TL;DR: No, it is not possible


First of all, you have typos in your docker-compose. Please copy the whole docker-compose next time. Here is mine corrected (I didn't want to edit your question) and extended to be testable:

version: '2.4'

x-base-template: &base-template
  image: alpine
  command: env
  environment:
    - FOO=BAR

x-custom-template-1: &custom-template1
  <<: *base-template
  environment:
    - FOO2=BAR2

services:
  service-1:
    <<: *custom-template1

This setup will completely override the environment setting, so only FOO2 is set. I suppose that's why you are asking.

I don't know where you picked up the plus+ syntax, but I can't find anything about it. The only place I found the + is in https://yaml.org/refcard.html, but there is no mention of arrays. That's for strings.

You cannot merge arrays, but you can use key: value syntax for environment, and that can be merged this way:

version: '2.4'

x-base-environment: &base-environment
  FOO: BAR

x-base-template: &base-template
  image: alpine
  command: env
  environment: *base-environment # This is only necessary if you want variables in base-template

x-custom-template-1: &custom-template1
  <<: *base-template
  environment:
    <<: *base-environment
    FOO2: BAR2

services:
  service-1:
    <<: *custom-template1

The merging we use, the Merge Key Language-Independent Type, doesn't support nested merging. That means that the key is either picked from one object, or the other, no combination. And that's the intended design. It's friendly behaviour most of the time. The sad thing is, there is no yaml feature (or any I know of) that supports nested merging; the simple answer to your questions is, "No, it is not possible."


Sidenote: GitLab tried to solve this for their CI config with proprietary extends, which supports

reverse deep merge based on the keys

michalhosna
  • 7,327
  • 3
  • 21
  • 40
  • 1
    Should have accepted as answer long ago. Thank you for the good explanation. – scott Mar 12 '19 at 14:50
  • `extends` is Docker but was dropped in v3. If just overriding likes this, it's worth looking at setting environment variables from the command line, `-e`, or with an [override file](https://docs.docker.com/compose/extends/), whichever involves the least typing. – Nomas Prime Nov 01 '19 at 10:32
  • @NomasPrime > Docker but was dropped in v3. But there is no reason to switch to v3, v2 is still developed. More on this here: https://stackoverflow.com/a/53636006/2866778 – michalhosna Dec 14 '20 at 12:41