How to start multiple processes for a Docker container in a bash script - bash

I found very strange behaviour when I build and run docker container. I would like to have container with cassandra and ssh.
In my Dockerfile I've got:
RUN echo "deb http://www.apache.org/dist/cassandra/debian 20x main" | sudo tee -a /etc/apt/sources.list
RUN echo "deb-src http://www.apache.org/dist/cassandra/debian 20x main" | sudo tee -a /etc/apt/sources.list
RUN gpg --keyserver pgp.mit.edu --recv-keys 4BD736A82B5C1B00
RUN apt-key add ~/.gnupg/pubring.gpg
RUN apt-get update
RUN apt-get -y install cassandra
And then for ssh
RUN apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo '{{ docker_ssh_user }}:{{docker_ssh_password}}' | chpasswd
EXPOSE 22
And I added start script to run everything I want:
USER root
ADD start start
RUN chmod 777 start
CMD ["sh" ,"start"]
And here comes problem. When I have start like this below:
#!/bin/bash
/usr/sbin/sshd -D
/usr/sbin/cassandra -f
SSH is working well. I can do ssh root#172.17.0.x. After I log in container I try to run cqlsh to ensure that cassandra is working. But cassandra is not started for some reason and I can't access cqlsh. I've also checked /var/log/cassandra/ but it was empty.
In second scenario I change my start script to this:
#!/bin/bash
/usr/sbin/sshd -D & /usr/sbin/cassandra/ -f
And I again try to connect ssh root#172.17.0.x and then when I run cqlsh inside container I have connection to cqlsh.
So I was thinking that ampersand & is doing some voodoo that all works well ?
Why I can't run bash staring script with one command below another?
Or I'm missing something else??
Thanks for reading && helping.

Thanks to my friend linux guru we found the reason of error.
/usr/sbin/sshd -D means that -D : When this option is specified, sshd will not detach and does not become a deamon. This allows easy monitoring of sshd
So in the first script sshd -D was blocking next command to run.
In second script I've got & which let sshd -D go background and then cassandra could start.
Finally I've got this version of script:
#!/bin/bash
/usr/sbin/sshd
/usr/sbin/cassandra -f

Related

How to catch SIGTERM properly in Docker?

I have a docker container created by the following Dockerfile:
ARG TAG=latest
FROM continuumio/miniconda3:${TAG}
ARG GROUP_ID=1000
ARG USER_ID=1000
ARG ORG=my-org
ARG USERNAME=user
ARG REPO=none
ARG COMMIT=none
ARG BRANCH=none
ARG MAKEAPI=True
RUN addgroup --gid $GROUP_ID $USERNAME
RUN adduser --uid $USER_ID --disabled-password --gecos "" $USERNAME --ingroup $USERNAME
COPY . /api_maker
RUN /opt/conda/bin/pip install pyyaml psutil packaging
RUN apt install -y openssh-client git
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
ENV GIT_SSH_COMMAND="ssh -i /run/secrets/thekey"
RUN --mount=type=secret,id=thekey git clone git#github.com:$ORG/$REPO.git /repo
RUN /opt/conda/bin/python3 /api_maker/repo_setup.py $BRANCH $COMMIT
RUN /repo/root_script.sh
RUN chown -R $USERNAME:$USERNAME /api_maker
RUN chown -R $USERNAME:$USERNAME /repo
RUN mkdir -p /data
RUN chown -R $USERNAME:$USERNAME /data
RUN mkdir -p /working
RUN chown -R $USERNAME:$USERNAME /working
RUN mkdir -p /opt/conda/pkgs
RUN mkdir -p /opt/conda/envs
RUN chmod -R 777 /opt/conda
RUN touch /opt/conda/pkgs/urls.txt
USER $USERNAME
RUN /api_maker/user_env_setup.sh $MAKEAPI
CMD /repo/run_api.sh $#;
with the following run_api.sh script:
#!/bin/bash
cd /repo
PROCESSES=${1:-9}
LOCAL_DOCKER_PORT=${2:-7001}
exec /opt/conda/envs/environment/bin/gunicorn --bind 0.0.0.0:$LOCAL_DOCKER_PORT --workers=$PROCESSES restful_api:app
My app contains some signal handling. If I manually send SIGTERM to gunicorn (either the worker or the parent process) from inside the container, my signal handling works properly. However, it does not work right when I run docker stop on the container. How can I make my shell script properly forward the SIGTERM it is supposedly receiving?
You need to make sure the main container process is your actual application, and not a shell wrapper.
As you have the CMD currently, a shell invokes it. The argument list $# will always be empty. The shell parses /repo/run_api.sh and sees that it's followed by a semicolon, so it might need to do something else. So even though your script correctly ends with exec gunicorn ... to hand off control directly to the other process, it's still running underneath a shell, and when you docker stop the container, it goes to the shell wrapper.
The easiest way to avoid this shell is to use an exec form CMD:
CMD ["/repo/run_api.sh"]
This will cause your script to run directly, without having a /bin/sh -c wrapper invoking it, and when the script eventually exec another process, that process becomes the main process and will receive the docker stop signal.

