Docker compose stops multiple services - docker

I hope I didn't miss anything simple from the manual.
The structure is:
/home/user
/foo1/bar1/docker/
Dockerfile
docker-compose.yml
/foo2/bar2/docker/
Dockerfile
docker-compose.yml
docker-compose.yml
version: '3.9'
services:
foo1-bar1:
build:
context: .
args:
DOCKER_SERVER_ROOT_DIR: ${DOCKER_SERVER_ROOT_DIR}
dockerfile: Dockerfile
image: foo1-bar1:v1
container_name: foo1-bar1-v1
The same is for foo-bar-v2.
Both of them I successfully run as:
cd /foo1/bar1/docker/
docker-compose up -d
[+] Running 1/1
⠿ Container foo1-bar1-v1 Started
cd /foo2/bar2/docker/
docker-compose up -d
[+] Running 1/1
⠿ Container foo2-bar2-v1 Started
The question is, why does it stop both of them when I try to stop only 1? Service names, container names, image names are different...
user#vm:~/foo1/bar1/docker$ docker-compose stop
[+] Running 2/2
⠿ Container foo1-bar1-v1 Stopped
⠿ Container foo2-bar2-v2 Stopped

docker-compose has the concept of projects. Run docker-compose --help and you will see:
--project-directory string Specify an alternate working directory
(default: the path of the, first specified, Compose file)
-p, --project-name string Project name
So in your case, both your services belong to the same project named docker.
You can actually run docker-compose -p docker ps and you will see both your services.
You can also override this by specifying your own project name independent of the directory name.
My version of docker-compose (Docker Compose version v2.10.2 MacOS) does warn me that there are orphan containers in this project when I replicate your setup. Also it doesn't automatically stop "orphan" services and gives a warning that the network could not be removed either.
This is also another interesting fact: both services run on the same network (docker_default) only because the project name (folder name) is the same.
I hope this explains it.

You have to specify the service to stop. Otherwise it will stop all services.
docker compose stop [OPTIONS] [SERVICE...]
here : docker-compose stop foo1-bar1

Related

Restart entire docker compose stack from one of the containers

Is there any proper way of restarting an entire docker compose stack from within one of its containers?
One workaround involves mounting the docker socket:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
and then use the Docker Engine SDKs (https://docs.docker.com/engine/api/sdk/examples/).
However, this solution only allows restarting the containers itselves. There seems to be no way to send compose commands, like docker compose restart, docker compose up, etc.
The only solution I've found to send docker compose commands is to open a terminal on the host from the container using ssh, like this: access host's ssh tunnel from docker container
This is partly related to How to run shell script on host from docker container? , but I'm actually looking for a more specific solution to only send docker compose commands.
I tried with this simple docker-compose.yml file
version: '3'
services:
nginx:
image: nginx
ports:
- 3000:80
Then I started a docker container using
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd):/work docker
Then, inside the container, I did
cd /work
docker-compose up -d
and it started the container up on the host.
Please note that you have an error in your socket mapping. It needs to be
- /var/run/docker.sock:/var/run/docker.sock
(you have a period instead of a slash at one point)
As mentioned by #BMitch in the comments, compose project name was the reason why I wasn't able to run docker compose commands inside the running container.
By default the compose project name is set to the directory name, so if the docker-compose.yml is run from a host directory named folder1, then the commands inside the container should be run as:
docker-compose -p folder1 ...
So now, for example, restarting the stack works:
docker-compose -p folder1 restart
Just as a reference, a fixed project name for your compose can be set using name: ... as a top-level attribute of the .yml file, but requires docker compose v2.3.3 : Set $PROJECT_NAME in docker-compose file

Docker Compose Always Force Build for One Service

This is a section of my docker-compose file:
version: "3.2"
services:
cachable_service:
image: my/cachable_service:x.x
build:
context: .
dockerfile: cachable_service_Dockerfile
service_in_development:
image: my/service_in_development:latest
build:
context: .
dockerfile: Dockerfile
depends_on:
- cachable_service
How do I force only the image for the service_in_development to be always build from scratch so I get my latest code in there?
I've looked into the cache_from option in the docker-compose file reference, but I couldn't find any clear explanation on what exactly it does.
Clarifications:
In this question, I was asking about an option to force rebuild only specific services using an option in the docker-compose.yml file itself. But, if a commandline option let's me do this, I'd be happy with that as well for now.
Also, I'm talking about forcing a 'rebuild' of images. Not just 'recreation' of service.
You can use command below to rebuild all images:
docker-compose up --build --force-recreate
to force rebuild one service:
docker-compose up --build --force-recreate service-name-here
More useful parameters in documentation
Usage: up [options] [--scale SERVICE=NUM...] [SERVICE...]
Options:
-d, --detach Detached mode: Run containers in the background,
print new container names. Incompatible with
--abort-on-container-exit.
--no-color Produce monochrome output.
--quiet-pull Pull without printing progress information
--no-deps Don't start linked services.
--force-recreate Recreate containers even if their configuration
and image haven't changed.
--always-recreate-deps Recreate dependent containers.
Incompatible with --no-recreate.
--no-recreate If containers already exist, don't recreate
them. Incompatible with --force-recreate and -V.
--no-build Don't build an image, even if it's missing.
--no-start Don't start the services after creating them.
--build Build images before starting containers.
--abort-on-container-exit Stops all containers if any container was
stopped. Incompatible with -d.
-t, --timeout TIMEOUT Use this timeout in seconds for container
shutdown when attached or when containers are
already running. (default: 10)
-V, --renew-anon-volumes Recreate anonymous volumes instead of retrieving
data from the previous containers.
--remove-orphans Remove containers for services not defined
in the Compose file.
--exit-code-from SERVICE Return the exit code of the selected service
container. Implies --abort-on-container-exit.
--scale SERVICE=NUM Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.

Don't create containers twice with docker-compose up and running docker run containers

I'd like docker-compose to use an already running container for imageA and not create it a second time when calling docker-compose up -d. The original container was run using docker run.
Steps:
I started a container with docker run, eg.
docker run --name imageA -d -p 5000:5000 imageA
I then call docker-compose up -d with a docker-compose.yml file that includes a service with the same name and image as the first container.
version: "3"
services:
imageA:
image: imageA
ports:
- "5000:5000"
imageB:
image: imageB
ports:
- "5001:5001"
What happens:
docker-compose tries to create imageA and fails when it tries to bind port 5000 since container imageA has it bound already.
Question: How can docker-compose "adopt" or "include" the first container without trying to create it a again?
I don't believe this is currently possible. If you compare the outputs of docker ps and docker-compose ps, you should notice that docker-compose ps does not show the imageA running, if it was started with docker run.
Docker-compose is only interested in the services that are defined in the docker-compose files, and it does not seem to use only the container names for that, but labels too, and you cannot add labels to running containers currently.
Other than that, the container started with docker run will also not be (at least by default) in the same internal network as those that are started with docker-compose.
So your best option would be either:
a) Removing the already running container from the compose-file.
b) Calling docker-compose up -d imageB to run only the individual service, so that the compose updates only that or
c) just stopping the already running container and starting it again with compose.
Docker containers should anyway be created in a way that it is easy and acceptable to just restart them when needed.
Adding --no-recreate flag will prevent recreation of the container, if it already exists.
Example:
docker-compose -f docker-compose-example.yaml up -d --no-recreate

Why does docker-compose depends on working directory?

When calling docker-compose in different directories, I get conflict errors and problems with networking:
Problem with conflicts
docker-compose.yml
version: '3'
services:
redis:
image: "redis:alpine"
container_name: redis
I. create and start docker container by docker-compose => OK
$ docker-compose up --force-recreate -d
Creating redis ... done
II. recreate and start docker container by docker-compose => OK
$ docker-compose up --force-recreate -d
Recreating redis ... done
III. copy docker-compose.yml to other directory.
Then try to recreate from other directory => ERROR
$ cp docker-compose.yml red2/
$ cd red2/
$ docker-compose up --force-recreate -d
Creating redis ... error
ERROR: for redis Cannot create container for service redis: Conflict. The container name "/redis" is already in use by container "1ba060b545f716731ac1c5992b680e4d4b3639fc0ffeb291899c712f0839d23a". You have to remove (or rename) that container to be able to reuse that name.
ERROR: Encountered errors while bringing up the project.
Different Networks
Containers created from docker-compose in different directories also do not share the same network.
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
4a4af52e89cd red2_default bridge local
57695428bd9d redis_default bridge local
Usecase
My usecase for that szenario:
Call docker-compose from different deployment jobs.
Start containers for testing
Questions
Why is there the directory dependency? Is there an option to switch it off?
Does docker ps show which directory was used?
Answer for 1:
The directory name is used as the default project name.
You should better specify the project name:
docker-compose -p myproject up --force-recreate -d
Question 2 still open

docker-compose, rebuild image(s) without starting containers

I docker compose, it is possible to define the context as follows
version: '3'
services:
node1:
build: node1
image: node1
container_name: node1
node2:
build: node2
image: node2
container_name: node2
Where build refers to directory containing Dockerfile and the build resources. By using the command docker-compose up -d --build it is possible to rebuild images and restart changed containers. But using the following docker-compose file, is it possible to only build images without starting them, and preferably choose the images to build or build all?
You can build specific services without starting them like so:
docker-compose build node1
To build them all:
docker-compose build
You can also try docker-compose up --no-start
It will perform build , create network , create volume without starting containers.
Usage: up [options] [--scale SERVICE=NUM...] [SERVICE...]
Options:
-d, --detach Detached mode: Run containers in the background,
print new container names. Incompatible with
--abort-on-container-exit.
--no-color Produce monochrome output.
--quiet-pull Pull without printing progress information
--no-deps Don't start linked services.
--force-recreate Recreate containers even if their configuration
and image haven't changed.
--always-recreate-deps Recreate dependent containers.
Incompatible with --no-recreate.
--no-recreate If containers already exist, don't recreate
them. Incompatible with --force-recreate and -V.
--no-build Don't build an image, even if it's missing.
--no-start Don't start the services after creating them.

Resources