-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Updates to multi-process container topic #3026
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
--- | ||
description: How to run more than one process in a container | ||
keywords: docker, supervisor, process management | ||
redirect_from: | ||
- /engine/articles/using_supervisord/ | ||
- /engine/admin/using_supervisord/ | ||
title: Run multiple services in a container | ||
--- | ||
|
||
A container's main running process is the `ENTRYPOINT` and/or `CMD` at the | ||
end of the `Dockerfile`. It is generally recommended that you separate areas of | ||
concern by using one service per container. That service may fork into multiple | ||
processes (for example, Apache web server starts multiple worker processes). | ||
It's ok to have multiple processes, but to get the most benefit out of Docker, | ||
avoid one container being responsible for multiple aspects of your overall | ||
application. You can connect multiple containers using user-defined networks and | ||
shared volumes. | ||
|
||
The container's main process is responsible for managing all processes that it | ||
starts. In some cases, the main process isn't well-designed, and doesn't handle | ||
"reaping" (stopping) child processes gracefully when the container exists. If | ||
your process falls into this category, you can use the `--init` option when you | ||
run the container. The `--init` flag inserts a tiny init-process into the | ||
container as the main process, and handles reaping of all processes when the | ||
container exits. Handling such processes this way is superior to using a | ||
full-fledged init process such as `sysvinit`, `upstart`, or `systemd` to handle | ||
process lifecycle within your container. | ||
|
||
If you need to run more than one service within a container, you can accomplish | ||
this in a few different ways. | ||
|
||
- Put all of your commands in a wrapper script, complete with testing and | ||
debugging information. Run the wrapper script as your `CMD`. This is a very | ||
naive example. First, the wrapper script: | ||
|
||
```bash | ||
#!/bin/bash | ||
|
||
# Start the first process | ||
./my_first_process -D | ||
status=$? | ||
if [ $status -ne 0 ]; then | ||
echo "Failed to start my_first_process: $status" | ||
exit $status | ||
fi | ||
|
||
# Start the second process | ||
./my_second_process -D | ||
status=$? | ||
if [ $status -ne 0 ]; then | ||
echo "Failed to start my_second_process: $status" | ||
exit $status | ||
fi | ||
|
||
# Naive check runs checks once a minute to see if either of the processes exited. | ||
# This illustrates part of the heavy lifting you need to do if you want to run | ||
# more than one service in a container. The container will exit with an error | ||
# if it detects that either of the processes has exited. | ||
while /bin/true; do | ||
PROCESS_1_STATUS=$(ps aux |grep -q my_first_process) | ||
PROCESS_2_STATUS=$(ps aux |grep -q my_second_process) | ||
if [ $PROCESS_!_STATUS || $PROCESS_2_STATUS ]; then | ||
echo "One of the processes has already exited." | ||
exit -1 | ||
fi | ||
sleep 60 | ||
done | ||
``` | ||
|
||
Next, the Dockerfile: | ||
|
||
```conf | ||
FROM ubuntu:latest | ||
COPY my_first_process my_first_process | ||
COPY my_second_process my_second_process | ||
COPY my_wrapper_script.sh my_wrapper_script.sh | ||
CMD ./my_wrapper_script.sh | ||
``` | ||
|
||
- Use a process manager like `supervisord`. This is a moderately heavy-weight | ||
approach that requires you to package `supervisord` and its configuration in | ||
your image (or base your image on one that includes `supervisord`), along with | ||
the different applications it will manage. Then you start `supervisord`, which | ||
manages your processes for you. Here is an example Dockerfile using this | ||
approach, that assumes the pre-written `supervisord.conf`, `my_first_process`, | ||
and `my_second_process` files all exist in the same directory as your | ||
Dockerfile. | ||
|
||
```conf | ||
FROM ubuntu:latest | ||
RUN apt-get update && apt-get install -y supervisor | ||
RUN mkdir -p /var/log/supervisor | ||
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf | ||
COPY my_first_process my_first_process | ||
COPY my_second_process my_second_process | ||
CMD ["/usr/bin/supervisord"] | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely a fan of how lightweight this example is -- basically, if you want to run multiple processes, that's fine, here's an example of one application that can do so, but getting a "good" configuration for it is Up To You (Docker's not going to help you figure that out because it's Bad). 👍 ❤️ |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome 😍