How to run two docker containers from cron?

I am trying to set up crontab to run two docker containers on system startup/reboot. The line I use to do this after entering the command crontab -e is:
#reboot sh folder_b/run_docker_containers.bash
The script run_docker_containers.bash has the following contents:
#!/bin/bash
# Run containers based on setup_image and main_image
sudo bash /home/user/folder_a/run_setup_docker_container.bash
sudo bash /home/user/folder_b/run_main_docker_container.bash
The scripts run_setup_docker_container.bash and run_main_docker_container.bash both have the following contents (where docker_image is setup_image and main_image, respectively):
#!/bin/bash
/snap/bin/docker run \
--rm \
--detach \
--privileged \
--net=host \
--device /dev/bus/usb \
docker_image:latest \
/bin/bash -c\
"
*SOME COMMANDS*
"
export containerId=$(/snap/bin/docker ps -l -q)
However, the containers are not run when the script is executed on reboot. I prove it finds the script folder_b/run_docker_containers.bash by adding the following code to it and seeing that the new file has been created after reboot.
touch proof_that_crontab_has_done_something.txt
It seems that crontab cannot find the scripts run_setup_docker_container.bash and run_main_docker_container.bash. Any ideas where I'm going wrong?
If you want to execute a shellscript with sudo rights I would recommend using the sudo crontab.
sudo crontab -e
Your personal cronjob should not be able to start a shell with sudo rights. Unless you do some weird modifications.
Use the absolute path
#reboot /...../folder_b/run_docker_containers.bash

bash script not moving onto next command

I have a simple bash script as follows:
#!/bin/bash
gunicorn --bind 0.0.0.0:5000 --chdir server/ run:app -w 2
supervisord -c /usr/src/server/supervisord.conf -n
The script is supposed to launch the gunicorn service and then start supervisor. However when the script is called, only the gunciron service is started and not the supervisor service.
The script is being called as follows from a Dockerfile:
FROM python:3.8.1
RUN apt-get update && \
apt-get -y install netcat && \
apt-get clean
RUN apt-get install -y libpq-dev
RUN apt-get install -y redis-server
COPY . usr/src/server
WORKDIR /usr/src
RUN pip install -r server/requirements.txt
RUN chmod +x /usr/src/server/start.sh
CMD ["/usr/src/server/start.sh"]
I have tried using the && separator between the 2 commands as well, but that doesn't seem to make a difference.
The bash script will move on to the next command when the first command has finished running. supervisord will start when gunicorn exits.
To run Gunicorn in the background, pass the --daemon option.
#!/bin/bash
gunicorn --bind 0.0.0.0:5000 --chdir server/ run:app -w 2 --daemon
supervisord -c /usr/src/server/supervisord.conf -n
However, this doesn't make much sense to me. Since you're running Supervisor, why aren't you running Gunicorn from Supervisor? Starting daemons is Supervisor's job.

Cant't build Jenkins latest within Docker

