Docker: run startup scripts then exit to a shell

As I’ve mentioned before the way Docker is set up it expects to run one command at container start up, and when that command exits the container stops. There are all sorts of creative ways to get around that if, for example, you want to mimic init behavior by launching some daemons before opening a shell to work in the container. Here’s a little snippet from a Docker build file that illustrates one simple approach:

CMD bash -C '/path/to/start.sh';'bash'

In the ‘start.sh’ script (which I usually copy to /usr/local/bin during container build) you can put any start up commands you want. For example the one in the container I’m working on now just has:

service elasticsearch start

The result when launching the container is that bash runs, executes the command which spools up es, and then executes another shell and quits:

mark:~$ sudo docker run -i -t mark/example
 * Starting Elasticsearch Server                                         [ OK ] 
root@835600d4d0b2:/home/root# curl http://localhost:9200
{
  "status" : 200,
  "name" : "Box IV",
  "version" : {
    "number" : "1.0.1",
    "build_hash" : "5c03844e1978e5cc924dab2a423dc63ce881c42b",
    "build_timestamp" : "2014-02-25T15:52:53Z",
    "build_snapshot" : false,
    "lucene_version" : "4.6"
  },
  "tagline" : "You Know, for Search"
}
root@835600d4d0b2:/home/root# exit
exit
mark:~$

15 thoughts on “Docker: run startup scripts then exit to a shell

  1. Thanks for stopping by, Jim. It’s worth noting that I wrote this post two years ago, and have continued to work with Docker and learn new techniques since then. Most of what we used startup scripts for back when I wrote this I would not repeat today, because I understand better now how to manage the lifecycle of a container. We still do use startup scripts, primarily for customizing configuration before launching the foreground application that will run inside the container. We very rarely launch background processes inside them anymore. Much of that approach derived from an early conception that I had of containers as “appliances” that run all the stuff they need to, for example, provide certain services on specific ports. As we moved from manually launching individual containers to using orchestration platforms like Google Container Engine (kubernetes) it became clear that the preferred model was to have each container run a single process, and to group containers into collaborating networks to provide more complex services. The main advantages of this are simplification of container state, and enabling the monitors in the platform to manage the container from the outside: if the process a container implements (mongodb, say) dies then the container dies, and the supervisor layer can launch it again according to established restart policies. I think that back when I started working with this stuff I had an erroneous idea of containers as more “heavyweight” and overhead-laden than they are, and so I wanted to pack a lot of functionality into them. Unfortunately this just leads to higher degrees of complexity in the state of the container, and makes it harder to see from outside what is going on. Hope this helped, and thanks for your comment.

  2. Hello
    I tried to use this now. I had the start.sh script right in the folder where I had the dockerfile. Yet I get an error of “No such file or directory”. I also tried copying the start.sh to usr/local/bin and give its path to the Dockerfile CMD. It did not work too. Any way to come around this?
    Thanks

  3. The CMD and ENTRYPOINT directives tell Docker which process to launch inside the container file system at startup. You didn’t give quite enough detail on what you’re doing, but I’m guessing you did not add the startup.sh script to the image by using the ADD or COPY directives in the dockerfile.

  4. Thanks for stopping by catpan. I’m glad it worked for you, but this post is pretty old and docker has evolved, and I think there are better ways to do this now. I’ve learned a few things as well over the last two years, and as a general rule I now try to run a single process per container. It made sense sometimes to run more than one for networking purposes but docker compose and platforms like kubernetes now make it easy to orchestrate groups of containers and link them together. What I was trying to get when I wrote this post, i.e. to run a docker container and then have a shell I could use to interact with it internally, can be achieved using docker exec after starting a single process container. The last thing I would mention about startup scripts like this is that they should use exec to launch the process that the container is going to host. This allows the process to replace the startup script as pid 1 and handle signals correctly. And of course using exec prevents the technique of dropping into a shell. So once the process is running you do something like “docker exec -it /bin/bash” and you’re in.

  5. Hey Man,
    Could you explain your code a little clearer. I did it it works but Like:

    CMD bash -C ‘/path/to/start.sh’;’bash’

    What does the -C Parameter do?
    Why is the path to the executable in single quotes?
    What does the ; separate?
    Is running “bash” after the ; just like running /bin/bash shell?

    Thanks

  6. Hi, Michel. Thanks for stopping by. Yes, that command essentially just runs another bash shell in the existing one, however, see my reply to catman on this thread. This post is pretty old and I no longer recommend this approach. Here is a link to a post I did on medium.com a couple of weeks ago on debugging docker containers. It has a section that explains the use of ENTRYPOINT and CMD: https://medium.com/@betz.mark/ten-tips-for-debugging-docker-containers-cde4da841a1d#.nmb739yyn

  7. Hi :) This script though is running every time I attach to the docker container. Is there a way I use this script once (i.e. when the container is created for the first time) and then just attach to the container without any script execution?

  8. Hi, Eli. Thanks for dropping by. This technique is quite old and no longer recommended. See my earlier comments on the thread.

Leave a Reply

Your email address will not be published. Required fields are marked *