Restart entire docker compose stack from one of the containers - docker

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

Related

What is the difference between docker run -p and ports in docker-compose.yml?

I would like to use a standard way of running my docker containers. I have have been keeping a docker_run.sh file, but docker-compose.yml looks like a better choice. This seems to work great until I try to access my website running in the container. The ports don't seem to be set up correctly.
Using the following docker_run.sh, I can access the website at localhost. I expected the following docker-compose.yml file to have the same results when I use the docker-compose run web command.
docker_run.sh
docker build -t web .
docker run -it -v /home/<user>/git/www:/var/www -p 80:80/tcp -p 443:443/tcp -p 3316:3306/tcp web
docker-compose.yml
version: '3'
services:
web:
image: web
build: .
ports:
- "80:80"
- "443:443"
- "3316:3306"
volumes:
- "../www:/var/www"
Further analysis
The ports are reported as the same in docker ps and docker-compose ps. Note: these were not up at the same time.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
<id> web "/usr/local/scripts/…" About an hour ago Up About an hour 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:3307->3306/tcp <name>
$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------------------------------
web /usr/local/scripts/start_s ... Up 0.0.0.0:3316->3306/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
What am I missing?
As #richyen suggests in a comment, you want docker-compose up instead of docker-compose run.
docker-compose run...
Runs a one-time command against a service.
That is, it's intended to run something like a debugging shell or a migration script, in the overall environment specified by the docker-compose.yml file, but not the standard command specified in the Dockerfile (or the override in the YAML file).
Critically to your question,
...docker-compose run [...] does not create any of the ports specified in the service configuration. This prevents port collisions with already-open ports. If you do want the service’s ports to be created and mapped to the host, specify the --service-ports flag.
Beyond that, the docker run command you show and the docker-compose.yml file should be essentially equivalent.
You don't run docker-compose.yamls the same way that you would run a local docker image that you have either installed or created on your machine. docker-compose files are typically launched running the command docker-compose up -d to run in detached mode. Then when you run docker ps you should see it running. You can also run docker-compose ps as you did above.

Edit a file in docker container from outside the container?

I have one docker container, that container is running in weblogic11 so that Weblogic is running by default in Production-mode, so I want to change that production-mode to Development-mode, for that I need to edit file config.xml inside the container, how we can edit that file from outside the container?
Absolutely you can do that. There's docker configuration called mounting. To mount the file inside container, add -v parameter on your docker run command:
docker run -d -v /path/to/your-file.xml:/path/to/file/inside/container-shoulbe.xml image:version
or if you are using docker-compose, your docker-compose.yml should be like this:
...
services:
web:
image: xxx:version
volumes:
...
- /path/to/your-file.xml:/path/to/file/inside/container-shoulbe.xml
...
Hope it helps.
You can do this by mounting your volumes. E.g
services:
web:
image: your_image:tag
volumes:
- app_config:/locaiton_of_config_folder
volumes:
app_config:
This will create docker volumes and it will be mounted at /var/lib/docker/volumes/volume_name/_data and you can edit the files. Be sure to use sudo because the files are created by root user inside docker.
You can check the list of volumes by docker volume ls.
Using this comand to get inside container :
docker exec -it container_id bash
Then vi /path/to/config.xml , nano /path/to/config.xml, .... if you want to edit file .
then restart container :
docker restart container_id

Connect to docker-compose network using docker run

Let say I have running orchestration with docker-compose with docker-compose.yml looking like this:
version: '2.2'
services:
service1:
# ...
networks:
- compose_network
service2:
# ...
networks:
- compose_network
networks:
compose_network:
I aim to run and connect temporarily one container to compose_network_1. I tried using
$ docker run --net=compose_network <image for the job>
but I could not connect. I am also aware that docker-compose names the networks as [projectname]_default, so I also tried that variant, but with same result.
Is there a way I can accomplish that?
I'm not sure if the --net option ever existed but it's now --network.
From docker run --help:
--network string Connect a container to a network (default "default")
As #maxm notes you can find the network name, with the DIR prefix of the compose project directory, then simply run it as you were trying:
$ docker run --network=DIR_compose_network <image for the job>
I wanted to connect on run as my container is transient (running tests) so I can't use a second docker network command in time before it quits.
e.g. for my docker composition in a "dev" folder with no network name specified so uses the docker-compose "default" name, therefore I get the name dev_default.
docker network ls
NETWORK ID NAME DRIVER SCOPE
2c660d9ed0ba bridge bridge local
b81db348e773 dev_default bridge local
ecb0eb6e93a5 host host local
docker run -it --network dev_default myimage
This connects the new docker container to the existing docker-compose network.
The network name is going to be something like name-of-directory_compose_network. Find the name with docker network ls
I had success with:
docker-compose up # within directory ./demo
docker run -itd -p "8000:8000" --hostname=hello "crccheck/hello-world"
# outputs: 1e502f65070c9e2da7615c5175d5fc00c49ebdcb18962ea83a0b24ee0440da2b
docker network connect --alias hello demo_compose_network 1e502f65070c
I could then curl hello:8000 from inside my docker compose containers. Should be the exact same functionality as your commands, just with an added alias.

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

Jenkins inside docker loses configuration when container is restarted

I have followed the next guide https://hub.docker.com/r/iliyan/jenkins-ci-php/ to download the docker image with Jenkins.
When I start my container using docker start CONTAINERNAME command, I can access to Jenkins from localhost:8080.
The problem comes up when I change Jenkins configuration and restart Jenkins using docker stop CONTAINERNAME and docker start CONTAINERNAME, my Jenkins doesn't contain any of my previous configuration changes..
How can I persist the Jenkins configuration?
You need to mount the Jenkins configuration as a volume, the -v flag will do just that for you. (you can ignore the --privileged flag in my example unless you plan on building docker images inside your jenkins docker image)
docker run --privileged --name='jenkins' -d -p 6999:8080 -p 50000:50000 -v /home/jan/jenkins:/var/jenkins_home jenkins:latest
The -v flag will mount your /var/jenkins_home outside your container in /home/jan/jenkins maintaining it between rebuilds.
--name so that you have a fixed name for the container to start / stop it from.
Then next time you want to run it, simply call
docker start jenkins
My understanding is that the init script
/sbin/tini -- /usr/local/bin/jenkins.sh
is reseting jenkins configuration on startup within the folder provided through the
JENKINS_HOME env var,
wether mounted outside the docker vm or not.
It is but possible to store the configuration on github using
configure/"Configure System"/"SCM Sync configuration"/Git
section.
See possible detailed configuration here
You can use this docker-compose file:
version: '3.1'
services:
jenkins:
image: jenkins:latest
container_name: jenkins
restart: always
environment:
TZ: GMT
volumes:
- ./jenkins_host:/var/jenkins_home
ports:
- 8080:8080
tty: true
You only need to share the jenkins volume ./jenkins_host:/var/jenkins_home with host folder
Besides the obvious, like running parameters that clear up the image that you should disable, you can do a few things:
use docker commit and reuse the commited container
mount the part where you write to the local file system with docker volumes
my favorite : use command :
docker container restart containername
Depending on your needs you can pick one.
I use the latter for example when testing jenkins plugins and it retains the data inside.
Source of the latter that is also useful for updates:
https://jimkang.medium.com/how-to-start-a-new-jenkins-container-and-update-jenkins-with-docker-cf628aa495e9

Resources