docker-compose up recreates container when config is unchanged - docker

I am not clearly understand how docker-compose realizes when to recreate container or where not.
My case is:
docker-compose -f conf.yml up // Ok
docker-compose -f conf.yml up // xxx is up-to-date
Then I do:
docker-compose -f /copy/conf.yml up // Recreating container
But copy/conf.yml is same as conf.yml
Why docker-compose recreates container, while it's config is unchanged? Its only loaded from other path. How docker-compose handles this stuff?
It must says "up-to-date", if config is same, despite of config's path (I know about --no-recreate flag, but I want to know how things works)

If one folder is /app/conf.yml and the other folder is /app_copy/conf.yml, then you'll find that docker creates two different "projects", one for "app" and the other for "appcopy" (it removes non-alphanumeric characters and makes it all lower case). The project is the first part of each container name by default, it's named $project_$service_$instance.
If you specify the container name inside your docker-compose.yml, then docker-compose will recreate it if you have things like volume mounts to the current folder which would be different. Otherwise, if the compose files are truly identical, the source image hasn't changed, and there are no externalities that would be different, then I'm not able to reproduce this one.
Here's an example without a fixed container_name:
$ docker-compose -f docker-compose.test.yml up -d
Creating test_testapp_1
$ docker-compose -f test/docker-compose.test.yml up -d
test_testapp_1 is up-to-date
Below is what happens if you try to specify a container name in the compose file:
$ pwd
..../test
$ docker-compose -f docker-compose.name.yml up -d
Starting unique_name
$ docker-compose -f subdir/docker-compose.name.yml up -d
Creating network "subdir_default" with the default driver
Creating unique_name
ERROR: for test Cannot create container for service test: Conflict. The container name "/unique_name" is already in use by container 80b44bc94912b755cf2430b132fa6112f960e2752f69a357c27375bbc905ff76. You have to remove (or rename) that container to be able to reuse that name.
$ mv subdir test
$ docker-compose -f test/docker-compose.name.yml up -d
unique_name is up-to-date

Related

Docker move/export docker-compose container to another machine

I am a beginner with docker and have created a docker-compose.yml file. Everything is running well, but I want to move my container that is generated by "docker-compose up" to another machine. How can I save/export my container that is running my services of the docker-compose.yml to another machine?
Thanks
For commit running container to image with new tag you can use this command :
$ docker commit <containerID> new_image_name:tag
For save new_image_name:tag to file use :
$ docker save -o new_file_name.tar new_image_name:tag
Now you can move your docker-compose.yml to same folder to another machine and your new_file_name.tar too.
On your mother machine where are this files run :
$ docker load --input new_file_name.tar
Rewrite in docker-compose.yml section image: to your new_image_name:tag
If you lost the name use :
$ docker images
and continue with $ docker load..... from above
Last step is run :
$ docker-compose up -d

The container exited with status code (1)

I encountered an issue when running the docker container.
An error log was generated as below:
[Error] mysqld : unknown variable “wait_timeout = 288000”.
I wanted to test some docker container features.
So, I opened the docker bash and entered the directory /etc/mysql/my.cnf.
And I added the variable “wait_timeout = 288000” below [mysqld] option.
However, after rebooting, when I ran the container, it exited immediately with status code (1).
I knew that the error was caused by the variable I just added.
So, I wanted to delete the variable, but now the docker container bash won’t open.
Is there any way that I can delete the variable “wait_timeout” in this case?
If there isn’t, could you recommend other methods for troubleshooting?
Thanks for checking the issue.
Delete and recreate the container, and it will start fresh from a clean container filesystem.
That is probably also a better way to modify the database configuration (if you do, in fact, need a custom my.cnf). You can bind-mount a directory of configuration files into the container at startup time:
docker run -d -p 3306:3306 --name mysql \
-v $PWD/mysql-conf:/etc/mysql/conf.d \
mysql:8
Then when the configuration changes, you can delete and recreate this container:
docker stop mysql
docker rm mysql
docker run -d -p 3306:3306 ... mysql:8 # as above
(See "Using a custom MySQL configuration file" in the Docker Hub mysql image page for more information.)
Deleting and recreating Docker containers is very routine, and one of the benefits is that when a new container starts, it always has a "clean" filesystem. This particular setup also makes sure the modified configuration file is stored outside the container, so if you are forced to recreate the container (to upgrade MySQL to get a critical security fix, for example) it's something you're used to doing and you won't lose data or settings.

How to know which command or compose file has been used to start Docker containers?

Is there any way to find a source of the docker container script? I have a setup where I can not find any docker-compose.yml file nor the bash script etc that would have run all the Docker containers currently running. I have a virtual machine that starts docker containers on the startup, but have no idea which file is actually run.
i think no option to know which docker-compose file is use.
but you can check manual every you project folder.
the docker-compose mechanism is by matching the docker-compose.yml file. so if you run command sudo docker-compose ps in every your project folder. docker-compose will match between the docker-compose file used by container and docker-compose file in your project, if the same than the results will be displayed, if not the results is not displayed
If the containers are running automatically on reboot and you have no cron/bash profile/rc.local or any other startup screen then that may mean that they are containers with --restart option set. You can change that by running below command
docker ps -q | xargs docker update --restart no
docker ps -q | xargs docker stop
Then restart the machine. The containers should not start. If they do then you have some script somewhere which is starting them

