通常情况下,诸如 apache2、tomcat 和 mysql 等服务进程,是不会直接停止的,所以在这种情况下 docker run 和 docker start 都不会直接退出
docker run -i -t –name nginx nginx
参数 -i -t 是提供交互式shell的根本
- -i 标志保障容器中STDIN是开启的,保证可以使用 docker attach 附着进去
- -t 会为创建的容器分配一个伪tty终端,这样新创建的容器才能提供一个交互式的shell
Linux 系统中想要对进程进行干涉,需要发送一些特定的信号
这些信号有几十种这里就不一一例举了
要停止或者终止一个进程比较常用的是以下三种,
- ctrl + c 发送的是 SIGINT 信号,SIGINT信号会且只会发送到当前活动窗口的进程 和 这个进程的所有子进程(进程树)
- kill PID 发送的是 SIGTERM,可以被阻塞、处理和忽略
- kill -9 PID 发送的是 SIGKILL,SIGKILL 信号不能被阻塞、处理和忽略,直接停止指定的进程,不影响其他子进程和父进程,但是子进程的父进程会从这个被kill的进程转为 init 进程
其中 SIGTERM 和 SIGINT 信号会按照程序自定义的逻辑来处理这些信号,例如下面这个Java程序
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();
}
}
}
使用 ctrl + c 对其发送 SIGINT 信号时,它只是输出了信息,并没有停止自己
使用kill PID发送 SIGTERM信号之后,它只是输出了信息,并没有停止自己
最后是 kill -9 PID 的 SIGKILL信号,直接杀死了
要停止容器的话,最常用的是 docker stop
stop 命令本质上是向该进程(例如Nginx进程)发送 SIGTERM 信号,大多数应用都能正确的响应这个信号,开始停止自己
如果出现了特殊情况,就需要使用 docker kill container_name 来发送 SIGKILL