docker entrypoint script fails to run - docker

I have a script startScript.sh that I want to run after the docker container completely starts (including loading all services that the container is supposed to start)
After that I want to run a script: startScript.sh
This is what I do:
sudo docker run -p 8080:8080 <docker image name> " /bin/bash -c ./startScript.sh"
However this gives me an error:
WFLYSRV0073: Invalid option '/bin/bash'
Even tried different shells still same error. Even tried passing just the script file name. Still did not help.
Note: I know that the above file is in the container in the root folder: /
In fact I once entered the container by doing: sudo docker exec and manually ran that script file and it worked.
But when I try to automatically do it as above, it does not work for me.
Some questions:
1. Please suggest what could be the issue.
2. I want to run that script after the container has started completely and is up and running - including all the services that are part of it. Is this the right way to even do it? Or does this try to run while the container is starting up?

When you pass arguments after the image name, you are not modifying the entrypoint, but the command (CMD). It seems your image has WFLYSRV0073 as entrypoint, which makes the actual executed binary be your entrypoint, with your command as arguments. Which makes WFLYSRV0073 fail when trying to parse /bin/bash as an argument.
To run just your script, you could override the image's entrypoint with an empty string, making it run your command's first element. Notice I also remove the quotes, or else Docker will search for a binary with the name containing spaces, which of course doesn't exist.
sudo docker run --entrypoint "" -p 8080:8080 <docker image name> /bin/bash -c ./startScript.sh
However this is probably not what you want: it won't run what the image should actually be running, only your setup script. The correct thing to do here is to modify the image's Dockerfile to run the setup script as the entrypoint, and at the end of it run the script's current entrypoint (the actual thing you want to run).
Alternatively, if you do not control the image you are running, you can use FROM <the current image> in a new Dockerfile to build another image based on it, setting the entrypoint to your script.
Edit:
An example of how the above can be done can be seen in MariaDB's entrypoint: you first start a temporary server, run your setup, then restart it, running the definitive service (which is the CMD) at the end.
The above solutions are good in case you want to perform initialization for an image, but if you just want to be able to run a script for development reasons instead of doing it consistently on the image's entrypoint, you can copy it to your container and then use docker exec <container name> your-command and-arguments to run it.

Related

Docker: Keep Ubuntu container running after starting?

I am trying to start a docker container using the ubuntu image:
docker container run -d --name ubuntu_assignment_4 6e4f1fe62
However as soon as I start the container it stops again.
Why does this happen and how can I ensure the container stays running?
The image I am trying to run here is: ubuntu:14.04
If you are going to use the ubuntu:14.04 image without any modifications to it, you would not require a separate Dockerfile. And it is not possible to keep the plain ubuntu:14.04 image running as a container.
You can directly launch the container with an interactive shell using the ubuntu:14.04 image.
docker run -it ubuntu:14.04 /bin/bash
But the plain ubuntu:14.04 image does not have curl pre-installed on it.
You will need a custom Dockerfile for this.
I can't say exactly what is happening without seeing the complete Dockerfile that was used to build the image, but I am pretty certain that the trouble you are having is just because whatever task that is being started inside the container is finishing and exiting.
Docker containers work by having some command assigned (using ENTRYPOINT or CMD directives in the Dockerfile, or as an argument to docker start or docker run on the command line) which is the program that is started when the container loads. The container will live for as long as that task continues to run, and once that program finishes the container will terminate.
To specify the startup entrypoint at the command line, try:
docker create -it [image] /bin/bash
Then start it like this:
docker start -ia [Container ID]
The container will exit once the shell exits, because this is assigning the shell as the entry point.
cURL may not be installed by default. It is possible to install it using apt-get. But again, once the shell is closed, the container will stop and any changes will be lost. As a start, try creating a new directory somewhere, and then add a file called Dockerfile with this content:
FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl
ENTRYPOINT ["/bin/bash"]
That will create a new image with curl installed. then, from inside the new directory where the Dockerfile was created, use:
docker build .
docker images
which will build a new image, using the Dockerfile as the blueprint.
Once the build finishes, find the image ID for the new container, and run it using:
docker run -it [image id]
Ultimately, to make Docker really useful, the typical approach is to replace that last line in the Dockerfile (ENTRYPOINT ["command"]) with something that will continue running forever (like ENTRYPOINT ["apache2"] or ENTRYPOINT ["redis"] or similar). If you have experience using regular desktop/server OS installs, and full virtual machines like VMWare or VirtualBox, just remember that Docker is very different; the way it works and the patterns used to deploy it are not the same.

Debug set always restart container docker

How can I debug docker container that I set to always restart.
I have a container that launch nodejs app, with a
CMD ["nodemon", "/usr/src/app/app.js »] that work very well on other container but not on the new one i created it says with docker logs containerName :
Usage: nodemon [nodemon options] [script.js] [args]
See "nodemon --help" for more.
How can I connect to the container to have more informations than logs, for example see some config file or if my nodejs files have been copied.
I didn’t find a way : I would like to use docker exec -it bash and navigate in my docker but because it is always restarting I cannot. How to debug this kind of container ?
EDIT : i use the CMD["bash"] but when i use docker exec -it bash i doesn't work
Because the container keep restarting.
You could make a new image base on your container image, and a different starting script (one which runs the node command for testing, and then opens a bash for instance)
You could need to COPY that script
COPY myscript /usr/local/bin
CMD ["/usr/local/bin/myscript"]
That way, you can test your current image as wrapped in a test image.
You can even only use bash in that new image
CMD["bash"]
And launch the command manually.
For that, you would need to run that image with:
docker run -it --rm myNewImage
That will open an interactive bash session.

How to start a stopped Docker container with a different command?

I would like to start a stopped Docker container with a different command, as the default command crashes - meaning I can't start the container and then use 'docker exec'.
Basically I would like to start a shell so I can inspect the contents of the container.
Luckily I created the container with the -it option!
Find your stopped container id
docker ps -a
Commit the stopped container:
This command saves modified container state into a new image named user/test_image:
docker commit $CONTAINER_ID user/test_image
Start/run with a different entry point:
docker run -ti --entrypoint=sh user/test_image
Entrypoint argument description:
https://docs.docker.com/engine/reference/run/#/entrypoint-default-command-to-execute-at-runtime
Note:
Steps above just start a stopped container with the same filesystem state. That is great for a quick investigation; but environment variables, network configuration, attached volumes and other stuff is not inherited. You should specify all these arguments explicitly.
Steps to start a stopped container have been borrowed from here: (last comment) https://github.com/docker/docker/issues/18078
Edit this file (corresponding to your stopped container):
vi /var/lib/docker/containers/923...4f6/config.json
Change the "Path" parameter to point at your new command, e.g. /bin/bash. You may also set the "Args" parameter to pass arguments to the command.
Restart the docker service (note this will stop all running containers unless you first enable live-restore):
service docker restart
List your containers and make sure the command has changed:
docker ps -a
Start the container and attach to it, you should now be in your shell!
docker start -ai mad_brattain
Worked on Fedora 22 using Docker 1.7.1.
NOTE: If your shell is not interactive (e.g. you did not create the original container with -it option), you can instead change the command to "/bin/sleep 600" or "/bin/tail -f /dev/null" to give you enough time to do "docker exec -it CONTID /bin/bash" as another way of getting a shell.
NOTE2: Newer versions of docker have config.v2.json, where you will need to change either Entrypoint or Cmd (thanks user60561).
Add a check to the top of your Entrypoint script
Docker really needs to implement this as a new feature, but here's another workaround option for situations in which you have an Entrypoint that terminates after success or failure, which can make it difficult to debug.
If you don't already have an Entrypoint script, create one that runs whatever command(s) you need for your container. Then, at the top of this file, add these lines to entrypoint.sh:
# Run once, hold otherwise
if [ -f "already_ran" ]; then
echo "Already ran the Entrypoint once. Holding indefinitely for debugging."
cat
fi
touch already_ran
# Do your main things down here
To ensure that cat holds the connection, you may need to provide a TTY. I'm running the container with my Entrypoint script like so:
docker run -t --entrypoint entrypoint.sh image_name
This will cause the script to run once, creating a file that indicates it has already run (in the container's virtual filesystem). You can then restart the container to perform debugging:
docker start container_name
When you restart the container, the already_ran file will be found, causing the Entrypoint script to stall with cat (which just waits forever for input that will never come, but keeps the container alive). You can then execute a debugging bash session:
docker exec -i container_name bash
While the container is running, you can also remove already_ran and manually execute the entrypoint.sh script to rerun it, if you need to debug that way.
I took #Dmitriusan's answer and made it into an alias:
alias docker-run-prev-container='prev_container_id="$(docker ps -aq | head -n1)" && docker commit "$prev_container_id" "prev_container/$prev_container_id" && docker run -it --entrypoint=bash "prev_container/$prev_container_id"'
Add this into your ~/.bashrc aliases file, and you'll have a nifty new docker-run-prev-container alias which'll drop you into a shell in the previous container.
Helpful for debugging failed docker builds.
This is not exactly what you're asking for, but you can use docker export on a stopped container if all you want is to inspect the files.
mkdir $TARGET_DIR
docker export $CONTAINER_ID | tar -x -C $TARGET_DIR
docker-compose run --entrypoint /bin/bash cont_id_or_name
(for conven, put your env, vol mounts in the docker-compose.yml)
or use docker run and manually spec all args
It seems docker can't change entry point after a container started. But you can set a custom entry point and change the code of the entry point next time you restart it.
For example you run a container like this:
docker run --name c --entrypoint "/boot" -v "./boot":/boot $image
Here is the boot entry point:
#!/bin/bash
command_a
When you need restart c with a different command, you just change the boot script:
#!/bin/bash
command_b
And restart:
docker restart c
My Problem:
I started a container with docker run <IMAGE_NAME>
And then added some files to this container
Then I closed the container and tried to start it again withe same command as above.
But when I checked the new files, they were missing
when I run docker ps -a I could see two containers.
That means every time I was running docker run <IMAGE_NAME> command, new image was getting created
Solution:
To work on the same container you created in the first place run follow these steps
docker ps to get container of your container
docker container start <CONTAINER_ID> to start existing container
Then you can continue from where you left. e.g. docker exec -it <CONTAINER_ID> /bin/bash
You can then decide to create a new image out of it
I have found a simple command
docker start -a [container_name]
This will do the trick
Or
docker start [container_name]
then
docker exec -it [container_name] bash
I had a docker container where the MariaDB container was continuously crashing on startup because of corrupted InnoDB tables.
What I did to solve my problem was:
copy out the docker-entrypoint.sh from the container to the local file system (docker cp)
edit it to include the needed command line parameter (--innodb-force-recovery=1 in my case)
copy the edited file back into the docker container, overwriting the existing entrypoint script.
To me Docker always leaves the impression that it was created for a hobby system, it works well for that.
If something fails or doesn't work, don't expect to have a professional solution.
That said: Docker does not only NOT support such basic administrative tasks, it tries to prevent them.
Solution:
cd /var/lib/docker/overlay2/
find | grep somechangedfile
# You now can see the changed file from your container in a hexcoded folder/diff
cd hexcoded-folder/diff
Create an entrypoint.sh (make sure to backup an existing one if it's there)
cat > entrypoint.sh
#!/bin/bash
while ((1)); do sleep 1; done;
Ctrl+C
chmod +x entrypoint.sh
docker stop
docker start
You now have your docker container running an endless loop instead of the originally entry, you can exec bash into it, or do whatever you need.
When finished stop the container, remove/rename your custom entrypoint.
It seems like most of the time people are running into this while modifying a config file, which is what I did. I was trying to bypass CORS for a PHP/Apache server with a Vue SPA as my entry point. Anyway, if you know the file you horked, a simple solution that worked for me was
Copy the file you horked out of the image:
docker cp bt-php:/etc/apache2/apache2.conf .
Fix it locally
Copy it back in
docker cp apache2.conf bt-php:/etc/apache2/apache2.conf
Start your container back up
*Bonus points - Since this file is being modified, add it to your Compose or Build scripts so that when you do get it right it will be baked into the image!
Lots of discussion surrounding this so I thought I would add one more which I did not immediately see listed above:
If the full path to the entrypoint for the container is known (or discoverable via inspection) it can be copied in and out of the stopped container using 'docker cp'. This means you can copy the original out of the container, edit a copy of it to start a bash shell (or a long sleep timer) instead of whatever it was doing, and then restart the container. The running container can now be further edited with the bash shell to correct any problems. When finished editing another docker cp of the original entrypoint back into the container and a re-restart should do the trick.
I have used this once to correct a 'quick fix' that I butterfingered and was no longer able to run the container with the normal entrypoint until it was corrected.
I also agree there should be a better way to do this via docker: Maybe an option to 'docker restart' that allows an alternate entrypoint? Hey, maybe that already works with '--entrypoint'? Not sure, didn't try it, left as exercise for reader, let me know if it works. :)

How can I remove the Cmd entry from a Docker image configuration?

After modifying a Docker image "from within" by running
docker run -it --user root <image_name> bash
…and commiting the changes, the image's config now contains the bash command in Container.Cmd and ContainerConfig.Cmd.
I have seen that docker commit at least used to have a -run option which could let me modify the configuration, but I haven't found documentation for it.
How can I remove Cmd from the configuration to make entrypoint active again (and what should I have done to avoid the problem)?
(Workaround) You could run your new image with docker run --entrypoint to set a new entrypoint, then commit that new container as a new image. It should keep the entrypoint you started it with.
Alternatively you could manually edit the JSON metadata for the image, but I wouldn't recommend that as a production hack -- it is always better to go through the APIs for that.

Workaround to docker run "--env-file" supplied file not being evaluated as expected

My current setup for running a docker container is on the lines of this:
I've got a main.env file:
# Main
export PRIVATE_IP=\`echo localhost\`
export MONGODB_HOST="$PRIVATE_IP"
export MONGODB_URL="mongodb://$MONGODB_HOST:27017/development"
In my service file (upstart), I source this file . /path/to/main.env
I then call docker run with multiple -e for each of the environment variables I want inside of the container. In this case I would call something like: docker run -e MONGODB_URL=$MONGODB_URL ubuntu bash
I would then expect MONGODB_URL inside of the container to equal mongodb://localhost:27017/development. Notice that in reality echo localhost is replaced by a curl to amazon's api for an actual PRIVATE_IP.
This becomes a bit unwieldy when you start having more and more environment variables you need to give your container. There is a fine point to see here which is that the environment variables need to be resolved at run time, such as with a call to curl or by referring to other env variables.
The solution I was hoping to use is:
calling docker run with an --env-file parameter such as this:
# Main
PRIVATE_IP=\`echo localhost\`
MONGODB_HOST="$PRIVATE_IP"
MONGODB_URL="mongodb://$MONGODB_HOST:27017/development"
Then my docker run command would be significantly shortened to docker run --env-file=/path/to/main.env ubuntu bash (keep in mind usually I've got around 12-15 environment variables.
This is where I hit my problem which is that inside the container none of the variables resolve as expected. Instead I end up with:
PRIVATE_IP=`echo localhost`
MONGODB_HOST="$PRIVATE_IP"
MONGODB_URL="mongodb://$MONGODB_HOST:27017/development"
I could circumvent this by doing the following:
Sourcing the main.env file.
Creating a file containing just the names of the variables I want (meaning docker would search for them in the environment).
Then calling docker run with this file as an argument to --env-file. This would work but would mean I would need to maintain two files instead of one, and really wouldn't be that big of an improvement of the current situation.
What I would prefer is to have the variables resolve as expected.
The closest question to mine that I could find is:
12factor config approach with Docker
Ceate a .env file
example: test=123 val=Guru
Execute command
docker run -it --env-file=.env bash
Inside the bash verify using
echo $test (should print 123)
Both --env and --env-file setup variables as is and do not replace nested variables.
Solomon Hykes talks about configuring containers at run time and the the various approaches. The one that should work for you is to volume mounting the main.env from host into the container and sourcing it.
So I just faced this issue as well, what solved it for me was I specified the --env-file or -e KEY=VAL before the name of the container image. For example
Broken:
docker run my-image --env-file .env
Fixed:
docker run --env-file .env my-image
creating an ENV file that is nothing more than key/value pairs can be processed in normal shell commands and appended to the environment. Look at the bash -a pragma.
What you can do is create a startup script that can be run when the container starts. So if your current docker file looks something like this
From ...
...
CMD command
Change it to
From ...
...
ADD start.sh start.sh
CMD ["start.sh"]
In your start.sh script do the following:
export PRIVATE_IP=\`echo localhost\`
export MONGODB_HOST="$PRIVATE_IP"
export MONGODB_URL="mongodb://$MONGODB_HOST:27017/development"
command
I had a very similar problem to this. If I passed the contents of the env file to docker as separate -e directives then everything ran fine however if I passed the file using --env-file the container failed to run properly.
Turns out there were some spurious line endings in the file (I had copied from windows and ran docker in Ubuntu). When I removed them the container ran the same with --env or --env-file.
I had this issue when using docker run in a separate run script run.sh file, since I wanted the credentials ADMIN_USER and ADMIN_PASSWORD to be accessible in the container, but not show up in the command.
Following the other answers and passing a separate environment file with --env or --env-file didn't work for my image (though it worked for the Bash image). What worked was creating a separate env file...
# env.list
ADMIN_USER='username'
ADMIN_PASSWORD='password'
...and sourcing it in the run script when launching the container:
# run.sh
source env.list
docker run -d \
-e ADMIN_USER=$INFLUXDB_ADMIN_USER \
-e ADMIN_PASSWORD=$INFLUXDB_ADMIN_PASSWORD \
image_repo/name:tag

Resources