|
| 1 | +--- |
| 2 | +description: How to run more than one process in a container |
| 3 | +keywords: docker, supervisor, process management |
| 4 | +redirect_from: |
| 5 | +- /engine/articles/using_supervisord/ |
| 6 | +- /engine/admin/using_supervisord/ |
| 7 | +title: Run multiple services in a container |
| 8 | +--- |
| 9 | + |
| 10 | +A container's main running process is the `ENTRYPOINT` and/or `CMD` at the |
| 11 | +end of the `Dockerfile`. It is generally recommended that you separate areas of |
| 12 | +concern by using one service per container. That service may fork into multiple |
| 13 | +processes (for example, Apache web server starts multiple worker processes). |
| 14 | +It's ok to have multiple processes, but to get the most benefit out of Docker, |
| 15 | +avoid one container being responsible for multiple aspects of your overall |
| 16 | +application. You can connect multiple containers using user-defined networks and |
| 17 | +shared volumes. |
| 18 | + |
| 19 | +The container's main process is responsible for managing all processes that it |
| 20 | +starts. In some cases, the main process isn't well-designed, and doesn't handle |
| 21 | +"reaping" (stopping) child processes gracefully when the container exists. If |
| 22 | +your process falls into this category, you can use the `--init` option when you |
| 23 | +run the container. The `--init` flag inserts a tiny init-process into the |
| 24 | +container as the main process, and handles reaping of all processes when the |
| 25 | +container exits. Handling such processes this way is superior to using a |
| 26 | +full-fledged init process such as `sysvinit`, `upstart`, or `systemd` to handle |
| 27 | +process lifecycle within your container. |
| 28 | + |
| 29 | +If you need to run more than one service within a container, you can accomplish |
| 30 | +this in a few different ways. |
| 31 | + |
| 32 | +- Put all of your commands in a wrapper script, complete with testing and |
| 33 | + debugging information. Run the wrapper script as your `CMD`. This is a very |
| 34 | + naive example. First, the wrapper script: |
| 35 | + |
| 36 | + ```bash |
| 37 | + #!/bin/bash |
| 38 | + |
| 39 | + # Start the first process |
| 40 | + ./my_first_process -D |
| 41 | + status=$? |
| 42 | + if [ $status -ne 0 ]; then |
| 43 | + echo "Failed to start my_first_process: $status" |
| 44 | + exit $status |
| 45 | + fi |
| 46 | + |
| 47 | + # Start the second process |
| 48 | + ./my_second_process -D |
| 49 | + status=$? |
| 50 | + if [ $status -ne 0 ]; then |
| 51 | + echo "Failed to start my_second_process: $status" |
| 52 | + exit $status |
| 53 | + fi |
| 54 | + |
| 55 | + # Naive check runs checks once a minute to see if either of the processes exited. |
| 56 | + # This illustrates part of the heavy lifting you need to do if you want to run |
| 57 | + # more than one service in a container. The container will exit with an error |
| 58 | + # if it detects that either of the processes has exited. |
| 59 | + while /bin/true; do |
| 60 | + PROCESS_1_STATUS=$(ps aux |grep -q my_first_process) |
| 61 | + PROCESS_2_STATUS=$(ps aux |grep -q my_second_process) |
| 62 | + if [ $PROCESS_!_STATUS || $PROCESS_2_STATUS ]; then |
| 63 | + echo "One of the processes has already exited." |
| 64 | + exit -1 |
| 65 | + fi |
| 66 | + sleep 60 |
| 67 | + done |
| 68 | + ``` |
| 69 | + |
| 70 | + Next, the Dockerfile: |
| 71 | + |
| 72 | + ```conf |
| 73 | + FROM ubuntu:latest |
| 74 | + COPY my_first_process my_first_process |
| 75 | + COPY my_second_process my_second_process |
| 76 | + COPY my_wrapper_script.sh my_wrapper_script.sh |
| 77 | + CMD ./my_wrapper_script.sh |
| 78 | + ``` |
| 79 | + |
| 80 | +- Use a process manager like `supervisord`. This is a moderately heavy-weight |
| 81 | + approach that requires you to package `supervisord` and its configuration in |
| 82 | + your image (or base your image on one that includes `supervisord`), along with |
| 83 | + the different applications it will manage. Then you start `supervisord`, which |
| 84 | + manages your processes for you. Here is an example Dockerfile using this |
| 85 | + approach, that assumes the pre-written `supervisord.conf`, `my_first_process`, |
| 86 | + and `my_second_process` files all exist in the same directory as your |
| 87 | + Dockerfile. |
| 88 | + |
| 89 | + ```conf |
| 90 | + FROM ubuntu:latest |
| 91 | + RUN apt-get update && apt-get install -y supervisor |
| 92 | + RUN mkdir -p /var/log/supervisor |
| 93 | + COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf |
| 94 | + COPY my_first_process my_first_process |
| 95 | + COPY my_second_process my_second_process |
| 96 | + CMD ["/usr/bin/supervisord"] |
| 97 | + ``` |
0 commit comments