In the traditional CentOS container, if you want to use systemctl, you will encounter the following situations
The system prompts you that you cannot use systemctl because the current system is not booted by systemd Therefore, it is not difficult to understand why the following commands can use systemctl
docker run -itd --name=centos --privileged=true centos /usr/sbin/init
But relatively speaking, the situation of Ubuntu will be more trouble
Use the –init parameter to change the container’s process 1 to /sbin/docker-init
When the init parameter is not used, as shown in the figure below, pay attention to the differences
Kill process 25 and change the parent process of process 28 into process 1
Kill process 28 again and generate a verification in the zombie process by yourself. At this time, process 28 should become a zombie process. However, process 28 is recycled normally because process 1 of the container is docker init
Conclusion: when the –init parameter is used, the No. 1 process of the container is docker-init, which can normally recycle orphan processes, thus avoiding the problem of zombie processes under specific conditions
#!/usr/bin/env python3
import subprocess
import time
import os
print(os.getpid())
p = subprocess.Popen(['/bin/sleep', '1'])
time.sleep(1000000)
In this program, the main process will start a sleep subprocess, and the execution of this sleep will end in 1 second.
At this time, it will enter the state of waiting to be recycled
However, the main process enters sleep (1000000) at this time. During the blocking process, the child process is not recycled, so the child process is not recycled 6701 main process and 6702 subprocess become zombies
In other words, you can easily get a zombie process as long as you meet two conditions
Parent process blocking (sleep)
The subprocess ends execution and waits for recycling
Based on the above two conditions, let’s try docker
Let’s first create a sleep Ubuntu container. Process 1 of this container is a blocking process, that is, it will not recycle any child processes
We created several bash processes using bash
Next, let’s kill process 27, so that the parent process of process 30 will become process 1 (that is, sleep process)
At this point, the parent process of process 30 becomes a sleep process that does not care about it Because process 27 has been recycled by process 24, there are no zombie processes in the host
We’ll kill process 30, which nobody cares about
In this way, we successfully created a zombie process PID 30 in container, PID 7132 on host If the container is stopped, the zombie process will be recycled by the host
To sum up, when
The main process of docker container is blocked for some reason
The main process creates some child processes
Once the parent process of these child processes becomes the container main process in blocking, they will become zombie processes that cannot be recycled after running
To understand how to avoid the zombie process, we first need to know where this problem comes from The maximum value of Linux system process number is 32768
When the total number of PID reaches this value, the system will not be able to create a new process, which is a very serious problem
I once encountered a system bug, that is, when calling the external system, the external system did not return, the process would not be released and kept waiting, which eventually led to the bug of PID depletion I don’t want to repeat the Linux Process tree here,
Under normal circumstances, when the process exits, the PID will be recycled by the parent process. The specific method is
When the child process ends, the system sends sigchild signal to its parent process
Blocking after the parent process calls the wait function
The parent process is awakened by the sigchild signal and then recovers the zombie child process
There is a special case where the parent process ends earlier than the child’s process. For example, the parent process is killed In this case, the parent process of the child process will be directed to init (that is, process 1), so process 1 will be responsible for recycling The init process in the early Linux system was very lightweight, called sysinit However, in the modern Linux environment, the init process is generally a heavyweight process such as systemd or upstartd, which will do a lot of extra work. (in fact, this issue has caused a lot of debate. Some developers believe that using a heavier init process will do more harm than good) By constantly calling bash, you can get a standard process tree
We can see that the parent process of process 3099 is 3093, and its child processes include 3105, 3111, 3117 and 3123 Here, if you kill process 3099, you will find that the parent process of its direct child process 3105 has indeed become /lib/systemd/systemd –user (PID 1634) Although it is indeed systemd, what about the agreed process 1? Process 1 is /sbin/init auto noprompt
Want to know why? After Ubuntu 18 (I’m currently Ubuntu 20), /sbin/init is a soft link to / lib/system/systemd
On the above normal Linux system, even if we kill the parent process of 3105, it will not become a zombie. At this time, no zombie process can be found by using ps -ef | grep defunct
After killing process 21, process 24 will be hosted to process 1 of docker
We talked about how to connect containers in the previous section A network that shares the same third container, To use localhost to access the endpoints of other containers. The main principle is the namespace of Linux network However, this problem is different in docker compose Start the two containers through the following script and configure them to share a network called unetwork
Because the network namespace between different containers is isolated, the localhost loopback address of each container can only point to itself However, in k8s, containers in the same pod can actually use localhost to access each other. Why? K8s’s pod will run a container named pause by default, and other containers will be hung on this pause, that is, the docker run –net container is used
docker run -i -t --name pause busybox sleep infinity
docker run -i -t --name nginx --net container:pause nginx
docker run -i -t --name watcher --net container:pause ubuntu sleep infinity
docker exec -i -t watcher /bin/bash
in the container
apt update
apt install curl
curl localhost:80
WordPress docker deployment using – link can directly connect to the database without configuring MySQL database connection.
Here I want to discuss what link has done
First of all, we need to clarify two concepts: MySQL is the source container and the connected container, WordPress is the target container and the receiving container
For the next test, we start two busybox containers and connect them together
For WordPress containers, WP_ MySQL and MySQL are a container with the same containerid
–link source:mysource
For the target container, source and mysource are one container
2. DNS
3. environment variable
The reason why WordPress can directly connect to the database above is that it actually uses environment variables
The image of WordPress will read the database configuration from the alias MySQL by default, so if it is written as –link wp_mysql:test_mysql and WordPress can’t recognize the database, which can be understood as a convention
The target container gets the following environment variables
4. If the IP of the source container changes
After deleting the source container, I create an nginx container, which takes up all the resources of the original source container
172.17.0.2 IP you can see that the new IP is 172.17.0.4
At this point, no content is updated in the target container
Start a target2 container, and you can see that DNS and env are replaced with new ones
Generally, service processes such as apache2, Tomcat and MySQL will not stop directly, so docker run and docker start will not exit directly in this case
docker run -i -t –name nginx nginx
The -i -t parameter is fundamental to providing an interactive shell
-i ensures that stdin in the container is open and can be attached with docker attach
-t assigns a pseudo TTY terminal to the created container so that the newly created container can provide an interactive shell
If you want to interfere with the process in Linux system, you need to send some specific signals
There are dozens of these signals, so we won’t list them one by one
There are three common ways to stop or terminate a process,
CTRL + C sends SIGINT signal, which will and will only send to the process in the currently active window and all the subprocesses of the process (process tree)
Kill PID sends SIGTERM, which can be blocked, processed, and ignored
Kill – 9 PID sends sigkill. Sigkill signal cannot be blocked, processed, or ignored. It stops the specified process directly and does not affect other child processes and parent processes. However, the parent process of the child process will be changed from the process that was killed to the init process
SIGTERM and SIGINT signals will be processed according to the logic defined by the program, such as the following Java program
import sun.misc.Signal;
import sun.misc.SignalHandler;
@SuppressWarnings("restriction")
public class Test {
public static void main(String[] args) {
System.out.println("Signal handling example.");
SignalHandler handler = new MySignalHandler();
// kill命令
Signal termSignal = new Signal("TERM");
Signal.handle(termSignal, handler);
// ctrl+c命令
Signal intSignal = new Signal("INT");
Signal.handle(intSignal, handler);
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
System.out.println("Interrupted: " + e.getMessage());
}
}
}
@SuppressWarnings("restriction")
class MySignalHandler implements SignalHandler {
@Override
public void handle(Signal signal) {
System.out.println("Signal handler called for signal " + signal);
try {
System.out.println("Handling " + signal.getName());
} catch (Exception e) {
System.out.println("handle|Signal handler" + "failed, reason "
+ e.getMessage());
e.printStackTrace();
}
}
}
When using Ctrl + C to send SIGINT signal to it, it just outputs information and does not stop itself
After using kill PID to send SIGTERM signal, it only outputs information and does not stop itself
Finally, the sigkill signal of kill – 9 PID directly kills the system
To stop a container, the most common method is docker stop
The stop command essentially sends SIGTERM signal to the process (such as nginx process). Most applications can correctly respond to this signal and start to stop themselves
If there is a special case, you need to use docker kill container_ Name to send sigkill