Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I run script automatically after Docker container startup

I'm using Search Guard plugin to secure an elasticsearch cluster composed of multiple nodes. Here is my Dockerfile:

#!/bin/sh
FROM docker.elastic.co/elasticsearch/elasticsearch:5.6.3

USER root

# Install search guard
RUN bin/elasticsearch-plugin install --batch com.floragunn:search-guard-5:5.6.3-16 \
    && chmod +x \
        plugins/search-guard-5/tools/hash.sh \
        plugins/search-guard-5/tools/sgadmin.sh \
        bin/init_sg.sh \
    && chown -R elasticsearch:elasticsearch /usr/share/elasticsearch

USER elasticsearch

To initialize SearchGuard (create internal users and assign roles). I need to run the script init_sg.sh after the container startup. Here is the problem: Unless elasticsearch is running, the script will not initialize any security index.

The script's content is :

sleep 10
plugins/search-guard-5/tools/sgadmin.sh -cd config/ -ts config/truststore.jks -ks config/kirk-keystore.jks -nhnv -icl

Now, I just run the script manually after the container startup but since I'm running it on Kubernetes.. Pods may get killed or fail and get recreated automatically for some reason. In this case, the plugin have to be initialized automatically after the container startup!

So how to accomplish this? Any help or hint would be really appreciated.

like image 363
PhiloJunkie Avatar asked Dec 06 '17 10:12

PhiloJunkie


People also ask

Does docker run automatically pull?

Using docker run to get the image We could have skipped the docker pull step; if you use the docker run command and you don't already have a copy of the Docker image, Docker will automatically pull the image first and then run it.

How do you automate a docker build?

From the Repositories page, click into a repository, and click the Builds tab. Click Configure automated builds to edit the repository's build settings. In the Build Rules section, locate the branch or tag you no longer want to automatically build. Click the autobuild toggle next to the configuration line.

How do I start a docker container automatically?

Start containers automatically. Docker provides restart policies to control whether your containers start automatically when they exit, or when Docker restarts. Restart policies ensure that linked containers are started in the correct order. Docker recommends that you use restart policies, and avoid using process managers to start containers.

How do I run a script from a dockerfile?

You basically put the script in your GitHub repository and then put commands like this at the end of the Dockerfile to install and run it. RUN chmod +x /tmp/install.sh && /tmp/install.sh && rm /tmp/install.sh The above copies the script install.sh into the docker, runs it and then deletes it.

What is the --restart policy for Docker containers?

Restart Policies Using the --restart flag on Docker run you can specify a restart policy for how a container should or should not be restarted on exit. no - Do not restart the container when it exits. on-failure - Restart the container only if it exits with a non zero exit status.

Can I use Supervisord to auto-start Docker containers?

I've used supervisord in the past to auto start web apps. But that doesn't feel like the right thing for Docker. Apparently, the current method to auto-start Docker containers ( from Docker 1.2) is to use restart policies.


5 Answers

The image itself has an entrypoint ENTRYPOINT ["/run/entrypoint.sh"] specified in the Dockerfile. You can replace it by your own script. So for example create a new script, mount it and first call /run/entrypoint.sh and then wait for start of elasticsearch before running your init_sg.sh.

like image 146
Jonathan Lechner Avatar answered Oct 08 '22 04:10

Jonathan Lechner


Not sure this will solves your problem, but its worth check my repo'sDockerfile

I have created a simple run.sh file copied to docker image and in the Dockerfile I wrote CMD ["run.sh"]. In the same way define whatever you want in run.sh and write CMD ["run.sh"]. You can find another example like below

Dockerfile

FROM java:8

RUN apt-get update && apt-get install stress-ng -y 
ADD target/restapp.jar /restapp.jar 
COPY dockerrun.sh /usr/local/bin/dockerrun.sh 
RUN chmod +x /usr/local/bin/dockerrun.sh 
CMD ["dockerrun.sh"]

dockerrun.sh

#!/bin/sh
java -Dserver.port=8095 -jar /restapp.jar &
hostname="hostname: `hostname`"
nohup stress-ng --vm 4 &
while true; do
  sleep 1000
done
like image 21
Veerendra Avatar answered Oct 08 '22 04:10

Veerendra


I was trying to solve the exact problem. Here's the approach that worked for me.

  1. Create a separate shell script that checks for ES status, and only start initialization of SG when ES is ready:

Shell Script

#!/bin/sh

echo ">>>>  Right before SG initialization <<<<"
# use while loop to check if elasticsearch is running 
while true
do
    netstat -uplnt | grep :9300 | grep LISTEN > /dev/null
    verifier=$?
    if [ 0 = $verifier ]
        then
            echo "Running search guard plugin initialization"
            /elasticsearch/plugins/search-guard-6/tools/sgadmin.sh -h 0.0.0.0 -cd plugins/search-guard-6/sgconfig -icl -key config/client.key -cert config/client.pem -cacert config/root-ca.pem -nhnv
            break
        else
            echo "ES is not running yet"
            sleep 5
    fi
done

Install script in Dockerfile

You will need to install the script in container so it's accessible after it starts.

COPY sginit.sh /
RUN chmod +x /sginit.sh

Update entrypoint script

You will need to edit the entrypoint script or run script of your ES image. So that it starts the sginit.sh in the background BEFORE starting ES process.

# Run sginit in background waiting for ES to start
/sginit.sh &

This way the sginit.sh will start in the background, and will only initialize SG after ES is started.

The reason to have this sginit.sh script starts before ES in the background is so that it's not blocking ES from starting. The same logic applies if you put it after starting of ES, it will never run unless you put the starting of ES in the background.

like image 40
nafooesi Avatar answered Oct 08 '22 03:10

nafooesi


This is addressed in the documentation here: https://docs.docker.com/config/containers/multi-service_container/

If one of your processes depends on the main process, then start your helper process FIRST with a script like wait-for-it, then start the main process SECOND and remove the fg %1 line.

#!/bin/bash
  
# turn on bash's job control
set -m
  
# Start the primary process and put it in the background
./my_main_process &
  
# Start the helper process
./my_helper_process
  
# the my_helper_process might need to know how to wait on the
# primary process to start before it does its work and returns
  
  
# now we bring the primary process back into the foreground
# and leave it there
fg %1
like image 3
ManishM Avatar answered Oct 08 '22 03:10

ManishM


I would suggest to put the CMD in you docker file to execute the script when the container start

FROM debian
RUN apt-get update && apt-get install -y nano && apt-get clean
EXPOSE 8484
CMD ["/bin/bash", "/opt/your_app/init.sh"]

There is other way , but before using this look at your requirement,

    ENTRYPOINT "put your code here" && /bin/bash
    #exemple ENTRYPOINT service nginx start && service ssh start &&/bin/bash "use && to separate your code"
like image 2
Sohan Avatar answered Oct 08 '22 05:10

Sohan