How to execute script that opens interactive and continues inside container - bash

Hello i want to create a script that starts an interactive session with a docker container , and then reads a file from that container's filesystem (and maybe more).
How can i can make the commands from a bash script execute inside that session ?
myscript.sh
docker exec -it server0 bash
cat dock.txt --this file is in the container filesystem and i want to see it
//do more stuff in the filesystem

Option 1
You can add multiple actions in:
docker exec server0 /bin/sh -c "cmd1;cmd2;...;cmdn"
Option 2
You add your script from local folder with volume (-v) parameter and then execute it inside docker:
docker exec -it -v ./myscript.sh:/myscript.sh server0 /myscript.sh
myscript.sh
cat dock.txt
ls -la
//do more stuff in the filesystem
//do more stuff in the filesystem
start.sh
docker exec -it -v ./myscript.sh:/myscript.sh server0 /myscript.sh
Start script locally:
./start.sh

Related

Entering text into a docker container via ssh from bash file

What I am trying to do is setup a local development database and to prevent everyone having to go through all the steps I thought it would be useful to create a script.
What I have below stop once it is in the terminal, which looks like:
output
./dbSetup.sh
hash of container 0d1b182aa6f1
/ #
At which point I have to manually enter exit.
script
#!/bin/bash
command=$(docker ps | grep personal)
set $command
echo "hash of container ${1}"
docker exec -it ${1} sh
Is there a way I can inject a command via a script into a dockers container terminal?
In order to execute command inside a container, you can use something like this:
docker exec -ti my_container sh -c "echo a && echo b"
More information available at: https://docs.docker.com/engine/reference/commandline/exec/
Your script finds a running Docker container and opens a shell to it. The "-it" makes it interactive and allocates a tty which is why it continues to wait for input, e.g. "exit". If the plan is to execute some commands to initialize a local development database, I'd recommend looking at building an image with a Dockerfile instead. i.e. Once you figure out the commands to run, they would become RUN commands and the container after docker run would expose a local development database.
If you really want some commands to run within the shell after it is started and maintain the session, depending on the base image, you might be able to mount a bash profile that has the required commands, e.g. -v db_profile:/etc/profile.d where db_profile is a folder with the shell scripts you want to run. To get them to run you'd exec sh -l to have the login startup scripts to run.

docker exec bash behaves weirdly

When I do:
docker exec -ti myContainer /bin/bash
I have a new bash terminal on running container myContainer.
Now when I write
docker exec -ti lescompanions /bin/bash -c "echo youpi"
docker only outputs youpi and returns with no interactive terminal created. I was actually expecting docker to create the terminal and run echo youpi within the newly created terminal.
Where am I wrong?
---- EDIT ----
Now how shall I run echo youpi in the new terminal on the existing container and not have the terminal return to the host after the execution of echo youpi?
docker exec takes a command to run a process inside the container while the -it flag attaches an interactive session against that process.
Your session will only live as long as the command given to exec
As others have mentioned the command /bin/bash -c "echo youpi" simply uses bash to run the command echo "echo youpi" and terminates, hence your terminal session terminates also.
You are not doing anything wrong, it's just how bash works. I've checked it on my Ubuntu (without Docker):
$ /bin/bash
(no output, bash instance running)
$ /bin/bash -c "echo youpi"
youpi
(bash finished)
echo youpi is a command that is run inside the container. The echo command prints the arguments given to it, which is youpi in this case, and that is also what you see.

Dockerfile CMD instruction will exit the container just after running it

I want to setup some configuration when my container starts, for this I am using shell scripts. But my container will exits as soon as my scripts ends, I have tried with -d flag / detached mode but It will never run in detached mode.
Below is my Dockerfile
FROM ubuntu:14.04
ADD shell.sh /usr/local/bin/shell.sh
RUN chmod 777 /usr/local/bin/shell.sh
CMD /usr/local/bin/shell.sh
Below is my shell script
#!/bin/bash
echo Hello-docker
Run without any flag
docker run hello-docker
This will print 'Hello-docker' on my console and exits
Run with -itd flags
docker run -itd hello-docker
and as below my console output, This time also will exits soon. :(
The difference I saw is in COMMAND section when I run other images command section will shows "/bin/bash" and will continue in detached mode.
And when I run my image in container with shell script COMMAND section will show "/bin/sh -c /usr/loca", and Exit.
I want to run container till I not stop it manually.
EDIT:
After adding ENTRYPOINT instruction in Dockerfile, this will not execute my shell script :(
FROM ubuntu:14.04
ADD shell.sh /usr/local/bin/shell.sh
RUN chmod 777 /usr/local/bin/shell.sh
CMD /usr/local/bin/shell.sh
ENTRYPOINT /bin/bash
As per docker documentation here
CMD will be overridden when running the container with alternative arguments, so If I run docker image with some arguments as below, will not execute CMD instructions. :(
sudo docker run -it --entrypoint=/bin/bash <imagename>
A docker container will run as long as the CMD from your Dockerfile takes.
In your case your CMD consists of a shell script containing a single echo. So the container will exit after completing the echo.
You can override CMD, for example:
sudo docker run -it --entrypoint=/bin/bash <imagename>
This will start an interactive shell in your container instead of executing your CMD. Your container will exit as soon as you exit that shell.
If you want your container to remain active, you have to ensure that your CMD keeps running. For instance, by adding the line while true; do sleep 1; done to your shell.sh file, your container will print your hello message and then do nothing any more until you stop it (using docker stop in another terminal).
You can open a shell in the running container using docker exec -it <containername> bash. If you then execute command ps ax, it will show you that your shell.sh is still running inside the container.
Finally with some experiments I got my best result as below
There is nothing wrong with my Dockerfile as below it's correct.
FROM ubuntu:14.04
ADD shell.sh /usr/local/bin/shell.sh
RUN chmod 777 /usr/local/bin/shell.sh
CMD /usr/local/bin/shell.sh
What I do to get expected result is, I just add one more command(/bin/bash) in my shell script file as below and vola everything works in my best way.
#!/bin/bash
echo “Hello-docker” > /usr/hello.txt
/bin/bash
You can also modify your first Dockerfile, replacing
CMD /usr/local/bin/shell.sh
by
CMD /usr/local/bin/shell.sh ; sleep infinity
That way, your script does not terminate, and your container stays running.
CMD bash -C '/path/to/start.sh';'bash'
Try
CMD /bin/bash -c 'MY_COMMAND_OR_SHELL_SCRIPT; /bin/bash'
Trying an explanation here to the answer of #lanni654321. sh shell is standard in Dockerfile. You must call bash shell to start bash with .bashrc, many commands also need RUN /bin/bash -c '...' in the same way as in CMD above, since sh shell is often not enough. If you add 'bash' in the end of CMD, the container will not exit because the image was committed with something that is still open.
See “/bin/sh: 1: MY_COMMAND: not found” for an error caused by sh and solved by bash.
I think that you will usually not need this. You can just use RUN /bin/bash -c '...', in my case, this could do anything that can be done in a base image before you go into varying details in docker-compose to start the containers.
But that is all not needed if you need to just have a container running without exiting. Just
docker run -dit --name MY_CONTAINER MY_IMAGE:latest
and then
docker exec -it MY_CONTAINER /bin/bash
and you should be in the bash of the container, and it should not exit.
Or if the exit happens during docker-compose, use
command: bash -c "MY_COMMAND --wait"
At your start shell append a line code:
tail -f /dev/null or /bin/bash
to make sure you shell done and suspend a process in system so that docker container not shutdown.Don't forget to give "chmod +x" access to start.sh.
there is demo:
#!/bin/bash
cp /root/supervisor/${RUN_SERVICE}.ini /etc/supervisor/conf.d/
sleep 1
service supervisor start
/bin/bash

How can I set the current working directory for docker exec with an internal bash shell?

I have a developer docker image based on ubuntu:14.04 that I use to develop apps for Ubuntu 14.04. I start this image when the machine boots with docker start image-name
My home directory was bind mounted with --volumes when initially created.
To enter the image I have an alias defined in .bash_aliases
alias d_enter="docker exec -ti ub1404-dev /bin/bash"
So to enter the image I just type d_enter
But I often forget to run d_enter after entering a long path and would like d_enter to switch to that internal directory automatically.
The following doesn't work.
docker exec -ti ub1404-dev /bin/bash <(echo ". ~/.bashrc && cd $(pwd)")
Is there another way I could achieve the desired result?
For example, if my current working directory is: /home/matt/dev/somepath/blabla
And I type d_enter, my current working directory currently becomes: /home/matt what I want to do for current directory after exec is be /home/matt/dev/somepath/blabla
From API 1.35+ you can use the -w (--workdir) option:
docker exec -w /my/dir container_name command
https://docs.docker.com/engine/reference/commandline/exec/
You can achieve it with:
docker exec -it containerName sh -c "cd /var/www && /bin/bash"
When building an image, one can specify the WORKDIR variable in Dockerfile:
WORKDIR /var/www/html
Definitely a hack but you could do something like making d_enter a shell function (could stay an alias but this is easier to maintain):
d_enter() {
pwd > ~/.docker_initial_pwd
docker exec -ti ub1404-dev /bin/bash
}
And then in the container in your user account's .bashrc, add something like:
if [[ -f "${HOME}/.docker_initial_pwd ]]; then
cd $(cat "${HOME}/.docker_initial_pwd")
fi

Running a script inside a docker container using shell script

I am trying to create a shell script for setting up a docker container. My script file looks like:
#!bin/bash
docker run -t -i -p 5902:5902 --name "mycontainer" --privileged myImage:new /bin/bash
Running this script file will run the container in a newly invoked bash.
Now I need to run a script file (test.sh)which is already inside container from the above given shell script.(eg: cd /path/to/test.sh && ./test.sh)
How to do that?
You can run a command in a running container using docker exec [OPTIONS] CONTAINER COMMAND [ARG...]:
docker exec mycontainer /path/to/test.sh
And to run from a bash session:
docker exec -it mycontainer /bin/bash
From there you can run your script.
Assuming that your docker container is up and running, you can run commands as:
docker exec mycontainer /bin/sh -c "cmd1;cmd2;...;cmdn"
I was searching an answer for this same question and found ENTRYPOINT in Dockerfile solution for me.
Dockerfile
...
ENTRYPOINT /my-script.sh ; /my-script2.sh ; /bin/bash
Now the scripts are executed when I start the container and I get the bash prompt after the scripts has been executed.
In case you don't want (or have) a running container, you can call your script directly with the run command.
Remove the iterative tty -i -t arguments and use this:
$ docker run ubuntu:bionic /bin/bash /path/to/script.sh
This will (didn't test) also work for other scripts:
$ docker run ubuntu:bionic /usr/bin/python /path/to/script.py
This command worked for me
cat local_file.sh | docker exec -i container_name bash
You could also mount a local directory into your docker image and source the script in your .bashrc. Don't forget the script has to consist of functions unless you want it to execute on every new shell. (This is outdated see the update notice.)
I'm using this solution to be able to update the script outside of the docker instance. This way I don't have to rerun the image if changes occur, I just open a new shell. (Got rid of reopening a shell - see the update notice)
Here is how you bind your current directory:
docker run -it -v $PWD:/scripts $my_docker_build /bin/bash
Now your current directory is bound to /scripts of your docker instance.
(Outdated)
To save your .bashrc changes commit your working image with this command:
docker commit $container_id $my_docker_build
Update
To solve the issue to open up a new shell for every change I now do the following:
In the dockerfile itself I add RUN echo "/scripts/bashrc" > /root/.bashrc". Inside zshrc I export the scripts directory to the path. The scripts directory now contains multiple files instead of one. Now I can directly call all scripts without having open a sub shell on every change.
BTW you can define the history file outside of your container too. This way it's not necessary to commit on a bash change anymore.
Thomio's answer is helpful but it expects the script to exist inside the image. If you have a one-of script that you want to run/test inside a container (from command-line or to be useful in a script), then you can use
$ docker run ubuntu:bionic /bin/bash -c '
echo "Hello there"
echo "this could be a long script"
'
Have a look at entry points too. You will be able to use multiple CMD
https://docs.docker.com/engine/reference/builder/#/entrypoint
If you want to run the same command on multiple instances you can do this :
for i in c1 dm1 dm2 ds1 ds2 gtm_m gtm_sl; do docker exec -it $i /bin/bash -c "service sshd start"; done
This is old, and I don't have enough reputation points to comment. Still, I guess it is worth sharing how one can generalize Marvin's idea to allow parameters.
docker exec -i mycontainer bash -s arg1 arg2 arg3 < mylocal.sh

Resources