容器的启动和停止

通常情况下,诸如 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

Send a Message