In Docker, the process management is based on the PID namespace technology of the Linux kernel. You can have the same PID in different PID namespaces.
The Linux kernel maintains a tree-like data structure for all PID namespaces. At the top level is the root namespace (root namespace) created during system initialization. The parent node can see the process in the child node and influence the process in the child node through signals and other ways. Conversely, children cannot see anything in their parent’s namespace, nor can they affect processes in their parent or other namespaces by killing or ptrace.
There is a very special process in Docker — the process with PID 1, which is also the main process of Docker, specified by ENTRYPOINT and/or CMD directives in Dockerfile. When the main process exits, the container’s PIG namespace is destroyed, and the container’s life cycle ends. Docker best practice recommends one service per container, not one thread per container. Some services, such as Apache and UWSGi, spawn more child processes, which is perfectly OK.
The PID1 process is responsible for the child processes it creates. If the main process is not properly designed and cannot gracefully exit the child processes, many problems may occur, such as database Container. If the process that processes data does not gracefully exit, data loss may occur. If, unfortunately, your main process is one of those that cannot manage child processes, Docker provides a small tool to help you do this. All you need to do is provide a — init flag when the Run creates the container, and Docker takes care of it manually.
Let’s look at an example
In Docker, for CMD and ENTRYPOINT, two process execution modes are supported: exec and shell.
The shell format is:
CMD "executable param1 param2"
Copy the code
The final PID1 process will be: /bin/sh -c “executable param1 param2”
The format of Exec is:
CMD ["executable"."param1"."param2"]
Copy the code
The final PID1 process is: Executable Param1 param2
Now there are two images, the dockerfiles are as follows:
- Mirror redis: shell
FROM ubuntu:14.04
RUN apt-get update && apt-get -y install redis-server && rm -rf /var/lib/apt/lists/*
EXPOSE 6379
CMD "/usr/bin/redis-server"
Copy the code
- Mirror redis: exec
FROM ubuntu:14.04
RUN apt-get update && apt-get -y install redis-server && rm -rf /var/lib/apt/lists/*
EXPOSE 6379
CMD ["/usr/bin/redis-server"]
Copy the code
docker run -d --name myredis1 redis:shell
docker run -d --name myredis2 redis:exec
Copy the code
Which docker image is better?
As we mentioned earlier, the PID1 process (the main process) is responsible for its children, and in the case of redis:shell, it produces PID1
/bin/sh -c "/usr/bin/redis-server"
Copy the code
/usr/bin/redis-server! /usr/bin/redis-server is just a child process it creates!
Execute the command
docker exec myredis1 ps -ef
Copy the code
You can test this guess
The main process of the Container running through exec is what we expect.
You might think, what’s the big deal? The problem is when we stop the container.
Stop redis: shell
docker stop myredis1
docker logs myredis1
Copy the code
When stopped, Docker obviously stopped for a period of time, and check the log shows that Redis did not do any operation to save the database, and was directly forced to exit. What happened in between? First, running the stop command sends a SIGTERM signal to the container, telling the main process that it’s time to quit and tidy up. However, the main process is /bin/sh, how can it possibly have a mechanism to handle the redis process exit? So the Redis process will not exit immediately. The Docker Daemon waits for some time (10 seconds by default) to find that the container has not completely quit, and then sends SIGKILL to forcibly kill the container. During this process, the Redis process has no idea that it should exit, so it doesn’t do any finishing touches.
Stop redis: exec
docker stop myredis2
docker logs myredis2
Copy the code
This time, the stop will take effect immediately, and there is no lag phenomenon. From the output, Redis shutdown the operation, and the persistent data is saved to disk. Because the PID1 process is
/usr/bin/redis-server
Copy the code
It is able to handle SIGTERM signals correctly. That’s what we expect.
To summarize
The PID1 process is a special Docker process whose life cycle is the life cycle of the Docker Container. It is responsible for the child process generated by the PID1 process. When writing the Dockerfile, make sure that the PID1 process is defined.