I have recently tried to combine Docker Compose profiles with the extends:
feature to create a slightly modified service B based on the main service A.
a_service:
profiles: [a]
some_settings: ...
ports:
- 8080:8080
b_service:
profiles: [b]
extends: a_service
ports:
- 8090:8080
How I would have liked it to work:
The issue: Service B seems to inherit the profile from A and appends its own profile instead of overriding it (as is the case with other variables). It now has ['a', 'b'] profiles. There doesn't seem to be a way to deploy A but not B, since any profile assigned to A gets passed to B as well.
I have tested this with both the array syntax [a] as well as the list syntax "- a".
Any easy way to use inheritance with profiles? Or would you recommend another approach that doesn't require copying over the entire service?
The behavior you describe is explicit in the Compose Specification definition of extends:
:
Merging service definitions
Sequences: Items are combined together into a new sequence. The order of elements is preserved with the referenced items coming first and main items after.
That is, in the Compose file you show, b
's profiles:
and ports:
are appended to a
's; there is no way to replace them.
Instead of trying to override settings from some base service, you can make this work if you define a new artificial service, giving it a profiles:
value you'll never use (compare Is there any way to disable a service in docker-compose.yml). In that base service, define all of the values that you won't need to override. Both services you're planning to run need to extends:
this base service. Each will add a new profiles:
value to the list, so it will run in both the profile you want and the "never-use-this" profile.
version: "4.0" # Works with all versions of Docker Compose tool version 2.x
services:
base:
profiles: [do-not-use]
build: .
image: registry.example.com/image:${IMAGE_TAG:-latest}
a:
extends: {service: base}
profiles: [a]
ports: ["8080:8080"]
b:
extends: {service: base}
profiles: [b]
ports: ["8090:8080"]
If you only have a couple of settings you want to reuse, then YAML anchors are a popular technique to have the same content in multiple places in the file. This is more useful if you have a complex build:
or environment:
block that you want to reuse, rather than wholesale reusing a previous service definition with some tweaks.
version: "2.4" # Works with all versions of Docker Compose tool, both 1.x and 2.x
services:
a:
build: &build-a
context: .
dockerfile: subdir/Dockerfile
args: [foo, bar, baz]
profiles: [a]
...
b:
build: *build-a
profiles: [b]
...