-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Overriding the set of values when extending the "ports" option. #2260
Comments
I would do something like this: docker-compose.yml (no ports) restserver:
image: node
webserver:
image: django For dev you can setup some host ports docker-compose.override.yml
and for prod you can set them to a different port: docker-compose.prod.yml
In prod you would run |
It seems like a good, clean approach. Only cons would be the verbose command on production but that one is automatic. Thanks @dnephin |
Another downside is that it no longer "just works". The user has to either create an override file or specify ports manually. It would be nice if the override file could actually override array values like it does for scalar values. Instead, the override file appends array values and only actually overrides scalar values. |
I agree with @gregmartyn . A feature that would allow to override ports array instead of merging them would be awesome. In my case we use it to override a port when one of the developers is not able to work on the default one. Maybe docker-compose could just override the ports that are already forwarded: If port 80 is specified in both files, it uses just the one from docker-compose.override.yml? |
@gregmartyn @mkurzeja Docker is already having that feature. I tried that to override with simple docker-compose, it is working. For example, docker-compose.yml with content,
And docker-compose.override.yml with content,
This is the
It is taking override's image and port from the compose file. |
@udhayakumaran see above. "the override file appends array values and only actually overrides scalar values." The image in your example is a scalar value and did get overridden. The port you specified is part of an array and was not overridden. You didn't specify any ports in your override file, so they were not overridden. Had you specified ports in the override file, they would have been combined with the port specified in the main config file. |
@gregmartyn Okay, I understand now. Thanks for correcting me.. |
@gregmartyn If you are using the For dev environments you can set Together with what @dnephin suggested it works fine. |
@datacarl Do you have a link to documentation on the |
@kevin-cantwell https://docs.docker.com/compose/env-file/ (should be |
@datacarl Ah, |
- Relates to docker#2260
- Relates to docker#2260
- Relates to docker#2260 Signed-off-by: CarstenHoyer <[email protected]>
I have added a preliminary pull request, that introduces a way to add an overwrite strategy other than the default append/union. The overwrite config currently only supports "ports" but it would be a smallish thing to support the other array options too. Your compose file would then look like either:
or
And the result could be that if docker-compose.yml has ports: 80, 443, and your override file has 8080 and 8443 fx, then only the 8080 and 8443 ports would be in the final config. |
- Relates to docker#2260
- Relates to docker#2260
- Relates to docker#2260
- Relates to docker#2260
- Relates to docker#2260
Running the test targets (single-node-test, cluster-unicast-test) can sometimes lead to CI failures: https://devops-ci.elastic.co/view/Docker/job/elastic+elasticsearch-docker+5.0/21/console. This can happen when both targets are run simultaneously due to a conflict on the locally exposed port :9200. Remove local port references for ES in docker-compose.yml. This change doesn't affect the tests as the test container accesses ES through the docker network driver. Retain backwards compatibility for run-es(single|cluster) targets, by overriding the localhost port definitions with docker-compose.hostports.yml. This strategy is described in: docker/compose#2260 (comment)
Running the test targets (single-node-test, cluster-unicast-test) can sometimes lead to CI failures: https://devops-ci.elastic.co/view/Docker/job/elastic+elasticsearch-docker+5.0/21/console. This can happen when both targets are run simultaneously due to a conflict on the locally exposed port :9200. Remove local port references for ES in docker-compose.yml. This change doesn't affect the tests as the test container accesses ES through the docker network driver. Retain backwards compatibility for run-es(single|cluster) targets, by overriding the localhost port definitions with docker-compose.hostports.yml. This strategy is described in: docker/compose#2260 (comment)
Running the test targets (single-node-test, cluster-unicast-test) can sometimes lead to CI failures: https://devops-ci.elastic.co/view/Docker/job/elastic+elasticsearch-docker+5.0/21/console. This can happen when both targets are run simultaneously due to a conflict on the locally exposed port :9200. Remove local port references for ES in docker-compose.yml. This change doesn't affect the tests as the test container accesses ES through the docker network driver. Retain backwards compatibility for run-es(single|cluster) targets, by overriding the localhost port definitions with docker-compose.hostports.yml. This strategy is described in: docker/compose#2260 (comment)
@CarstenHoyer did your |
@dimaqq - I am afraid not. I have not kept the PR up to date with the upstream, and it also doesnt contain any automated tests. Since I never got any official feedback, I figured it was not in scope. |
Solution available see http:gitHub.com/keithy/sprankle-podOn 3 May 2019 11:27 am, port22 <[email protected]> wrote:This problem is even bigger, when you have to use multiple files. YAML merging/anchors are not sufficient. I need services for developers, and the same service with different definitions for developers of other departments, quality assurance, testing ... I need to override volumes.
There should be a possibility to merge definitions. Or can you put an example how to use an anchor of another docker-compose.yml file? Even if that would be possible, it would make the additional file senseless and specific persons would have to modify the docker-compose.yml or an .override. file themselves, which has to be avoided. I want to serve a main yml and different override yamls for different persons
—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or mute the thread.
|
Does anybody else see why I am suggesting a dictionary rather than an array? |
I do but the compose project looks semi abandoned. I wouldn't recommend it using in production. |
@mike-code thats nonsense this project is quite active. |
I don't think the dictionary suggestion is a good one, docker-compose shouldn't have some new half baked scheme for merging files when YAML already has a standard that does all that is needed (other than @keithy 's use case, which sounds so complex it's out of scope). |
Portmapping is fundamentally a dictionary, not an array, and merging comes for free. |
@vectorjohn is there any official yaml lib that can do the merging? |
My use case and solution is very simple actually: docker-compose allows you to supply .env as an environment file. The environment variable COMPOSE_FILE provides a list of compose_files to be assembled. In those individual files I place environment variables where there are ports mentioned, so that the .env file can supply those values also. The missing piece of the puzzle, as with so much of the docker stuff, is to make the .env file readable. I do this by creating the .env file from a readable version using an all-to-simple pre-processor docker-compose-use <my.env> |
Oddly enough, docker-compose already supports this it looks like: |
This is a proposed fix for docker#2260 which has remained an issue for many users even though it was closed almost immediately after being opened because a partial work-around exists. My intent for this change is to allow the author of a docker-compose.yml file to specify a default port mapping that can have the external/host-side mappings be overridden. E.g., the author of a particular file may specify that the container/guest port `tcp/8000` be mapped to the sam external/host port: `tcp/8000`. This works well for most users except some users may already have port 8000 in use on their workstations. In those cases, the user should be able to specify something like `ports: ['8001:8000/tcp']` in docker-compose.override.yml to replace the predefined default on their system and avoid a 'port is already allocated' binding error. From what I can tell, the existing merge_field only allows the port's `mode` attribute to be overridden. This change allows the `published` and `external_ip` attributes to be overridden. Since the container/guest's `protocol` and `target` are the two attributes that are given/fixed/predefined/immutable based on the image being loaded, they seem like a more natural merge key. After this change, if overriders want only the `mode` attribute to change, they can simply reiterate/restate the `published` port and `external_ip` defined in the base file. This change is technically backwards-breaking. Although I don't expect it will negatively impact the vast majority of users, a more comprehensive change could be to add another property to the `ports` specification/schema in compose files called e.g., `merge_strategy`. Then ServicePort.merge_field could be redefined as follows: ``` if self.merge_strategy == 'internal_only': return (self.protocol, self.target) elif self.merge_strategy == 'include_published_and_external_ip': return (self.target, self.published, self.external_ip, self.protocol) else: return (self.target, self.published, self.external_ip, self.protocol) ``` Assuming that's the route we take, I'd add a deprecation warning to the release notes saying that the `include_published_and_external_ip` will stop being the default and that future versions will default to `merge_strategy == 'internal_only'`.
This is a proposed fix for docker#2260 which has remained an issue for many users even though it was closed almost immediately after being opened because a partial work-around exists. My intent for this change is to allow the author of a docker-compose.yml file to specify a default port mapping that can have the external/host-side mappings be overridden. E.g., the author of a particular file may specify that the container/guest port `tcp/8000` be mapped to the sam external/host port: `tcp/8000`. This works well for most users except some users may already have port 8000 in use on their workstations. In those cases, the user should be able to specify something like `ports: ['8001:8000/tcp']` in docker-compose.override.yml to replace the predefined default on their system and avoid a 'port is already allocated' binding error. From what I can tell, the existing merge_field only allows the port's `mode` attribute to be overridden. This change allows the `published` and `external_ip` attributes to be overridden. Since the container/guest's `protocol` and `target` are the two attributes that are given/fixed/predefined/immutable based on the image being loaded, they seem like a more natural merge key. After this change, if overriders want only the `mode` attribute to change, they can simply reiterate/restate the `published` port and `external_ip` defined in the base file. This change is technically backwards-breaking. Although I don't expect it will negatively impact the vast majority of users, a more comprehensive change could be to add another property to the `ports` specification/schema in compose files called e.g., `merge_strategy`. Then ServicePort.merge_field could be redefined as follows: ``` if self.merge_strategy == 'internal_only': return (self.protocol, self.target) elif self.merge_strategy == 'include_published_and_external_ip': return (self.target, self.published, self.external_ip, self.protocol) else: return (self.target, self.published, self.external_ip, self.protocol) ``` Assuming that's the route we take, I'd add a deprecation warning to the release notes saying that the `include_published_and_external_ip` will stop being the default and that future versions will default to `merge_strategy == 'internal_only'`. Signed-off-by: Brett Stime <[email protected]>
How does the override feature work for version: '3.6' in yaml head? Trying to override some settings in DDEV-Project (https://github.com/drud/ddev) also using docker-compose (version 1.24.1 which seems to be latest release already). Adding
|
@typoworx-de That was a proposed solution with a corresponding pull request that did not get merged. It is not available in version 3.6, or any other version for that matter. |
One reason this is very important (didn't see it mentioned yet) is that we don't always have access to change the base If I was able to create env files and remove ports from the base config, then sure, I'd accept that there's a workaround. But you aren't always in control of the base config file, and modifying it directly generally isn't the best idea. |
I'm also unclear how you could use yaml array merge to remove an entry from the list, whereas this is trivial if it is a dict |
What about adding a
|
@ebuildy - looks quite promising to me, but note that |
This should be reopened as the existing functionality is inconsistent with scalar values being overwritten by default. Or people should be able to make a choice - it makes no sense for them to be appended by default. |
It makes no sense, but changing it would break a lot of configs. I've proposed another non-breaking solution. #8276 |
I'd really like to have the override functionally suggested by CarstenHoyer on 13 Sep 2016. I have a situation where by default I want the application exposed on a port for easy testing. But also for testing, and in prod, staging etc, I want to deploy the app behind nginx, and therefore not expose the ports. So the default docker-compose.yml file would have the ports specified, then the docker-compose-withnginx.yml which just defines the nginx service, should override the ports. |
@adrianhelvik 's proposal #8276 is clean and does not require modifying the config / original docker-compose file. |
Why don't people copy what rubocop do. They have this exact same problem. For those who don't know rubocop is a ruby gem that provides stylistic configuration through yml files. Often people may have 2/3/4 on their repo at any time. There is a top level config option that specifies how to combine (In rubocop's example you often want to merge them, but you can have both behaviours). https://docs.rubocop.org/rubocop/configuration.html#merging-arrays-using-inherit_mode |
Perhaps this is an old discussion but I needed to do this quickly today, my solution was pretty simple: In docker-compose.yml define the
Default ports used are 8000:8000 for the app and 5678:5678 for debug attachment. Now I needed to start another web container to run a command within that container, so simply prepended The full command as follows:
Notice the use of brackets around the whole command. This is so the exports do not remain in the current running shell session when the command finishes. This works on my Linux machine, should be the same on Mac, not 100% sure on Windows, but should have similar options to pass environment variables to a command, maybe: this or this. Reference: Use an Environment File Hope this helps someone. |
The problem is with vendor's source, nowdays ot os essy to distribute your systems using docker and not all vendors makes variables or overridable ports, so for example if I have
in vendor's compose file, I can't change it anyway without changing the source, but it means that on update by git pull I will have to deal with this and moving things in and out or had to remeber that in the project i have to use some startup script and need to watch my composer up2date or so on. would be nice to have a way to reset lists in overrides |
The default behavior when extending a service or overriding a whole docker-compose.yml file is to concatenate the sets of values on the multi-value options: ports, expose, external_links, dns and dns_search.
The problem appears when for example you have two production hosts both serving on the port 80 and a single machine for development, there is no way of extending or overriding the services for a development environment that avoids the port collision on the host.
An example: lets assume there are two servers one is a REST API and the other is a webpage that uses the API, both listen on port 80 on the production host
On a development environment where you want to test this setup you would define:
Of course the "ports" option is concatenated with the production and there is no way of running both containers on the same host because both try to bind to port 80.
Is there any workaround or yml specific syntax for this use case?
The text was updated successfully, but these errors were encountered: