Running a command in a Docker container with variables - bash

I am using a docker-compose type of scenario.  I would like to back up the database for partkeepr on a nightly basis.  I can get a bash shell by doing a docker exec -it docker-partkeer_database_1 bash into the container and run the mysqldump command just fine but I can't run it successfully as a docker exec type of function. 
I run docker exec -it docker-partkeepr_database_1 bash -c mysqldump --databases partkeepr -upartkeepr -pUSERPASSWORD  > /var/lib/mysql/backup/partkeeprsql.$(date +%Y-%m-%d-%H.%M.%S).sql.  
That date part on the end works just fine when I already have gotten in with a bash shell in the container but not outside of it. I can run the command as written without the date part just fine but I need the date so I can have multiple backups.
The system errors with -bash: /var/lib/mysql/backup/partkeeprsql.$(date +%Y-%m-%d-%H.%M.%S).sql: No such file or directory.  
Have any ideas? 

I found out the answer to my question. I didn't wrap the command after the bash -c in ""'s. Once I ran the command below it worked like a charm. I just wanted everyone to know the answer that I figured out.
docker exec -it docker-partkeepr_database_1 bash -c "mysqldump --databases partkeepr -upartkeepr -
pUSERPASSWORD > /var/lib/mysql/backup/partkeeprsql.$(date +%Y-%m-%d-%H.%M.%S).sql"

Related

Crontab can't execute script directly in container environment

I present to you the following dilemma I execute my script manually and it works well, see next line for example:
docker exec -ti backup_subversion sh -c "/tmp/my_script.sh"
But when I attempt to schedule the process this line is just skipped.
I have tried to execute just a touch command and it too is ignored.
I have tried to execute as root, same problem.
I have tried to execute in another docker environment: same problem.
My OS is Centos 7.
In this script for example the bug part who will crash :
#!/bin/bash
# Create a container.
docker run -d --name=backup_subversion \
-v /subversion/dump:/var/dump \
--net my_network my_server.domaine.com/subversion/billy:1.9
# I copy a script.
docker cp tools_subversion_dump.sh backup_subversion:/tmp
# This line is ignore since crontab exec.
docker exec -ti backup_subversion sh -c "/tmp/tools_subversion_dump.sh"
Thank you in advance for your answers because it's a mystery to me.
It's probably because you used the -it options that only apply to an interactive shell rather then a pseudo one like the one used in scripts as referenced in the question

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.

use docker exec in bash script

I have a bash script that is supposed to execute other bash scripts using "docker exec" which are installed in different docker containers. Although each command works correctly when started manually, the script stops after the execution of first docker exec command.
Example:
#!/bin/bash
...
docker exec -it mysql_container /scripts/import_database.sh ## Scripts stops here...
docker exec -it web_container /scripts/copy_doc_root.sh
...
What am I missing? ;)
Thanks for your help!
David
Use docker exec -d since you neither want a terminal nor an interactive session.

Automatically enter only running docker container

In the cloud, I have multiple instances, each running a container with a different random name, e.g.:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5dc97950d924 aws_beanstalk/my-app:latest "/bin/sh -c 'python 3 hours ago Up 3 hours 80/tcp, 5000/tcp, 8080/tcp jolly_galileo
To enter them, I type:
sudo docker exec -it jolly_galileo /bin/bash
Is there a command or can you write a bash script to automatically execute the exec to enter the correct container?
"the correct container"?
To determine what is the "correct" container, your bash script would still need either the id or the name of that container.
For example, I have a function in my .bashrc:
deb() { docker exec -u git -it $1 bash; }
That way, I would type:
deb jolly_galileo
(it uses the account git, but you don't have to)
Here's my final solution. It edits the instance's .bashrc if it hasn't been edited yet, prints out docker ps, defines the dock function, and enters the container. A user can then type "exit" if they want to access the raw instances, and "exit" again to quit ssh.
commands:
bashrc:
command: if ! grep -Fxq "sudo docker ps" /home/ec2-user/.bashrc; then echo -e "dock() { sudo docker exec -it $(sudo docker ps -lq) bash; } \nsudo docker ps\ndock" >> /home/ec2-user/.bashrc; fi
As VonC indicated, usually you have to make some shell scripting of your own if you find yourself doing something repetitive. I made a tool myself here which works if you have Bash 4+.
Install
wget -qO- https://raw.githubusercontent.com/Pithikos/dockerint/master/docker_autoenter >> ~/.bashrc
Then you can enter a container by simply typing the first letters of the container.
$> docker ps
CONTAINER ID IMAGE ..
807b1e7eab7e ubuntu ..
18e953015fa9 ubuntu ..
19bd96389d54 ubuntu ..
$> 18
root#18e953015fa9:/#
This works by taking advantage of the function command_not_found_handle introduced in Bash 4. If a command is not found, the script will try and see if what you typed is a container and if it is, it will run docker exec <container> bash.

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