My docker compose configs look like this:
docker-compose.yml
version: '3.5'
services:
nginx:
ports:
- 8080:8080
docker-compose.prod.yml
version: '3.5'
services:
nginx:
ports:
- 80:80
Now, when I run command: docker-compose -f docker-compose.yml -f docker-compose.prod.yml up the nginx exposes on host machine two ports: 8000 and 80, because it merges ports properties:
version: '3.5'
services:
nginx:
ports:
- 8080:8080
- 80:80
Is there a way to override it? I want to expose only port 80.
This behaviour is documented at https://docs.docker.com/compose/extends/#adding-and-overriding-configuration
For the multi-value options ports, expose, external_links, dns, dns_search, and tmpfs, Compose concatenates both sets of values
Since the ports will be the concatenation of the ports in all your compose files, I would suggest creating a new docker-compose.dev.yml file which contains your development port mappings, removing them from the base docker-compose.yml file.
As Nikson says, you can name this docker-compose.override.yml to apply your development configuration automatically without chaining the docker-compose files. docker-compose.override.yml will not be applied if you manually specify another override file (e.g. docker-compose -f docker-compose.yml -f docker-compose.prod.yml)
it isn't possible a the moment but I found quite good way to fix this issue using the command yq.
You need to remove the ports from the original file.
Example:
Be careful this command will remove the nginx ports from your current docker-compose.yml (because of the -i option)
yq e -i 'del(.services.nginx.ports)' docker-compose.yml
You can execute this command on your deployment script or manually before your docker-compose up -d
There's also an open issue on docker-compose, that you may want to check once in a while.
Just keep the docker-compose.yml super simple and add the ports in another file docker-compose.develop.yml, then run it like docker-compose -f docker-compose.yml -f docker-compose.develop.yml up.
This way you can separate it from your docker-compose.override.yml file.
So you will have three files:
|- docker-compose.yml # no ports specified
|- docker-compose.override.yml # ports 8080:8080
|- docker-compose.develop.yml #ports 80:80
Refer to this post for longer explanation: https://mindbyte.nl/2018/04/04/overwrite-ports-in-docker-compose.html
I've faced the same problem. The proposed solution with docker-compose.override.yml sounds pretty well and is also an official one.
Although for some of my own projects I've applied the erb template engine to make docker-compose.yml.erb file compile for multiple environments. In short I use:
COMPOSE_TEMPLATE_ENV=production erb docker-compose.yml.erb > docker-compose.yml
COMPOSE_TEMPLATE_ENV=production erb docker-compose.yml.erb > docker-compose-production.yml
And then I can use the ENV['COMPOSE_TEMPLATE_ENV'] in my template and also the syntax of ERB, so only one file to configure and no worries about piplening them properly. Here's the short post article I've written about it
Use .override.yml file for overriding properties and a clear separation of properties need to be overridden
docker-compose.override.yml
Example:
version: '3.5'
services:
nginx:
ports:
- 80:80
Default:
docker-compose up
will use your docker-compose.yml and docker-compose.override.yml files
Reference: docker-compose multiple compose
Related
docker-compose.yml:
version: '3.7'
services:
db:
image: mysql:8.0
docker-compose.test.yml:
version: '3.7'
services:
db:
ports:
- 3306:3306
docker-compose config does not show the port. Why?
I'm trying to display the effective compose file, means: the merge result that is also used by docker-compose up.
docker-compose version 1.25.0
According to the documentation, docker-compose will only automatically find files named docker-compose.yml and docker-compose.override.yml:
By default, Compose reads two files, a docker-compose.yml and an optional docker-compose.override.yml file. By convention, the docker-compose.yml contains your base configuration. The override file, as its name implies, can contain configuration overrides for existing services or entirely new services.
If you want to use additional compose files, you need to specify them explicitly using -f <filename>:
docker-compose up -f docker-compose.yml -f docker-compose.test.yml
By default, docker-compose finds the docker-compose.yml file. The problem you are facing is happening because the port is configured in the other file and DockerCompose doesn't know anything about it. If you want to check the configuration of the other file, you need to pass it as a parameter:
docker-compose -f ./path/to/docker-compose.test.yml config
Or you can put the port configuration on the first file like this:
version: '3.7'
services:
db:
image: mysql:8.0
ports:
- 3306:3306
And it should work just fine.
for some reason, I need to create the container with the same image, But when I started the second one, It just restarted the fist one's container
the first yml file:
version: "3.1"
services:
php:
image:php:php73-fpm
restart: always
ports:
- "9000:9000"
- "9501:9501"
volumes:
- $PWD/../:/var/www/html/
networks:
- app_net
container_name: php
networks:
app_net:
driver: bridge
the second yml file:
version: "3.1"
services:
php:
image:php:php73-fpm
restart: always
ports:
- "19000:19000"
- "19501:19501"
volumes:
- $PWD/../:/var/www/html/
networks:
- app_net2
container_name: php73
networks:
app_net2:
driver: bridge
when I run docker-compose up -d to start the first one:
$ cd ~/Document/php/work/docker/
$ docker-compose up -d
Creating network "docker_app_net" with driver "bridge"
Creating php ... done
then I switch the directory to the second yml file
$ cd ../../private/docker/
$ docker-compose up -d
Recreating php ... done
Compose has a notion of a project name. By default the project name is the basename of the directory containing the docker-compose.yml file. In your example both directories are named docker (even if they're in different parent directories) so Compose looks for a project named docker and a container named php, and finds a match.
There are four ways to override this:
Rename one of the directories.
Set the COMPOSE_PROJECT_NAME environment variable.
Create a .env file in the current directory, and set COMPOSE_PROJECT_NAME there.
Use the docker-compose -p option (on every docker-compose command).
Within your docker-compose.yml file, the second part of ports: needs to match what the container is listening on; this is allowed to be different from the first part. So use the same 9500/9501 in both files.
Another consequence of the Compose project naming is that the standard names of containers, volumes, and networks that Compose creates will be prefixed with the project name. If the project name (current directory name) is docker2, and you reduce the Compose file to
version: "3.1"
services:
php:
build: .
restart: always
ports:
- "19000:9000"
- "19501:9501"
# no manual container_name: or networks:
The container will be named docker2_php_1, and it will be attached to a network named docker2_default; these will be different from the container/network created in the docker1 project/directory.
You can't have two containers with the same name. Since both names are just php, Docker thought they were settings that were supposed to be merged for the same container. Rename one of them.
I have docker-compose.yml file with build context property specified like this:
version: '3'
services:
my-service:
container_name: my-service
image: my-service
build:
context: foo
ports:
- 8088:8088
# other services
When I run docker-compose up locally, build context does exist and everything works fine. However, my CI server is configured to use the same docker-compose.yml file but there is no build context (images are copied as .tar archive via SSH and then loaded via docker load).
Now I've got an error:
ERROR: build path /foo either does not exist, is not accessible, or is
not a valid URL.
So I've tried to find a way to suppress looking for this build context when running docker-compose up (I don't want to build images cause they are already up-to-date), but docker-compose up --no-build does not work. Any ideas?
I posted your issue as a feature request on the docker-compose repository. Let's see how it progresses:
https://github.com/docker/compose/issues/7674
Meanwhile, you will have to workaround this by modifying your CI script that does the docker-compose up --no-build so it does the mkdir -p ... that you need.
docker-compose.override.yml is good solution in this case. You may override only build block and this is not hard to mantain as two independent files.
docker-compose.override.yml:
version: '3'
services:
my-service:
build:
context: foo
docker-compose.yml
version: '3'
services:
my-service:
container_name: my-service
image: my-service
ports:
- 8088:8088
See https://docs.docker.com/compose/extends/
I had the same problem, and my solution, until "docker-compose config" provides a way to skip the directory-exists check, is to automatically create those directories that "docker-compose config" expects.
Here is a one-liner that does this:
egrep ' (context:|build)' < docker-compose.yml | sed -E 's/\s+\S+:\s*//' | xargs mkdir -p .
It's ugly, but I couldn't figure out another way. (The .extends. way mentioned by dngnezdi is not a solution, as I needed an automatic method.)
I have a few docker-compose files to test different environments, for example testing vs development vs production.
My main issue is using the postgres image, creating different databases for each environment. Here is an example of two different environments' docker-compose.yml files:
docker-compose.first.yml
version: '3'
services:
db:
image: "postgres"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=first
- POSTGRES_DB=first
ports:
- 5432:5432
docker-compose.second.yml
version: '3'
services:
db:
image: "postgres"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=second
- POSTGRES_DB=second
ports:
- 5432:5432
If I do docker-compose -f docker-compose.first.yml up, I want it to build with the previous volumes of the first docker-compose file.
If I do docker-compose -f docker-compose.second.yml up, I want it to use the volumes of the second docker-compose file.
Right now, the behavior is that each of these files will use the same volumes, so unless I do docker-compose -f docker-compose.first.yml -v down before using the second one, there won't be any change, and I'll lose the volumes of the first one! How can I keep these separate?
Note: These files are in the same directory, does that make a difference?
The answer here after doing research about same-directory docker-compose files is that the names determine if a container will be freshly created or recreated, determining the volumes it uses.
Docker-compose by default uses the directory name as the "compose project name" so the name could be mytestproject_db_1 because it goes project-name_container-name_numerator. Since the compose files are in the same directory, they have the same name since none of the factors change.
To fix this, you manually change the "compose project name" using the -p option, so I could do docker-compose up -p test-myapp or docker-compose up -p prod-myapp to make sure the compose files won't be linked.
More info: https://github.com/docker/compose/issues/2120
How to be with orphan images when you have 2 independent projects and you want them to work at the same time or at least to build running docker-compose up -d without --remove-orphans flag when images are already built for another project.
docker compose file1:
version: '2'
services:
applications:
image: tianon/true
volumes:
- ../../:/var/www/vhosts/project1
nginx:
build: ./images/nginx
image: project1/nginx:latest
ports:
- "80:80"
volumes_from:
- applications
networks:
appnet:
aliases:
- project1.app
- admin.project1.app
php:
image: project1/php:latest
ports:
- "7778:7778"
build:
context: ./images/php
dockerfile: Dockerfile
volumes_from:
- applications
networks:
- appnet
mysql:
image: project1/mysql:latest
build: ./images/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
volumes:
- mysqldata:/var/lib/mysql
networks:
- appnet
ports:
- "33066:3306"
workspace:
image: project1/workspace:latest
build:
context: ./images/workspace
volumes_from:
- applications
working_dir: /var/www/vhosts/project1
networks:
- appnet
networks:
appnet:
driver: "bridge"
volumes:
mysqldata:
driver: "local"
the second docker compose file:
version: '2'
services:
project2_applications:
image: tianon/true
volumes:
- ../../:/var/www/vhosts/project2
project2_nginx:
build: ./images/nginx
image: project2/nginx:latest
ports:
- "8080:80"
volumes_from:
- project2_applications
networks:
project2_appnet:
aliases:
- project2.app
- admin.project2.app
project2_php:
image: project2/php:latest
ports:
- "7777:7777"
build:
context: ./images/php
dockerfile: Dockerfile
volumes_from:
- project2_applications
networks:
- project2_appnet
project2_mysql:
image: project2/mysql:latest
build: ./images/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
volumes:
- project2_mysqldata:/var/lib/mysql
networks:
- project2_appnet
ports:
- "33067:3306"
project2_workspace:
image: project2/workspace:latest
build:
context: ./images/workspace
volumes_from:
- project2_applications
working_dir: /var/www/vhosts/videosite
networks:
- project2_appnet
networks:
project2_appnet:
driver: "bridge"
volumes:
project2_mysqldata:
driver: "local"
And now when I have already built project1 and trying to run docker-compose up -d for the second project I see warning:
WARNING: Found orphan containers (docker_workspace_1, docker_nginx_1, docker_php_1, docker_mysql_1, docker_memcached_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
I have a supposition that it's because container names for project1 should be more specific and I need to add some prefixes like I'm doing for project2, but project1 is in use by many other developers and I do not want to change it.
Is there any way to turn off orphan check?
And the second thing: is just a warning message but for some reason, after it appearing compose is failing with error:
ERROR: Encountered errors while bringing up the project.
And to make it work I need to run docker-compose up -d --remove-orphans
Compose uses the project name (which defaults to the basename of the project directory) internally to isolate projects from each other. The project name is used to create unique identifiers for all of the project's containers and other resources. For example, if your project name is myapp and it includes two services db and web, then Compose starts containers named myapp_db_1 and myapp_web_1 respectively.
You get the "Found orphan containers" warning because docker-compose detects some containers which belong to another project with the same name.
To prevent different projects from interfering with each other (and suppress the warning) you can set a custom project name by using any of the following options:
The -p command line option.
COMPOSE_PROJECT_NAME environment variable. This environment variable can also be set via an environment file (.env in the current working directory by default).
Top-level name element in the Compose file. Note: if you pass multiple files to docker-compose via the -f option, then the value from the last file will be used.
docker-compose takes the name of the directory it is in as the default project name.
You can set a different project name by using -p or --project-name.
https://docs.docker.com/compose/reference/#use--p-to-specify-a-project-name
I had a similar problem because my projects all had the docker/docker-compose.yml structure.
To build on other answers, I create a .env file with my docker compose projects. I have a number of projects that all use the docker directory but are different projects.
To use docker-compose -p is a bit error prone, so creating .env file in the same directory as the docker-compose.yml:
-rw-rw-r-- 1 auser auser 1692 Aug 22 20:34 docker-compose.yml
-rw-rw-r-- 1 auser auser 31 Aug 22 20:44 .env
alleviates the necessary overhead of remembering -p.
In the .env file, I can now set the COMPOSE_PROJECT_NAME variable:
COMPOSE_PROJECT_NAME=myproject
On running:
docker-compose up -d
the COMPOSE_PROJECT_NAME is substituted without the use of -p.
Reference:
https://docs.docker.com/compose/env-file/
docker-compose up --remove-orphans
you can run this command to clean orphan containers. As specified in the warning
If the orphaned containers are expected and not intended to remove, you can set COMPOSE_IGNORE_ORPHANS variable to true.
Consise but just right away working source is here.
One option is to put it as a line into .env file next to docker-compose.yml like this:
COMPOSE_IGNORE_ORPHANS=True
Another option is pass or set it as an environment variable.
sh:
COMPOSE_IGNORE_ORPHANS=True docker-compose up -d
or
export COMPOSE_IGNORE_ORPHANS=True
docker-compose up -d
cmd:
SET COMPOSE_IGNORE_ORPHANS=True&& docker-compose up -d
powershell:
$env:COMPOSE_IGNORE_ORPHANS = 'True'; & docker-compose up -d
TL;DR
You can also add a unique name: myproject to each of your compose files.
My journey
In case this helps anybody else scrounging around to find help for the above issue (This is in support of the already good comments here):
I have several config files in the same directory
redis.yml
mariadb.yml
...
and I kept getting the same error about orphan containers when I ran
docker-compose -f <one of my configs>.yml up
as of now you can simply put each yml file into a separate project. This is simply done using the command like parameter "-p my_project_name" as has already been mentioned before. BUT the name must be in all lowercase!
This got me a little closer but I also kept forgetting that to bring the docker container down using docker-compose I needed to include that parameter as well.
For example to start the container:
docker-compose -p myproject-d redis.yml up -d
and to destroy the container
docker-compose -p myproject-d redis.yml down
Today I found that I can simply add the name: bit into the yml config. Here is an example for redis:
version: '3.9'
name: redis
services:
redis_0:
...
Now I can simply start the container with the following and don't have to worry about project names again:
docker-compose -f redis.yml <up/down>
This happens when your docker-compose file has got updated. I received similar error on Docker startup and found out that another team member updated the docker-compose.yml as part of cleanup.
To fix this, I deleted the docker group using the Delete button in Docker Desktop and started it again. This fixed the error for me.
As a complement for the existing answers, if you're using docker-compose with the -f option, to my surprise docker-compose will use the name of the parent folder of the first file passed via -f as the project name.
For example, assuming the following folder structure:
/
└── Users/
└── papb/
├── a.yml
└── foo/
└── b.yml
If you're in /Users and run docker-compose -f papb/a.yml -f papb/foo/b.yml:
The project name will be inferred as papb
Any relative paths you have in both files will be resolved against /Users/papb
If you're in /Users and run docker-compose -f papb/foo/b.yml -f papb/a.yml:
The project name will be inferred as foo
Any relative paths you have in both files will be resolved against /Users/papb/foo
If you're in /Users/papb and run docker-compose -f foo/b.yml -f a.yml:
The project name will be inferred as foo
Any relative paths you have in both files will be resolved against /Users/papb/foo