******** UPDATE *********
Bash script has no errors, checked with https://www.shellcheck.net/
Adding to the Dockerfilethe line
RUN tty | sed -e "s:/dev/::"
Outputs:
No tty
Next line on Dockerfile always fails:
ENTRYPOINT ["/usr/local/bin/jenkins.sh"]
I leave an image in order to clarify. In short, I think I need to attach a tty in some way to the batch script, but dunno how to do it.
Thanks
------------------- OLD CONTENT -------------------
I need to update a Jenkins image to 2.138.2. An excerpt of the original Dockerfile is as follows:
FROM openjdk:8-jdk
RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*
# ...
# Use tini as subreaper in Docker container to adopt zombie processes
COPY tini_pub.gpg ${JENKINS_HOME}/tini_pub.gpg
RUN curl -fsSL https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-$(dpkg --print-architecture) -o /sbin/tini \
&& curl -fsSL https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-$(dpkg --print-architecture).asc -o /sbin/tini.asc \
&& gpg --import ${JENKINS_HOME}/tini_pub.gpg \
&& gpg --verify /sbin/tini.asc \
&& rm -rf /sbin/tini.asc /root/.gnupg \
# ...
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/jenkins.sh"]
Using this Dockerfile FAILS due to gpg --import statement now needs to be fixed using --no-tty option. So that line remains as follows:
&& gpg --no-tty --import ${JENKINS_HOME}/tini_pub.gpg \
That's not fine since the execution of jenkins.sh now fails in several ways. The code of the script starts as follows:
#! /bin/bash -e
: "${JENKINS_WAR:="/usr/share/jenkins/jenkins.sh
This script is called from the Dockerfile in this line:
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/jenkins.sh"]
But now fails with several errors and seems to be impossible to process the file, nor removing the shebang line, nor removing the '-' or the '-e' option. The rest of the file is not processed fine if we change bash to other shell (not odd) nor removing the -e option (if I do that, the entrypoint does not find the jenkins.sh script).
Sumarizing, I've needed to remove a tty from gpg but doing that, I've lost access to bash scripting.
I've checked about the applied workaround, the workaround is described here ( (if I'm right, case is number 8, gpg might write to the tty at some point):
https://lists.gnupg.org/pipermail/gnupg-users/2017-April/058162.html
Is there any way to attach a tty to the entrypointor having any settings in the script in order to allow this work fine?
Thanks.
Finally runned on a Linux VM and no problems. Running it on Windows is the problem.

Need to run chromium as normal user from root script

I have a kiosk that shuts down every day using rtcwake, and this uses root user. I've used && to execute the boot script after rtcwake completes, however it then starts the browser as root causing problems.
This is the command I use:
echo debian | sudo -S rtcwake -m mem -u -t $(date +%s -d '3 days 7:45') && sudo -u debian -i bash $HOME/kiosk/bin/startup.sh &.
The sudo command does work to some extent. It calls the debian user, and executes the correct script, however, it still screws up my chromium preferences.
Here is the startup script:
echo debian | sudo -S hwclock -w
export HOME=/home/debian
#log boot time
echo "Booting at" $(date) >> $HOME/kiosk/bin/logs/boot.log
#echo debian | sudo -S service connman restart
echo debian | sudo -S at 15:30 -f $HOME/kiosk/bin/shutdown.sh
crontab -u debian crontab.txt
bash $HOME/git.sh
#sudo -i -u debian
#start kiosk
export DISPLAY=:0
chromium-browser --kiosk --disable-gpu
http://localhost/kiosk/Client/main.html &
#update ip
bash /home/debian/git.sh &
I'm wondering what could be causing chrome to be executed as root. I have no idea what is going wrong.
If you execute a command with sudo it will not change environment variables like $HOME. Since per user settings are stored in $HOME, this affects the executed program if it needs such configuration files. Check this for example:
sudo -u debian bash -c 'echo $HOME'
It will print the home folder of the calling user, not the home folder of the user specified trough -u. The sudo command supports the -H command line option to handle this, however if it works depends on the security police in use.
As a solution you can use the su command instead of sudo in this case:
... && su debian -c chromium
Since su itself is executed by root you won't be asked for the password.
You must enter a password to log into a new user shell.
The command needs to be modified as follows:
echo debian | sudo -S rtcwake -m mem -u -t $(date +%s -d '3 days 7:45') && echo debian | sudo -S -u debian -i bash $HOME/kiosk/bin/startup.sh &
This avoids needing a password to log in as normal Debian user, and executes the script.

Resources