Using the extension fields feature of Docker Compose 3.4, is it possible to combine a common set of environment variables in array form (or any array) with service-specific declarations? The documentation is unclear as to whether this is supported.
Calling docker-compose up on the the following YAML results in restart, entrypoint, and volumes being set in my-service, but it seems to replace the environment declaration coming from the extension field with the declaration which exists in my-service. I would like them merged.
version: '3.4'
x-service-config: &service-config
restart: "on-failure"
entrypoint: ""
volumes:
- "~/.aws:/home/serviceuser/.aws"
environment:
- "CommonVar1=foo"
- "CommonVar2=bar"
services:
my-service:
<<: *service-config
image: my-service:latest
environment:
- "ServiceVar1=baz"
The merge only happens at the top level. If you want to merge a key at a lower level, use a separate template.
I've recreated the issue using the following compose file. It uses a public image and runs the env command so one can easily follow along without any external dependencies.
Here's a docker-compose.yml that works standalone, showing the 'environment' getting merge in:
version: '3.4'
x-service-config: &ref
restart: 'on-failure'
environment: &env
'foo': 'bar'
'bing': 'baz'
services:
bop:
image: 'alpine'
command: 'env'
<<: *ref
Here's the output, showing that the 'environment' key from the anchor is getting copied over:
$ docker-compose up
Creating network "merge_default" with the default driver
Creating merge_bop_1 ... done
Attaching to merge_bop_1
bop_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
bop_1 | HOSTNAME=d4122a655e1d
bop_1 | foo=bar
bop_1 | bing=baz
bop_1 | HOME=/root
merge_bop_1 exited with code 0
Here's the same compose file, but with 'environment' overridden in the 'bop' service definition:
version: '3.4'
x-service-config: &ref
restart: 'on-failure'
environment: &env
'foo': 'bar'
'bing': 'baz'
services:
bop:
image: 'alpine'
command: 'env'
environment:
'bat': 'far'
<<: *ref
and the corresponding output, showing only bat=far and not the other variables:
$ docker-compose up
Creating network "merge_default" with the default driver
Creating merge_bop_1 ... done
Attaching to merge_bop_1
bop_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
bop_1 | HOSTNAME=efe76cb7e09d
bop_1 | bat=far
bop_1 | HOME=/root
merge_bop_1 exited with code 0
The fix is to break this out into two template/anchors as follows:
version: '3.4'
x-service-config: &ref
restart: 'on-failure'
x-environment-config: &env
'foo': 'bar'
'bing': 'baz'
services:
bop:
image: 'alpine'
command: 'env'
environment:
<<: *env
'true': 'false'
<<: *ref
and here's the output showing the merged values:
$ docker-compose up
Creating network "merge_default" with the default driver
Creating merge_bop_1 ... done
Attaching to merge_bop_1
bop_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
bop_1 | HOSTNAME=617f90a94a7d
bop_1 | foo=bar
bop_1 | bing=baz
bop_1 | true=false
bop_1 | HOME=/root
merge_bop_1 exited with code 0
This works because you're doing the merge at both keys that you want to merge.