As can be seen in https://github.com/docker/compose/issues/4315 , the extends
feature that exists in docker-compose
seems to be popular among users despite its flaws. However, it has so far not been added in the Engine's implementation of the Compose format. So far, we have advised users to simply flatten their Compose file structure when using v3, but is this the long-term solution we want to go with? How can we provide a clear upgrade path for users who have come to rely on this feature?
cc @dnephin @vdemeester
I've added some notes https://github.com/docker/compose/issues/4315#issuecomment-280617251 to me bringing back extends as it exists up to docker compose file 2.1 version is not a good idea but the main feature I miss is to be able to declare abstract services (that should never be runned but could be used to group common properties of services for convenience).
Agreed on comments from docker/compose#4315 that the way extends
worked was a bit spartan.
I won't recommend a solution, but FWIW, to show the extent of abuse, here are the conventions that adorn the top of our compose file:
#
# 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:
...
I think the extends as in v2.1 is a good choice. Extends is actually simple and understandable, this is too a good pratice for each environnement to have a little and readable transformation between dev, prod and env.
Actually, i have
This works, and i don't understand why we should search in this ticket a complete rewrite, but more the keep of an interessing feature. Extends is a good part with special use cases that other techniques can't resolv easily. I'm happy with extends possibilities.
Blocking us from upgrading to v3.x format as well.
We keep our docker container definitions in a folder-per-instance layout, where each folder contains a docker-compose.yml
that defines the env specifics for the container instance at hand. To factor out the common stuff (DRY) we use base service definitions in a parent folder and use extend
.
So when I need to manage a particular container instance, I just need to cd
into the right folder and can then directly run docker-compose commands without further configuration (no -f
flags required that team members need to lookup or know, just works as expected out-of-the-box).
I'm blocked from using version 3 compose files.
I use services.yml
to define the base layout of my services and then extend that with dev.services.yml
for my development evironment (mostly adding volumes) but I like the (DRY) re usability of extends when it was added. It's not a deal breaker but it would keep me from moving to version 3 unless there is a must have feature.
I'm not against improving the v2.1 'extends' solution with something more appropriate though. Something like abstract services could be both more safe to use and more powerful.
For example (since it's abstract) I could imagine supporting abstract volumes/mountpoints/networks, where the abstract base service defines a local mount point or a required network for a service, without defining the host part - meaning a deriving service could then define/map the host part of the mounts/volumes and networks to whats appropriate in his host/stage environment.
That's an example of something we can't do now with 'extends' as far as I know, and would open some interesting possibilities.
Taking away extends feature was not helpful at all. We have a lot of web services started with the same volumes mapped, environment variables and labels set. They also have same healthcheck policies. And Not to mention ports. Combining compose files using multiple -f option is tedious and error prone if you are dealing with multiple projects in the same host.
@shin- will this be brought back on 3.2 schema ?
I really, really would love to get extends
back into the file format. I have been using it to further refine abstract services for a number of projects. I understand that multiple -f
options fits almost the bill, but it doesn't always work. For example, I rather often change the name of the abstract service into something that is more meaningful in the context of the project at hand. This is something that the overriding that occurs with multiple -f
options does not support.
I would not mind loosing the exact extends
though, as long as their is some other way to "instantiate" an abstract service in a file.
I have a setup with a common service file and bunch of services extending it, changing mostly volumes, so I would say I rely on extends
feature and do not see other good way to describe my setup.
--frustrated
+1
I can see the logic behind the recommendation to flatten docker-compose files but I don't like the idea of duplicating the code that defines our development service topology across multiple projects. We'll use the -f workaround for now, with shell scripts so that developers don't have to remember which services to include in which cases.
I'm hoping a satisfactory solution can be found here to enable better factoring of compose structures!
At the top of my use case list is to DRYup my configuration managed hoard of services. I thought I'd be able to take advantage of 'extends' if v3. I don't want to go back to v2... and I don't want to have special cases where I must use the -f process work-around.
Hey, did anyone start working on this? I can't find a PR to keep track. It'd simplify a lot some things for us here as well (use-case very similar to some described above).
Since version 3 is frozen and I needed a way to share common configuration, I hacked a small workaround, which I think I could share here (I'm not sure if this is the right place but feel free to tell me where else I can share this info :))
I'm not going to elaborate on it here, since there's a readme in the repo.
Have a nice one, everyone ☮️
+1
+1
+1
Thanks for the +1s 💃
In the meantime, I've found another docker noop image, which smaller by a factor of 10^3 (due to the actual noop being written in assembly).
Unfortunately, there's no License in that repo. I already wrote a message to the owner on facebk but he didn't answer yet. Maybe he'll add a license if more people query him about it :)
Something that might help some of the extends use cases (those within a single file) would be support for YAML anchors: https://learnxinyminutes.com/docs/yaml/
It appears that the JSON Schema may be failing validation on them service must be a mapping, not a NoneType.
.
Hey, @grayside, yaml anchors do work, at least for me. See my comment above for how I use them.
Ok but it's too sad to use some noop service no?
Especially for env vars, what kind of values those env vars handle? If it's about secrets, use swarm secrets feature (or any other secrets solution). If it's about settings, we're ok that most of the time settings are app/service specific, not intended to be shared between services.
If you need to share settings between services, most of the time it's when you launch the same container image but for different runtime purposes/tasks (consumer, producer, http worker, ...).
If it's about settings, we're ok that most of the time settings are app/service specific, not intended to be shared between services.
I tend to disagree. In the project I'm currently working on, I use it for example for volumes:
# 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
Now I can specify these volumes like that:
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
This makes it way easier to navigate different volumes without having to think about which container you're in. Imho, this is one way to make your docker-compose setup more consistent and easier to use and maintain.
Ok yes I understand @JanNash but in your example below you don't have any noop service right?
But anchors are not enough for many cases.
My case involves supporting several environments for the same project. You can see a scaffolding for our projects here.
When you develop, you use devel.yaml
, but in production you use prod.yaml
. There's also test.yaml
. All of them inherit from common.yaml
and get some common variables from an .env
file.
Each one has its own peculiarities:
This simple separation allows to have a very agile and flexible DevOps pipeline, where everybody uses the same code among different stages, with just little tweaks depending on the environment in use.
I tried to move to compose file format v3, but not only When deciding between Swarm and DRY, we chose DRY for now, but some day we'll need Swarm and I hope that day both features are supported again... ☺️ extends
is unsupported, but also .env
, so right now it would be a maintenance nightmare (more because of the lack of .env
, to be honest).
... or at least we have a way to generate a valid DRY-less format from a DRY-ful solution. I thought docker-compose bundle
was for that, but seems to be doomed to deprecation right now...
... or we have a different tool that makes everything (I'm keeping an eye on ansible-container too). But surely this is not "the fix".
The link in https://github.com/moby/moby/issues/31101#issuecomment-301212524 includes a README with the working example of YAML anchors. Looking it over and trying it again today, it works fine. Not sure what I'm doing differently.
@JanNash 👍
@Yajo I hear you and as said, it's a workaround and it would be better by an order of magnitude if there was a good, built-in, DRY solution supplied by docker/moby/docker-compose (whatever is the correct reference). Let's all hope that will come soon because apart from that, I'm pretty happy with docker compose 👍
~For the sake of missing .env support, I also hacked a workaround (my project's not in production yet, so my talk is a bit cheap, I know :)). To support different sets of env vars (dependency and image versions/tags, for example) in different environments (for me right now, that is local-development and a small dev-server), I use two files, local.env
and development.env
and instead of running my commands by just docker-compose <command>
, I either source the respective .env file into my shell before, or I run it like this: (. local.env && docker-compose <command>)
. Still a hack, but for now, I'm quite happy with this.~
Have a nice one, y'all 🚶
Maybe even two orders of magnitude :D
@JanNash wait! is .env
not supported anymore in 3
?
I actually don't know, I just read in a comment that it wasn't.
I've been using the local.env and development.env procedure mainly because I didn't know about autoenv when I implemented it :D
Sorry for possible confusion.
Ah, @Yajo mentioned missing .env support in this comment.
Could you elaborate, @Yajo?
Oh sorry, my fault. It's not that it is not working, it's just that you must specify it with env_file: .env
, instead of being autodetected as before. Let's return to the original issue.
Is the discussion to drop extends
anywhere? I'd love to read through it before giving our use case because I think it's well understood that it was a pretty used feature.
Hi, I have one question - when? When "extends" support will be back in v3 ?
@JanNash you can get way super smaller than that. I just filed an issue in github against your repo, I got noop down to 1200 bytes from 750k on my machine.
I see that I can't use extend at the moment in swarm.
any ideas how to launch the same service with the same publish ports, and with one container on the service that has 1 extra environment variable?
+1 for extends support in swarm stack deploy
Hi,
We are running a microservices application that is spread in multiple git repositories (each one having its docker-compose file).
The deployment is leaded by one "root" docker-compose file that extends each services : for us this extends
feature is really needed for stack deploy.
So also +1 to extends support in swarm stack deploy
Thanks.
You can use YAML simple inheritance(see &default
, <<: *default
) as temporary solution:
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
Of course, extends
feature is better
How about when you extend a different file?
Yaml doesn't have file extending feature :(
Is there any update on this feature from a contributor to Docker? Is this planned to be re-introduced? If not, are there plans for something similar? If not, why not..?
@quolpr, I'm afraid your "YAML simple inheritance" code doesn't replace extends
in most cases since the "prototype" (i.e. &default
) will always be interpreted by Docker Compose as a service called worker
. Which service a) needs therefore to be well defined, b) might be unwanted.
Anyway, definitely an interesting feature.
@laugimethods you can also use YAML references:
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
(pay attention to &default_volumes
and *default_volumes
)
But I really can't understand why extends
feature was removed 🤔
FYI, to replace the missing "extends" feature, I'm now using a composition/merge of .yaml
files:
https://github.com/Logimethods/smart-meter/blob/master/README.md#docker-compose
extends works, is simply and mature, I think that if someone see extends as some anti-pattern then just don't use that, but please don't cut it off
May I ask for a clear explanation of the intended approach without using extends
? I use it extensively, particularly when inheriting from files contained within Git submodules, allowing a defintion of a meta-project handling cross-application networking wiring, etc. Although I'm well aware I can specify multiple docker-compose.yml
files and have them overridden, does this mean that I would need to specify the interconnections at the command-line, rather than being able to check them into source-control using extends
? Or have I missed some new feature somewhere in v3?
I am heavily using extends
in multiple projects to inherit a common set of service attributes for different environment and different hosts (read: I use extends
to inherit from a different file).
After reading in stupor the removal of extends
keyword and trying to find a replacement that doesn't require daisy chaining -f
docker compose files I am very curious what is the reason for removing extends
.
I understand the problem with links
and volume-from
but just refraining for use them in base yml files seems the best thing to do.
It would be improbable to remove the wheel of a car just because it _might_ get used to turn the car upside down... right?
PS: noop and anchors looks interesting but it adds unnecessary complexity to the most simple projects...
As a very, very simple example:
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:
Just how you keep DRY principles without extends
?
Currently I see no reason to upgrade from version 2.1 due to this.
@teodorescuserban,
daisy chaining -f docker compose files
What's a problem with that? You may create your own scripts with short aliases to call docker-compose.
Use following structure:
services:
web:
image: alpine:3.6
build: .
environment:
DOMAIN:
PREFIX:
services:
web:
ports:
- "8080:8080"
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
I didn't know of that feature. Although it makes your CLI a 💩, it can work.
I think that if that's going to be the official replacement for extends
, then there should be a way to make it easier.
For instance:
docker-compose.yml
version: "3" # or whatever
extend:
- ./common/common.yml
- ./dev/docker-compose.yml
services: # Not required now
# etc.
This way you can point to a single docker-compose.yml
file that does all you need.
A useful alternative would be to support multiple compose files in the COMPOSE_FILE
env var.
@Yajo
A useful alternative would be to support multiple compose files in the COMPOSE_FILE env var.
From https://docs.docker.com/compose/reference/envvars/#compose_file:
This variable supports multiple Compose files separated by a path separator (on Linux and macOS the path separator is
:
, on Windows it is;
). For example:COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml
. The path separator can also be customized usingCOMPOSE_PATH_SEPARATOR
.
@dermeister0 You could also permanently merge those files with tools like 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 thank you for your suggestion unfortunately it is a clunky way out of it. Using extends
remove the need to actually know how exactly you need to daisy chain those. While I can live with doing that for myself, I could never apply this solution to my dear devs.
However, I was not aware that COMPOSE_FILE
env variable can contain multiple values. Thank you @gsong ! That is awesome and can use it (I define it in the .env
file). There is one single issue here: in the base / common files I might also have some services I dont need.
Take for example a flat common file defining database and web containers. On staging you want them all clumped together but on prod you would want separate hosts for db and for web.
Also, docker-compose.override.yml is loaded by default.
https://docs.docker.com/compose/extends/#understanding-multiple-compose-files
I use this approach with version 3.3:
docker-compose.yml
;docker-compose.override.yml
for specific development configuration and services (like xdebug for example);docker-compose.staging.yml
for specific staging configuration options.Note: I don’t run Docker in production.
Using this approach I can easily build locally using docker-compose build
and when I deploy on staging I use:
docker-compose -f docker-compose.staging.yml -f docker-compose.yml build
I’m using Apache, and I don’t have separate virtual host files for development and staging. I have spent quite a bit to avoid having different files. In the end I have seen the only valid approach is using <IfDefine>
and environment variables (that I set in the environment section of the yml files), to include ssl configuration for example. And I use TLD and domain prefix, so I can have something like www.example.local http://www.example.local/:8080 and www.staging.example.com http://www.staging.example.com/. Locally the websites run under http and on staging on https. With this approach I don’t have to maintain different versions of the files. I think the same could be done in production, but as I said I prefer avoiding Docker in production, atm.
Paths are all relatives, so the containers will work in any environment.
My 2 cents
-Filippo
In my case, previously I used something like this:
Thanks to https://github.com/moby/moby/issues/31101#issuecomment-329482917 and https://github.com/moby/moby/issues/31101#issuecomment-329512231, which I didn't know about, now I can move to v3 by using a different schema:
I can also do any needed hacks by using the env variable, so in my case the issue is fixed. Thanks! 🎉 (Sorry, I should have read the new docs properly before complaining).
PS: Still, extends
would be a good thing to have back, but at least we have a fair enough alternative. 😊
@shin- First I was very disappointed to see the extends
feature missing in 3.0
, but YAML anchors (example: https://github.com/JanNash/docker-noop) would be a more than sufficient replacement.
The only thing is that, like in the above example, you need to put your anchors in some valid section of your docker-compose.yml
file.
Could we get a (top-level) templates
property or hidden keys like in GitLab to be more flexible in the way where to define the anchors?
@schmunk42 have a look at https://github.com/docker/cli/pull/452
The problem with relying docker-compose.override.yml is that it presupposes you only have one type of override you need to include, and one layer of overrides.
In my case, I want to have certain behaviors common to all local development, but might need them to be subtly different if the developer is running Windows, OSX, or Linux. To keep this manageable in a docker-compose v3 context, I have Linux users operating on the same behavior as the staging environment, which works but means they are slightly out of step with other developers.
I avoid using -f
for local development because I've found it's very prone to human error, and relying on it as a toggle for too many things causes trouble. Selecting one file seems reasonable, selecting multiple is something I carefully avoid imposing.
FYI, I think that once the hack with x-
mentioned above, and also daisy chaining docker-compose files using the COMPOSE_FILE
variable in the .env
project file, adding the docker-compose.override.yml should solve every use case I have encountered so far.
The yml anchors are also a nifty thing that I intend to use in the near future.
Not very happy with the x-
hack beauty but I can live with that.
Thank you guys for your input!
It seems like the removal of extends
is causing a lot of heartburn and either blocking move to v3 or resorting to hacks. I like the ability to define a "template" (or abstract) service that can carry some common things (e.g. update policies)
I am working on a simple golang filter utility that can pre-process a docker compose file with extends
and spit out a clean v3 file with the extends resolved:
resolve-compose
(or docker-compose up)
Will this work for at least some of your use cases / why gotchas?
@pnickolov That would be gorgeous for me.
I've been looking ansible-container (I use ansible personally, but not yet at work), which looks like it would do everything I need, but a script like yours would be more preferable (less churn)
So long as it can recursively process extends:
keys, I'd be happy!
Ok, looks like we found alternatives to extends
... 👍
What's disturbing is the fact that Moby's Project Management doesn't seem to consider maintaining compatibility as a key element. Forward compatibility is essential for broader adoption, especially for large applications deployed into production. How could we push for Docker Swarm / Docker EE when there is no guarantee that core features like extends
will remain? 👎
A good reputation is hard to win and easy to lose...
Personally, I'd prefer to rely on native YAML features to accomplish the task which is handled by extends
in v2
syntax, rather than a custom-script or a larger solution like ansible. I was having similar problems earlier and started writing my own converter before there were solution like using multiple .yml files etc.. (https://github.com/schmunk42/yii2-yaml-converter-command) - but it wasn't a viable solution.
To me it's also fine to deprecate features, if this is done along with a versioning policy; you can't carry old stuff forever, even if this means some work on our side.
@schmunk42 Deprecating features is fine, but only when:
Unfortunately, none of those requirements (in my book) does apply to the deprecation of extends
...
@laugimethods What's the reason you need to use v3
?
@schmunk42 Because of Swarm:
Version 3.x, the latest and recommended version, designed to be cross-compatible between Compose and the Docker Engine’s swarm mode. This is specified with a version: '3' or version: '3.1', etc., entry at the root of the YAML.
The docker stack deploy command supports any Compose file of version “3.0” or above
Btw, my comment is not only related to extends
, but to any (painful) deprecation that might occur in the future...
Yeah, we are facing the same issue because of swarm mode.
I asked myself in the first place, why the hell the docker CLI is now able to use --composer-file
input. But from our learnings with docker/swarm
it looks like a pretty complicated thing to run stacks on a (self-managing) swarm and that there are several good reasons why this have been moved to the engine.
Just to note some of my findings here ... transitioning from v2
to v3.4
is far from being easy.
Some of my problems:
volumes_from
, rather easy to circumvent, since we wanted to remove that anyway.env
files (like with docker-compose
) have no effect with Docker CLIdocker stack deploy -c docker-compose.yml -c docker-compose.override.yml doro
) seem not to work correctly, there's no error, but it looks to me like they are also not merged correctly - but there's also no command like docker-compose config
to check itdocker-compose
which supports v3.4
syntax; like Docker edge--scope swarm
CC: @handcode
Using the latest builds
I am now using this configuration pipeline to replace my use of _extend_ and _noop_
Keeps things a little bit DRYer
Hope this helps someone
base.yml (shared definitions, this is a valid yaml document, so mergable using _docker-compose config_)
version: '3.4'
networks:
net_back:
external: true
base-inject.yml (shared anchor definitions, unfortunately cant be added to base.yml as anchors can not be referenced across different yaml files, instead these are injected as text into foo.yml, not an ideal way to do this)
x-logging: &logging
driver: json-file
options:
max-size: "50m"
max-file: "2"
foo.yml (generic stack definition, references objects from base.yml, anchors from base-inject.yml and objects overridden in 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 (per environment stack definition)
version: '3.4'
services:
foo:
ports:
- "8080:80"
volumes:
volfoo:
name: '{{index .Service.Labels "com.docker.stack.namespace"}}_volfoo_{{.Task.Slot}}'
driver: local
Then the deployment command:
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
For those of you craving after extends
in compose 3+ files, I have just put my hands on a tool called baclin
. baclin
linearises such directives, recursively replacing all extends
directives by their content. This is alpha software, the code is part of my machinery as I am currently writing code to support Swarm mode and stacks deployment. Platform binaries of an early version of baclin
are available here. Please report any comment or issue here.
This is really confusing!
Reading the doc for the latest docker release (v17.09
) and also the v17.06
release doc this feature should be available.
$ head -n1 docker-compose.yml
version: '3'
But compose up
yields
ERROR: The Compose file './docker-compose.yml' is invalid because:
Unsupported config option for services.admin_application: 'extends'
when using the extends
keyword.
Also, I can't find anything about the removal of extends
in the compose
changelog.
Now which is it?!
Crucial info like this shouldn't be hard to find or hidden inside some obscure github issue.
$ docker --version
Docker version 17.09.0-ce, build afdb6d4
$ docker-compose --version
docker-compose version 1.16.1, build 6d1ac21
@jottr, See docs:
The extends keyword is supported in earlier Compose file formats up to Compose file version 2.1 (see extends in v1 and extends in v2), but is not supported in Compose version 3.x.
So if you want to use extends
you need to stick up to version: '2.1'
.
My bad. It should still be at the top of the doc with a red deprecation warning sign.
My bad. It should still be at the top of the doc with a red deprecation warning sign.
@jottr Just use Github to create a separate issue for that or even create a PR for that. Just created the issue hiere: https://github.com/docker/docker.github.io/issues/5340
In my case I have the docker-compose-override.yml
as follow:
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"
And I have several other docker-compose.yml
files that need to share the network and extra_hosts. How to do this using without extends feature?
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"
It would be great if docker-compose supported yaml anchor and references between different files. Maybe, applying anchor and references after merging files.
For example:
yaml
version: "3.4"
services:
common: &common
extra_hosts:
...
networks:
...
yaml
version: "3.4"
services:
mongo:
<<: *common
image: "mongo"
container_name: "mongo"
...
The result should be:
yaml
version: "3.4"
services:
mongo:
image: "mongo"
container_name: "mongo"
extra_hosts:
// EXTRA HOSTS HERE
networks:
...
@sandro-csimas this is possible with: https://docs.docker.com/compose/compose-file/#extension-fields
@shin- could this ticket be closed?
@rdxmb I don't think so. From what I can see, you cannot extend from another docker-compose file
Am I right in thinking that this is an issue for https://github.com/docker/compose/issues ?
Some debugging:
# 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
This is working with
docker stack deploy -c docker-compose.yml test
When using docker-compose:
# docker-compose up
ERROR: yaml.composer.ComposerError: found undefined alias 'common'
in "./docker-compose.yml", line 4, column 10
Changing the yml-file to:
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
also works with docker-compose.
So thought this should also be working with multiple files, which is not the case:
# 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
However, of course, merging this is possible with a simple use of 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
Running on xenial with the versions:
# docker --version
Docker version 17.11.0-ce, build 1caf76c
# docker-compose --version
docker-compose version 1.17.0, build ac53b73
@rdxmb, thanks!
So I should go merging compose files using "cat" command and executing the final file.
I also use the docker-compose config
to do this. An example for environment specific settings:
This is run by the CI pipeline: docker-compose -f docker-compose.yml -f docker-compose.override.prod.yml config > docker-compose.prod.yml
and then I use docker stack deploy -c .\docker-compose.prod.yml my-stack
Vote for this, the extends is very useful for v3.
Used it a lot with v2, very useful indeed!
+1
I would love to see extends
support in v3. It would help DRY up my docker-compose.yml
file a lot.
It has been almost a year since this issue has been brought and it is really obvious that a ton of people need this feature. Yet I haven't read a Docker dev respond to this request at all, nor an explanation of why it was not included in docker-compose v3 before release.
Sad state of software if we cannot even communicate or maintain features for our customers who put faith in a new technology.
One possible interpretation (and maybe also a summary of the current thread) of the situation is like this:
cat
and the advanced approach in this thread. The simple approach comment shows an issue of docker-compose loading multiple files towards the end (has anybody created an issue for that?). If that was fixed in docker-compose you wouldn't even need the file merging at all. So to me people desiring multi-file support should continue in docker/compose/issues as @rdxmb proposed.extends
was considered (see GitHub project events, nice transparency here from the Docker team, thanks!) and you might interpret the outcome as "there's loads of other stuff that's strategically more important for them" but you can still write a pull request for extends
I guess.To me that's a perfectly understandable viewpoint.
@aCandidMind Agreed.
IMHO, even though the approaches mentioned by @aCandidMind work, they add complexity to a the simpler-and-cleaner mechanism provided by extends
.
Maybe it's me, but moving a moderately complex extends configuration to extension fields becomes much harder to read and maintain.
After reading many comments and posts, it is still not clear to me why extends was dropped and what the advantages of this regression in capabilities are.
It is possible with a little bit of bash magic I put up a test repo so you can try it yourself.
Just structure your stack deploy
command like this:
docker stack deploy --compose-file=<(docker-compose -f docker/prod.yml -f docker/dev.yml config) <stackname>
@tylerbuchea - the only downside to that bash magic is that you might get a WARNING: Some services (<service-name(s)>) use the '<key>' key, which will be ignored. Compose does not support '<key>' configuration
. This can cause some confusion. But hey, it works 👍
@dnmgns you're right! Thanks for pointing that out. Like @joaocc said nothing is going to beat native support, but the solution I mentioned above is the best one I could find given that there are no dependencies other than bash.
@tylerbuchea One dirty way is to just redirect stderr to /dev/null :)
docker stack deploy --compose-file=<(docker-compose -f docker/prod.yml -f docker/dev.yml config 2> /dev/null) <stackname>
Ain't no shame in it 😄
I think the documentation should be more explicit about this confusion around extend
.
The description of extend
redirects the user to the how-to-upgrade docs, and the how-to-upgrade docs point back to the description of extend
for more information. This is not helpful enough: as a user I'd expect some help how to deal with this whole problem, what options I do have and what I should consider. I'm very sure there was a clear idea behind the decision of removing extend
from v3.
See:
https://docs.docker.com/compose/extends/#extending-services
https://docs.docker.com/compose/compose-file/compose-versioning/#upgrading
Regarding @tylerbuchea great one-liner bash based solution,
sadly it does not support some advanced Docker stack features:
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.
Not that since https://github.com/docker/cli/pull/569 go merged, starting from 18.03, docker stack deploy
will support merging multiple compose file into one. It does not fully replace the extends
key from composefile format v2 but hopefully it covers way more use case 👼
My own workaround was to use yq
(can be combined into a one-liner if using 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 they're just warnings the output will still include your deploy
and config
keys. You can verify this if you run docker-compose -f docker/prod.yml -f docker/dev.yml config
It is for compose files v3.4 and higher. It supports cross yaml references (partial). I finished with this zsh alias/perl script:
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
Pros: perl is common tool, all perl modules too, generation is fast.
Cons: I hate hacks but there is no other way for DRY. Final docker-compose is about 900 lines. Do you really want that I support it as a single file from the beginning? It is a shame to have binary docker wrapped with python docker-compose wrapped with perl hack.
How can you just take out a feature like extends? That seems like a core feature.
Using docker-compose config
piped to the standard input option of docker stack deploy -c -
has solved the problem for me:
docker-compose -f docker-compose.yml \
-f docker-compose.extended.yml \
config \
| docker stack deploy -c - my-stack
I haven't tried this, but I also just noticed this in the docker stack deploy
documentation:
If your configuration is split between multiple Compose files, e.g. a base configuration and environment-specific overrides, you can provide multiple
--compose-file
flags.
With this as the example:
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
Is the rationale for removing extends
documented somewhere? It doesn't seem to be explained in the official docs, e.g. here: https://docs.docker.com/compose/extends/#extending-services
If users could understand the rationale, then users could develop a better idea of how to respond to the removal. Thanks.
@shaun-blake I ended up using the multiple compose files. That seems to be the approach people use. Rather than inheritance it's more like a mix-in. When building or running I copy the correct environment yaml template to docker-compose.override.yml.
Multiple docker compose files (eg: base.yml
, local.yml
, prod.yml
) does not let service use YAML anchors from other files so factored service definitions could not be defined among multiple yml files.
Note, this issue is the 13th most commented: https://github.com/moby/moby/issues?q=is%3Aissue+is%3Aopen+sort%3Acomments-desc and 3rd most liked.
If users could understand the rationale, then users could develop a better idea of how to respond to the removal. Thanks.
+1 on documentation on rationale for removing extends
in the first place...
Still no _extends_ after almost 1 and a half year later. Cmon, devs, u don't remove sth without giving an alternative.
They did, they offer an alternative called composition. Please read my answer in the thread.
-Filippo
On 30 Jul 2018, at 09:41, Xiaohui Liu notifications@github.com wrote:
Still no extends after almost 1 and a half year later. Cmon, devs, u don't remove sth without giving an alternative.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/moby/moby/issues/31101#issuecomment-408790200, or mute the thread https://github.com/notifications/unsubscribe-auth/AAS_0AOynjpfVnVo4ZqciMbmjBmkcTQ3ks5uLsbNgaJpZM4MDcml.
@dedalozzo, "in the thread" == ?
Please see my comment here:
https://github.com/moby/moby/issues/31101#issuecomment-329527600 https://github.com/moby/moby/issues/31101#issuecomment-329527600
Basically you have to use a chain of .yml files to override or change the configuration of your containers.
Please read "Specifying multiple Compose files”
You can supply multiple -f configuration files. When you supply multiple files, Compose combines them into a single configuration. Compose builds the configuration in the order you supply the files. Subsequent files override and add to their predecessors.
https://docs.docker.com/compose/reference/overview/ https://docs.docker.com/compose/reference/overview/
This approach uses composition over inheritance to obtain, more or less, the same result.
On 30 Jul 2018, at 15:23, Serban Teodorescu notifications@github.com wrote:
@dedalozzo https://github.com/dedalozzo, "in the thread" == ?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/moby/moby/issues/31101#issuecomment-408880809, or mute the thread https://github.com/notifications/unsubscribe-auth/AAS_0FZO30NplqHRid_Id8VBOJW7nk5Iks5uLxbigaJpZM4MDcml.
Wouldn't we be able to get the same extendability back if we combine
yaml extension fields (compose 2.1+/3.4+)
with allowing those x-
fields to reference other files?
So we could allow a root include
listing to specify files to load.
they would be put in an x-include
and be instantly usable via standard YAML anchors & merging.
# /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
# /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 that's a YAML feature, built into the laguage spec itself, to avoid repeating parts in the same file. When using different files, that's basically impossible.
You should propose that feature to the YAML spec itself.
This discussion burns down to:
docker-compose -f file.yml
is so much better than docker-compose -f file.yml -f file_extension.yml
?Only when working on the command line, the inconvenience becomes notable. We have to acknowledge that for a second. Everything else is scriptable, anyway.
If that's the real argument, then docker-compose up service
has better semantics than docker-compose -f service.yml up
: define everything needed for local development (aka on the command line) in docker-compose.override.yml
.
Given semantics are very clean and well thought through. Adopting service.yml
_for the command line use_ probably means lowering UX. There is another argument to it: while it is clear at first sight, what a docker-compose.yml
is, a service.yml
can be anything, really anything.
Disclaimer: A provocative opinion. :wink: I didn't take into account every possible use case...
After this prolonged discussion not sure whether it will ever make it. IMHO, extends was cool and must have been atleast carefully deprecated and then discussed instead of simply dropping it away.
I think one thing we could do is improve the documentation story about v2 vs. v3. Many assume that v3 replaced v2, but that's not entirely true. Both receive new features that focus on their use cases. This GH issue was started so we could have the discussion about what future features needed to make their way from docker-compose into Swarm, and how to improve docs for using docker-compose, the compose file format, and Swarm stacks together. Extends still works great in the up-to-date v2.4. Hopefully, I can help offer information on what solutions we have today:
v2: For docker-compose cli only. Development workflow focused on a single machine and engine. Also good for CI build/test workflows. This version branch received new features as recent as December 2017 in v17.12
v3: Ideal for Swarm/Kube stacks, with multi-node concepts and maintains support for most docker-compose cli features.
If you're not using Swarm or Docker Enterprise Kubernetes stacks, there is no reason to use v3. Stick with v2.4, and you get all the docker-compose cli features including extends, depends_on, extension fields, and even depends_on with healthchecks (to avoid wait-for-it scripts).
v3 was created to try and merge the features of a single engine docker-compose cli world with a multi-node cluster world. Not all v2 features (like depends_on) make sense in a cluster. Other features (like extend) just haven't made it into v3, likely because before v3 existed, all the code was in docker-compose Python, and for v3.0 to support Swarm, they had to rewrite that in docker cli Go, and now they are writing it again in the engine daemon to eventually make a Swarm stacks API, which doesn't yet exist.
For those new to this issue, also note much of the work that's gone on to solve various configuration, templating, and team workflow concerns since 3.0 release:
The docs at https://docs.docker.com/compose/extends/#extending-services should emphasize in red the fact that the extends keyword is removed in v3, as it's more important than just a _note_.
I migrated and skimmed the docs for why it was no longer working, then followed several closed issues before ending up here, then went back to the original docs and noticed the wording.
The extends keyword is supported in earlier Compose file formats up to Compose file version 2.1 (see extends in v1 and extends in v2), but is not supported in Compose version 3.x.
Could be rephrased as:
The extends keyword has been removed in Compose version 3.x, but is still supported in earlier Compose file formats up to Compose file version 2.1 (see extends in v1 and extends in v2).
It's a small difference, but one that's easy to overlook when skimming docs.
@krisrp PR started ^^^
Thanks @BretFisher
Are there any plans to perhaps rename v2 to "version: docker-cli" and v3 to "version: swarm/kube"?
It'd make more sense to differentiate them like this, considering how v3 supersedes v2 in most other versioning schemes. At present both are maintained and diverging, so unless I'm mistaken it seems like they'll both be around for a while.
@krisrp On the contrary, the reason for incrementing a major version number is to signal the divergence in compatibility.
@cpuguy83 I wasn't implying otherwise. Apologies for not being more clear or explicit.
IIRC Gnome 2 & 3 also had this confusion years ago when independent forks of each were maintained.
I don't want to derail this thread to discuss the semantics of versioning (bad pun), so I'll leave it at that. @BretFisher 's post last week about improving documentation on v2 vs v3 would have helped myself and probably others.
@shin- @cpuguy83 Looking at this issue over a year later, what _is_ the reasoning for not adding it back in version 3?
I couldn't find much about it, other than "we could do it differently" (but no actual better solution offered)
Is there a technical limitation? Or just a lack of pull request?
After all, my compose 2.1 files are still running fine.
Not only this, but the changelog says "this has been removed, see 'how to upgrade' for details". I look at "how to upgrade" for, you know, details on how to upgrade, and what that says is "see 'extending services' for details". I go to "extending services" figuring I'll finally see a way to extend my files, only to see "this has been removed, see the changelog for details".
At this point, this seems like a cruel joke the documentation writer is playing.
Ultimately, the "stack" format is not controlled here and is part of the Docker CLI.
I personally don't know the reason it was excluded from v3... I also don't think I've seen anyone actually try to add it in.
It might be best to bring this up in docker/cli... maybe even just a PR with a high level doc change that acts as if the feature is there so it can be discussed and the implementation can be added once the design is approved.
Basically, if someone wants it, make a PR. I suggest the doc change just to make sure you don't waste a ton of time in case it is rejected... since again I am not sure why it was omitted from v3.
Same as above. Waiting for this to be solved before using docker-compose again.
+1 please get this fixed, we have extend based compose files and can't use compose for swarm because of it.
+1 for extends feature
Any news on this?
Still waiting for it
Same here. Still waiting.
Any update?
Was there ever a reason given as to why it was taken out?
On Mon, 5 Aug 2019, 11:10 Jaykishan, notifications@github.com wrote:
Any update?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/moby/moby/issues/31101?email_source=notifications&email_token=ABOE6GA4CXY6ESMZMTDSFGDQC74CZA5CNFSM4DANZGS2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3RLFLQ#issuecomment-518173358,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABOE6GCEFFJ3SOLDWRWX2IDQC74CZANCNFSM4DANZGSQ
.
Any update?
so.. it's almost 3 years...
but I still have hope it will land :D
There needs to be some sort of alternative to extends if it's not coming back. Why not allow abstract services? The file format would be flat and all service declarations would be in one file. You could use abstract services in conjunction with yaml's ability to add aliases for a node (via an &
) reuse those aliases via the <<:
operator.
Why 3 years!! it seem you are working and focusing in stuff no one cares about
any update on this?
This is pathetic. Terraform uses composition - so it is doable, why compose is not capable to follow on this good design practice ?!
Terraform Modules Composition
Terraform Best Practices
"pathetic", nice.
@Cristian-Malinescu Go ahead, implement it please.
This is free and open source software.
Instead of complaining like every other one in this chat.
That just doesn't add any value here, really.
As said several times nobody did want to implement this so far,
so it's just a problem someone else should fix k,thanks.
@luckydonald Thanks to push away @Cristian-Malinescu with an easy/passive-agressive answer, it's, like always not helping. @Cristian-Malinescu It is do-able as it already been done before but removed, there must (I hope) be a reason.Is there anyone on this thread actually in the docker-compose team so he/she can shed light on the matter?
Skimmed the thread and leveraging supported YAML functionality has been mentioned.
Thought this example might help.
@nomasprime thank you for that find! I was deciding between v2 and v3 for my project, and this resolved the big dilemma in this thread. Surprised that these alternative solutions are not mentioned in the official docs for the extending services feature.
Nice, sounds like a good opportunity to use the Request docs changes
link on the right nav bar of the docs page.
@nomasprime Yep, that idea was around in this thread before.
If that could combined with a file loading mechanism for other yml files, that's all what's needed really to have all the old depends
functionality.
See above, e.g. https://github.com/moby/moby/issues/31101#issuecomment-413323610
It wouldn't be very _readable_, but it would be at least _possible_.
@nomasprime thank you for that find! I was deciding between v2 and v3 for my project, and this resolved the big dilemma in this thread.
@arseniybanayev The article on medium says about v3 only, but newer versions of v2 also support anchors and extension fields. In my case I choose v2 (2.4 more specifically) because I use docker-compose
and not swarm
(and v3 doesn't support some features of v2 like limiting container memory)
and v3 doesn't support some features of v2 like limiting container memory
v3 does support limiting memory, but the field is under deploy -> resources -> limits
https://docs.docker.com/compose/compose-file/#resources
@thaJeztah I mean, for docker-compose
(because I'm not using swarm in the project I was referring to in my previous comment). IIRC deploy is only for swarm, isn't it?
Would it make sense to make a separate config for swarm and local? Seems like these two are conflicting with each other. Understandably Docker would like swarm usage to be increased, but a lot of people only use compose for local development.
I for one have never used swarm and run containers in production with either ECS, k8s, or GAE.
Most options should be translatable / usable for both swarm/kubernetes services and for containers deployed through compose. I'd have to check why memory
limits would not be applicable for docker-compose
still missing the extends feature, but for my main use case I switched to multiple docker compose files via the COMPOSE_FILE
env. I use it mostly to use the same base docker-compose.yml for dev and prod with different passwords or configuration.
example:
export COMPOSE_FILE=
docker-compose.yml` # defaultexport COMPOSE_FILE=
docker-compose.yml:docker-compose.prod.yml` # uses both yaml filesIn docker-compose.prod.yml
I just overwrite the env vars with the prod passwords.
This setup is simple and I don't need to always add multiple "-f" to the docker-compose
command. I just need to set the COMPOSE_FILE
env var different on the dev computer and the server and git ignore the docker-compose.prod.yml file.
Still waiting :)
I've been using this as a way to extend:
docker-compose \
-f ./docker/base.yml \
-f ./docker/extended.yml \
up
But extend in the file would be nicer, no need for an extra bash script.
I've also been using this to extend dynamically from the bash script:
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 those are plain old overrides!
I believe this is a potential valid usecase for extends
https://github.com/NerdsvilleCEO/devtools/blob/master/doctl/docker-compose.yml#L10
I have a docker-compose
wrapper which I use for an env of services https://github.com/nowakowskir/docker-compose-wrapper
EDIT: Another possible usecase is someone has a LAMP/LEMP stack and they want to extend those services for use with a specific service such as wordpress
Still waiting since 2017 while exploring docker compose alternatives.
@nomasprime Yep, that idea was around in this thread before.
If that could combined with a file loading mechanism for other yml files, that's all what's needed really to have all the old
depends
functionality.See above, e.g. #31101 (comment)
It wouldn't be very _readable_, but it would be at least _possible_.
@luckydonald thanks for pointing out. Odd there's no built-in YAML include functionality, would certainly solve a lot of issues.
Looks like it would be pretty easy to implement a third party solution though so not sure why this hasn't been brought over to v3 🤷♂
A little reminder that a lot of people would like this feature :)
What is the reason for not porting it to v3 btw?
I forget but is there an actual reason it was taken away?
On Wed, 6 May 2020, 23:14 Julien Marechal, notifications@github.com wrote:
A little reminder that a lot of people would like this feature :)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/moby/moby/issues/31101#issuecomment-624919070, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/ABOE6GGDIVGATP734YJA4UTRQHOLJANCNFSM4DANZGSQ
.
The way yaml anchors handle this use case is a bit inconvenient compared toextend
. It's power, in my opinion, came largely from recursive merging of elements. Anchors get you maybe 75% of the way there--they don't merge yaml recursively; all your merging happens at the top level. Referencing an anchored service template and then redefining the environment
block will result in overwriting the anchored service's environment block instead of merging. You'll need to anchor and reference every dictionary down a recursive tree of dictionaries in order to match the behavior of the extend
keyword.
An example:
# 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
It might not look so annoying in this example, but it gets annoying and less readable if you're templating multiple (10+) services off one extension block.
In my mind an ideal scenario is a combination of the yaml anchor approach and the extend
approach--allow extend
ing only from a top level x-
prefixed extension field block, with the smarter merging characteristics.
In my organization we found yaml anchors a bit syntactically sloppy so we basically re-implemented the extend
feature in an external python script. That works for us, but it's a lame way to have to deal with something. Similarly we've had to create our own external tooling to deal with the removal of depends_on
for v3/Swarm stacks.
I have done a lot of gitlab CI YAML lately. It has exactly these features, which are sooo nice to achieve readable and manageable templates and final configurations:
x-
, in gitlab CI it's an initial .
instead.This is the exact set of feature that makes these files bearable.
I arrived at this issue from the docker docs, in my case I wanted to template my docker-compose
setup, and as a 'workaround' I followed the advice above and did decide to look for an existing templating program. I won;t get those our hours back so am detailing a bit of what I found here, irrespective of any discussion on this actual feature request, however, it may be that those involved would feel the use of a YAML-based template system to generate a compose file rather than integrating this feature into docker-compose
itself might be more appropriate in terms of encapsulation and picking the right tool for the job.
For some context, I am using a basic reverse proxy with Let's Encrypt and several application containers (Nextcloud for now, one for me, and some separated ones for friends) - in this case, I wanted to make a template of the Nextcloud containers so that I avoid mistakes and duplication with keystrokes for very similar setups. The following packages were what I tried:
ytt seems very comprehensive and is the only option to use YAML natively. It seemed powerful and the right tool for the job, and it uses Starlark, a superset of Python, directly inside the YAML file to performing processing. However after not long, the template became very messy, and the littering of fragments of code and fragments of YAML, plus mixing of Python data types like dictionaries and arrays and YAML fragments (that seem to be somewhat processed like text, a bit like using an HTML template engine that outputs tags like strings) eventually resulted in too many errors and too messy a file. Dhall also seems very comprehensive and uses a unique native language that can be output to a variety of formats; It seems more like a metaprogramming language than a template system, however given that the syntax is functional and it is pretty strictly typed, it quickly became more complex than was worth it for a simple template for unstructured YAML. As what seems a little like a blend of JSON and Haskell, it required too much thought to work what I needed done into the language.
Interestingly, sometihng that was difficult with both Dhall and ytt was using parameterised field names, both would have worked well enough otherwise, but I need to have the name of my instance appear in the services names and volume names, and in both of these achieving this was somewhat ugly; using arguments for the values in a hash is easy, but using those arguments in the names of the keys was messy or I couldn't find how to do it neatly, plus Dhall enforces type safety and this simply goes against that concept. With Jsonnet it was a simple as putting the expression in square brackets.
CUE and Jsonnet are both JSON-oriented, however running these through a converter is not hard at all, and it seems again, like Dhall, CUE has a lot of powerful features and was born out of shortcomings in Jsonnet, however partway into the documentation, it became apparent it was already overkill; perhaps with much more time to learn it properly it would be the superior option, but it seems CUE is more oriented to validation and schemata than a simple template job and so I quickly moved onto Jsonnet and finished the job quite quickly.
Finally, it was only after I had completed all this I realised the whole time I had been comparing these tools to the simplicity of Liquid tags or similar HTML templates, that I could actually probably simply have used Liquid in the first place. I have only used it in the context of a Jekyll site, so it just never ocurred ot me ot obtain a standalone package, however with basic looping and lists, and the ability ot evalate expressions straight into in-place text, this probably would have been a much better too for the job; Jsonify probably superior for JSON, but Liquid could operate in pure YAML and so the file becomes more readable again.
+1 docker-compose was one inspiration behind the bespoke solution I've implemented at work since this ticket was created to support migrating a large number of test envs to k8s. I was very careful to avoid bells and whistles but pretty quickly justified an analogous feature. The philosophical discussion (composition versus inheritance etc.) looks to me like a distraction from common sense (with the benefit hindsight - still unresolved nearly 3 years later). Evidently it is required by people who might continue to use docker-compose.
+1 :+1:
I used this feature heavily before for dev
/test
/ci
environments, where I could extend from a compose file in subdirectory paths of ./config/{dev,test,ci}/compose.yaml
. I would have a .env
that had COMPOSE_ENV=dev
, but developers could override, and obviously I would override in ci
.
I'm shocked by deprecating the feature and not replacing it with something that can do something similar. Maybe just allow us to use jinja2 and do what we want. I hope Docker-Compose would be less anti-DRY. :'(
Seems that extends
is supported by docker-compose
since v1.27 (https://github.com/docker/compose/pull/7588).
One use case where I use the feature heavily, is to version docker images to code. My docker dev and prod compose files both extend from docker-images.yml where only the basic service is listed and a tagged version of the image of the service.
Didn't found an easy workaround for this in v3.
Most helpful comment
Not only this, but the changelog says "this has been removed, see 'how to upgrade' for details". I look at "how to upgrade" for, you know, details on how to upgrade, and what that says is "see 'extending services' for details". I go to "extending services" figuring I'll finally see a way to extend my files, only to see "this has been removed, see the changelog for details".
At this point, this seems like a cruel joke the documentation writer is playing.