Docker-compose ps not showing any output

I am trying to run docker-compose ps and docker-compose logs and neither are showing any output. I was able to run docker-compose up and verified the correct containers are started with docker ps. However docker-compose logs and ps dont show anything
> sudo docker-compose -f /opt/docker-compose/server1-compose.yml ps
Name Command State Ports
------------------------------
> sudo docker-compose -f /opt/docker-compose/server1-compose.yml logs
Attaching to
Both commands are returning intended output. What is wrong here?
docker-compose version: 1.4.2
Docker version 1.7.1, build 786b29d
thanks so #dnephin to posting a response. For completeness here it is:
dnephin-
" I suspect what's happening here is that the project name is
different. The default project name is the basename of a directory, so
if you run docker-compose from a different directory you might get a
different project name.
You can set it with either -p or COMPOSE_PROJECT_NAME environment
variable. If you look at the first part of the container names (before
the first underscore) that's the project name.
There are open issues to configure the project name from a file. I
think we'll be looking to implement that soon."
Adding the -p switch to my compose command fixed the issue.
ie: sudo docker-compose -f /opt/docker-compose/server1-compose.yml logs -p projectname

How to set an environment variable in a running docker container

If I have a docker container that I started a while back, what is the best way to set an environment variable in that running container? I set an environment variable initially when I ran the run command.
$ docker run --name my-wordpress -e VIRTUAL_HOST=domain.example --link my-mysql:mysql -d spencercooley/wordpress
but now that it has been running for a while I want to add another VIRTUAL_HOST to the environment variable. I do not want to delete the container and then just re-run it with the environment variable that I want because then I would have to migrate the old volumes to the new container, it has theme files and uploads in it that I don't want to lose.
I would just like to change the value of VIRTUAL_HOST environment variable.
There are generaly two options, because docker doesn't support this feature now:
Create your own script, which will act like runner for your command. For example:
#!/bin/bash
export VAR1=VAL1
export VAR2=VAL2
your_cmd
Run your command following way:
docker exec -i CONTAINER_ID /bin/bash -c "export VAR1=VAL1 && export VAR2=VAL2 && your_cmd"
Docker doesn't offer this feature.
There is an issue: "How to set an enviroment variable on an existing container? #8838"
Also from "Allow docker start to take environment variables #7561":
Right now Docker can't change the configuration of the container once it's created, and generally this is OK because it's trivial to create a new container.
For a somewhat narrow use case, docker issue 8838 mentions this sort-of-hack:
You just stop docker daemon and change container config in /var/lib/docker/containers/[container-id]/config.json (sic)
This solution updates the environment variables without the need to delete and re-run the container, having to migrate volumes and remembering parameters to run.
However, this requires a restart of the docker daemon. And, until issue issue 2658 is addressed, this includes a restart of all containers.
To:
set up many env. vars in one step,
prevent exposing them in 'sh' history, like with '-e' option (passing credentials/api tokens!),
you can use
--env-file key_value_file.txt
option:
docker run --env-file key_value_file.txt $INSTANCE_ID
Here's how you can modify a running container to update its environment variables. This assumes you're running on Linux. I tested it with Docker 19.03.8
Live Restore
First, ensure that your Docker daemon is set to leave containers running when it's shut down. Edit your /etc/docker/daemon.json, and add "live-restore": true as a top-level key.
sudo vim /etc/docker/daemon.json
My file looks like this:
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
},
"live-restore": true
}
Taken from here.
Get the Container ID
Save the ID of the container you want to edit for easier access to the files.
export CONTAINER_ID=`docker inspect --format="{{.Id}}" <YOUR CONTAINER NAME>`
Edit Container Configuration
Edit the configuration file, go to the "Env" section, and add your key.
sudo vim /var/lib/docker/containers/$CONTAINER_ID/config.v2.json
My file looks like this:
...,"Env":["TEST=1",...
Stop and Start Docker
I found that restarting Docker didn't work, I had to stop and then start Docker with two separate commands.
sudo systemctl stop docker
sudo systemctl start docker
Because of live-restore, your containers should stay up.
Verify That It Worked
docker exec <YOUR CONTAINER NAME> bash -c 'echo $TEST'
Single quotes are important here.
You can also verify that the uptime of your container hasn't changed:
docker ps
You wrote that you do not want to migrate the old volumes. So I assume either the Dockerfile that you used to build the spencercooley/wordpress image has VOLUMEs defined or you specified them on command line with the -v switch.
You could simply start a new container which imports the volumes from the old one with the --volumes-from switch like:
$ docker run --name my-new-wordpress --volumes-from my-wordpress -e VIRTUAL_HOST=domain.com --link my-mysql:mysql -d spencercooley/wordpres
So you will have a fresh container but you do not loose the old data. You do not even need to touch or migrate it.
A well-done container is always stateless. That means its process is supposed to add or modify only files on defined volumes. That can be verified with a simple docker diff <containerId> after the container ran a while.
In that case it is not dangerous when you re-create the container with the same parameters (in your case slightly modified ones). Assuming you create it from exactly the same image from which the old one was created and you re-use the same volumes with the above mentioned switch.
After the new container has started successfully and you verified that everything runs correctly you can delete the old wordpress container. The old volumes are then referred from the new container and will not be deleted.
If you are running the container as a service using docker swarm, you can do:
docker service update --env-add <you environment variable> <service_name>
Also remove using --env-rm
To make sure it's addedd as you wanted, just run:
docker exec -it <container id> env
1. Enter your running container:
sudo docker exec -it <container_name> /bin/bash
2. Run command to all available to user accessing the container and copy them to user running session that needs to run the commands:
printenv | grep -v "no_proxy" >> /etc/environment
3. Stop and Start the container
sudo docker stop <container_name>
sudo docker start <container_name>
Firstly you can set env inside the container the same way as you do on a linux box.
Secondly, you can do it by modifying the config file of your docker container (/var/lib/docker/containers/xxxx/config.v2.json). Note you need restart docker service to take affect. This way you can change some other things like port mapping etc.
here is how to update a docker container config permanently
stop container: docker stop <container name>
edit container config: docker run -it -v /var/lib/docker:/var/lib/docker alpine vi $(docker inspect --format='/var/lib/docker/containers/{{.Id}}/config.v2.json' <container name>)
restart docker
I solve this problem with docker commit after some modifications in the base container, we only need to tag the new image and start that one
docs.docker.com/engine/reference/commandline/commit
docker commit [container-id] [tag]
docker commit b0e71de98cb9 stack-overflow:0.0.1
then you can pass environment vars or file
docker run --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY --env AWS_SESSION_TOKEN --env-file env.local -p 8093:8093 stack-overflow:0.0.1
the quick working hack would be:
get into the running container.
docker exec -it <container_name> bash
set env variable,
install vim if not installed in the container
apt-get install vim
vi ~/.profile at the end of the file add export MAPPING_FILENAME=p_07302021
source ~/.profile
check whether it has been set! echo $MAPPING_FILENAME(make sure you should come out of the container.)
Now, you can run whatever you're running outside of the container from inside the container.
Note, in case you're worried that you might lose your work if the current session you logged in gets logged off. you can always use screen even before starting step 1. That way if you logged off by chance of your inside running container session, you can log back in.
After understand that docker run an image constructed with a dockerfile , and the only way to change it is build another image stop everything and run everything again .
So the easy way to "set an environment variable in a running docker container" is read dockerfile [1] (with docker inspect) understand how docker starts [1].
In the example [1] we can see that docker start with /usr/local/bin/docker-php-entrypoint and we could edit it with vi and add one line with export myvar=myvalue since /usr/local/bin/docker-php-entrypoint Posix script .
If you can change dockerfile, you can add a call to a script [2] for example /usr/local/bin/mystart.sh and in that file we can set your environment var.
Of course after change the scripts you need restart the container [3]
[1]
$ docker inspect 011aa33ba92b
[{
. . .
"ContainerConfig": {
"Cmd": [
"php-fpm"
],
"WorkingDir": "/app",
"Entrypoint": [
"docker-php-entrypoint"
],
. . .
}]
[2]
/usr/local/bin/mystart.sh
#!/bin/bash
export VAR1=VAL1
export VAR2=VAL2
your_cmd
[3]
docker restart dev-php (container name)
Hack with editing docker inner configs and then restarting docker daemon was unsuitable for my case.
There is a way to recreate container with new environment settings and use it for some time.
1. Create new image from runnning container:
docker commit my-service
a1b2c3d4e5f6032165497
Docker created new image, and answered with its id. Note, the image doesn't include mounts and networks.
2. Stop and rename original container:
docker stop my-service
docker rename my-service my-service-original
3. Create and start new container with modified environment:
docker run \
-it --rm \
--name my-service \
--network=required-network \
--mount type=bind,source=/host/path,target=/inside/path,readonly \
--env 'MY_NEW_ENV_VAR=blablabla OLD_ENV=zzz' \
a1b2c3d4e5f6032165497
Here, I did the following:
created new temporary container from image built on step 1, that will show its output on terminal, will exit on Ctrl+C, and will be deleted after that
configured its mounts and networks
added my custom environment configuration
4. After you worked with temporary container, press Ctrl+C to stop and remove it, and then return old container back:
docker rename my-service-original my-service
docker start my-service
How to set environment variable in a running docker container as a development environment
Basically you can do like in normal linux, adding export MY_VAR="value" to ~/.bashrc file.
Instructions
Using VScode attach to your running container
Then with VScode open the ~/.bashrc file
Export your variable by adding the code in the end of the file
export MY_VAR="value"
Finally execute .bashrc using source command
source ~/.bashrc
You could set an environment variable to a running Docker container by
docker exec -it -e "your environment Key"="your new value" <container> /bin/bash
Verify it using below command
printenv
This will update your key with the new value provided.
Note: This will get reverted back to old on if docker gets restarted.
Use export VAR=Value
Then type printenv in terminal to validate it is set correctly.

Resources