14

In my Dockerfile, I run a script:

RUN /bin/sh -c scripts/init.sh

Inside init.sh, all commands ending with & are not executed: I cannot run background processes. Any idea why?

4
  • have tried to use the full path of init.sh ?
    – ebal
    Commented Aug 1, 2016 at 17:40
  • @ebal No, why? Relative paths are ok in the other commands of init.sh. I'll try tomorrow.
    – clemtoy
    Commented Aug 1, 2016 at 18:49
  • To solve my problem, I use docker exec -d my_command after the build...
    – clemtoy
    Commented Aug 3, 2016 at 13:55
  • 1
    Can you explain what are you trying to do a bit more? Is this a background process you need running at image build time or to run inside the container? Does your init script exit after running the background tasks?
    – Matt
    Commented Jan 9, 2018 at 13:30

5 Answers 5

4

I had the similar issue and something like the following helped me.

RUN nohup bash -c "scripts/init.sh &" && sleep 4

In many cases the server you started isn’t yet fully ready. To allow the server a bit more time to get ready add a sleep command. How large the argument sleep needs to depend on the service you start and you probably need to tweak it.

Read more on this Doc

2
  • What possible purpose does it serve to run the script (which happens at build time only) in the background (and wait an arbitrary time before proceeding)? Commented Jun 29, 2022 at 19:34
  • RUN is a build time command. You use it to build the container. It does nothing when the container itself is running.
    – Earl Ruby
    Commented Sep 9, 2023 at 15:59
2

The reason why it doesn't seem to work to run commands in the background with docker RUN commands is that RUN happens at docker build time. These commands help build the docker image, such as installing the things that need to be in the docker when it is instantiated, or setting up configuration files that will be used when the docker is instantiated. It makes no sense to run commands in the background at build time.

2

To run something in the background, let's use this in a Dockerfile:

FROM ubuntu:20.04
RUN mkdir /scripts
RUN echo 'touch /tmp/file &' >> /scripts/init.sh
RUN echo 'tail -F /dev/null' >> /scripts/init.sh
CMD sh -c "sh /scripts/init.sh"

You can replace tail -F /dev/null with the next command/service which doesn't exit and keeps container running.

Building and testing:

docker build -t mytest .
docker run -td --name mytest mytest
docker exec mytest ls -l /tmp/file

A note that entrypoint and command should not be set in Docker Compose, Kubernetes or any container management/orchestration tool. They override Dockerfile's CMD. Or you can set same CMD. So CMD is used at execution time, while RUN is used only when building image.


To make best quality app, you have to put your task to another container. For instance, put it to init container, use CronJob, Job or something equivalent.

Of course, tasks are still fine to be executed in background in any programming language.

But specifically Shell needs special efforts.


So here is bonus part

I have tested this only in Ubuntu, a thread logging using Shell and Docker.

Try adding this step after another touch step:

RUN echo 'touch /proc/no_file_can_be_created_in_proc_dir > /proc/1/fd/1 >> /proc/1/fd/2 &' >> /scripts/init.sh

So it prints logs for that background task:

$ docker logs mytest
touch: cannot touch '/proc/no_file_can_be_created_in_proc_dir': No such file or directory

So the trick is to use > /proc/1/fd/1 >> /proc/1/fd/2 & instead of just & in your command.

2
  • @JeffLearman this has been done. I've also added a bonus part to rectify my previous incorrect answer.
    – laimison
    Commented Jul 8, 2022 at 12:13
  • RUN is a build time command. You use it to build the container. It does nothing when the container itself is running.
    – Earl Ruby
    Commented Sep 9, 2023 at 16:00
0

Your scripts do run in the background, however only for the duration of that particular RUN command. Running processes are not part of the state of an image layer, and each RUN command builds a new image layer. It's not a virtual machine running each command in sequence and keeping all processes running in between. It's better to think of each layer as a folder of files, containing the consequences of all commands up to that point.

As others have pointed out, running multiple background processes is outside the spirit of what a single container is intended to do; it is better to run them as separate containers and orchestrate them with docker-compose or kubernetes.

However, you can do it by running both your background processes and your "foreground process" (the main purpose of your image) as part of the CMD statement at the end of your Dockerfile:

# Start MongoDB in the background, run the application in the foreground
CMD bash -c "mongod --dbpath=/root/tmp-mongodb-data & sleep 5 && npm run start"

The sleep command, as others have suggested, is there to wait for the background process (in this case MongoDB) to be ready to talk to the foreground process. Of course there are better ways, like a script that waits for a port to actually start taking connections.

However, in my case I didn't need MongoDB for the final foreground command — I needed it for one of my intermediate RUN commands that creates a layer. And, you can solve that too:

RUN bash -c "mongod --dbpath=/root/tmp-mongodb-data & sleep 5 && npm run build"

The key here is to start the background process separately for each RUN or CMD statement that must have access to it.

(To be clear, generally there is only one CMD statement at the end, they are not interchangeable with RUN statements.)

-1

My first idea is to create services inside the container instead of running them with nohup or &, run them as system service and you don't need to handle them in init.sh.

But this is not a "real" docker approach. If you need more than 1 service to run, separate them to different containers (1 container - 1 service) and put all of them together with a docker-compose solution.

1
  • Neither systemd nor initd run inside containers, so you can’t run a service in a container. You can run multiple background processes and you can use & to run a process in the background. However, RUN is a build command, and does not do anything when the container is running.
    – Earl Ruby
    Commented Sep 9, 2023 at 16:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .