Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run command in Docker Container only on the first start

Tags:

docker

People also ask

How do I run a command in docker container startup?

Running a Docker Container After you've built the Docker image, you'll need a container to run the Docker image that will execute the commands from the Dockerfile ENTRYPOINT and CMD instructions. To run a Docker container, invoke the run command to create a writeable container layer over the Docker image ( demo ).

How do I run a command in a docker container?

Running Commands in an Alternate Directory in a Docker Container. To run a command in a certain directory of your container, use the --workdir flag to specify the directory: docker exec --workdir /tmp container-name pwd.

What is restart unless stopped docker?

$ docker run -d --restart unless-stopped redis. This command changes the restart policy for an already running container named redis . $ docker update --restart unless-stopped redis. And this command will ensure all currently running containers will be restarted unless stopped.

What is difference between run and start in docker?

Start will start any stopped containers. This includes freshly created containers. Run is a combination of create and start. It creates the container and starts it.


I had the same issue, here a simple procedure (i.e. workaround) to solve it:

Step 1:

Create a "myStartupScript.sh" script that contains this code:

CONTAINER_ALREADY_STARTED="CONTAINER_ALREADY_STARTED_PLACEHOLDER"
if [ ! -e $CONTAINER_ALREADY_STARTED ]; then
    touch $CONTAINER_ALREADY_STARTED
    echo "-- First container startup --"
    # YOUR_JUST_ONCE_LOGIC_HERE
else
    echo "-- Not first container startup --"
fi

Step 2:

Replace the line "# YOUR_JUST_ONCE_LOGIC_HERE" with the code you want to be executed only the first time the container is started

Step 3:

Set the scritpt as entrypoint of your Dockerfile:

ENTRYPOINT ["/myStartupScript.sh"]

In summary, the logic is quite simple, it checks if a specific file is present in the filesystem; if not, it creates it and executes your just-once code. The next time you start your container the file is in the filesystem so the code is not executed.


The entry point for a docker container tells the docker daemon what to run when you want to "run" that specific container. Let's ask the questions "what the container should run when it's started the second time?" or "what the container should run after being rebooted?"

Probably, what you are doing is following the same approach you do with "old-school" provisioning mechanisms. Your script is "installing" the needed scripts and you will run your app as a systemd/upstart service, right? If you are doing that, you should change that into a more "dockerized" definition.

The entry point for that container should be a script that actually launches your app instead of setting things up. Let's say that you need java installed to be able to run your app. So in the dockerfile you set up the base container to install all the things you need like:

FROM alpine:edge

RUN apk --update upgrade && apk add openjdk8-jre-base
RUN mkdir -p /opt/your_app/ && adduser -HD userapp

ADD target/your_app.jar /opt/your_app/your-app.jar
ADD scripts/init.sh /opt/your_app/init.sh

USER userapp
EXPOSE 8081

CMD ["/bin/bash", "/opt/your_app/init.sh"]

Our containers, at the company I work for, before running the actual app in the init.sh script they fetch the configs from consul (instead of providing a mount point and place the configs inside the host or embedded them into the container). So the script will look something like:

#!/bin/bash

echo "Downloading config from consul..."
confd -onetime -backend consul -node $CONSUL_URL -prefix /cfgs/$CONSUL_APP/$CONSUL_ENV_NAME
echo "Launching your-app..."
java -jar /opt/your_app/your-app.jar

One advice I can give you is (in my really short experience working with containers) treat your containers as if they were stateless once they are provisioned (all the commands you run before the entry point).


I had to do this and I ended up doing a docker run -d which just created a detached container and started bash (in the background) followed by a docker exec, that did the necessary initialization. here's an example

docker run -itd --name=myContainer myImage /bin/bash
docker exec -it myContainer /bin/bash -c /init.sh

Now when I restart my container I can just do

docker start myContainer
docker attach myContainer

This may not be ideal but work fine for me.


I wanted to do the same on windows container. It can be achieved using task scheduler on windows. Linux equivalent for task Scheduler is cron. You can use that in your case. To do this edit the dockerfile and add the following line at the end

WORKDIR /app 
COPY myTask.ps1 . 
RUN schtasks /Create /TN myTask /SC ONSTART /TR "c:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\app\myTask.ps1" /ru SYSTEM

This Creates a task with name myTask runs it ONSTART and the task its self is to execute a powershell script placed at "c:\app\myTask.ps1".

This myTask.ps1 script will do whatever Initialization you need to do on the container startup. Make sure you delete this task once it is executed successfully or else it will run at every startup. To delete it you can use the following command at the end of myTask.ps1 script.

schtasks /Delete /TN myTask /F