In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)06/02 Report--
我们可能都使用过 docker stop 命令来停止正在运行的容器,有时可能会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程。这些操作的本质都是通过从主机向容器发送信号实现主机与容器中程序的交互。比如我们可以向容器中的应用发送一个重新加载信号,容器中的应用程序在接到信号后执行相应的处理程序完成重新加载配置文件的任务。本文将介绍在 docker 容器中捕获信号的基本知识。
信号(linux)
信号是一种进程间通信的形式。一个信号就是内核发送给进程的一个消息,告诉进程发生了某种事件。当一个信号被发送给一个进程后,进程会立即中断当前的执行流并开始执行信号的处理程序。如果没有为这个信号指定处理程序,就执行默认的处理程序。
进程需要为自己感兴趣的信号注册处理程序,比如为了能让程序优雅的退出(接到退出的请求后能够对资源进行清理)一般程序都会处理 SIGTERM 信号。与 SIGTERM 信号不同,SIGKILL 信号会粗暴的结束一个进程。因此我们的应用应该实现这样的目录:捕获并处理 SIGTERM 信号,从而优雅的退出程序。如果我们失败了,用户就只能通过 SIGKILL 信号这一终极手段了。除了 SIGTERM 和 SIGKILL ,还有像 SIGUSR1 这样的专门支持用户自定义行为的信号。下面的代码简单的说明在 nodejs 中如何为一个信号注册处理程序:
process.on('SIGTERM', function() { console.log('shutting down...');});
关于信号的更多信息,笔者在《linux kill 命令》一文中有所提及,这里不再赘述。
容器中的信号
Docker 的 stop 和 kill 命令都是用来向容器发送信号的。注意,只有容器中的 1 号进程能够收到信号,这一点非常关键!
stop 命令会首先发送 SIGTERM 信号,并等待应用优雅的结束。如果发现应用没有结束(用户可以指定等待的时间),就再发送一个 SIGKILL 信号强行结束程序。
kill 命令默认发送的是 SIGKILL 信号,当然你可以通过 -s 选项指定任何信号。
下面我们通过一个 nodejs 应用演示信号在容器中的工作过程。创建 app.js 文件,内容如下:
'use strict';var http = require('http');var server = http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n');}).listen(3000, '0.0.0.0');console.log('server started');var signals = { 'SIGINT': 2, 'SIGTERM': 15};function shutdown(signal, value) { server.close(function () { console.log('server stopped by ' + signal); process.exit(128 + value); });}Object.keys(signals).forEach(function (signal) { process.on(signal, function () { shutdown(signal, signals[signal]); });});
这个应用是一个 http 服务器,监听端口 3000,为 SIGINT 和 SIGTERM 信号注册了处理程序。接下来我们将介绍以不同的方式在容器中运行程序时信号的处理情况。
应用程序作为容器中的 1 号进程
创建 Dockerfile 文件,把上面的应用打包到镜像中:
FROM iojs:onbuildCOPY ./app.js ./app.jsCOPY ./package.json ./package.jsonEXPOSE 3000ENTRYPOINT ["node", "app"]
请注意 ENTRYPOINT 指令的写法,这种写法会让 node 在容器中以 1 号进程的身份运行。
接下来创建镜像:
$ docker build --no-cache -t signal-app -f Dockerfile .
然后启动容器运行应用程序:
$ docker run -it --rm -p 3000:3000 --name="my-app" signal-app
此时 node 应用在容器中的进程号为 1:
Now let's quit the program and execute the command:
$ docker container kill --signal="SIGTERM" my-app
The app will exit the way we expect:
The application is not process number 1 in the container
Create a script file app1.sh to launch the application, which reads as follows:
#!/ usr/bin/env bashnode app
Then create Dockerfile1 with the following content:
FROM iojs:onbuildCOPY ./ app.js ./ app.jsCOPY ./ app1.sh ./ app1.shCOPY ./ package.json ./ package.jsonRUN chmod +x ./ app1.shEXPOSE 3000ENTRYPOINT ["./ app1.sh"]
Next, create a mirror:
$ docker build --no-cache -t signal-app1 -f Dockerfile1 .
Then launch the container to run the application:
$ docker run -it --rm -p 3000:3000 --name="my-app1" signal-app1
At this point, the process number that node applies to the container is no longer 1:
Now try sending a SIGTERM signal to my-app1, it is impossible to exit the program! In this scenario, the application is started by bash script, bash receives the SIGTERM signal as process 1 in the container, but it does nothing in response.
We can do this by:
$ docker container stop my-app1# or$ docker container kill --signal="SIGKILL" my-app1
Exiting applications, they all end up sending SIGKILL signals to process 1 in the container. Obviously this is not what we expect, we want the program to receive the SIGTERM signal and exit gracefully.
Capture signals in scripts
Create another script file app2.sh to launch the application, which reads as follows:
#!/ usr/bin/env bashset -xpid=0# SIGUSR1-handlermy_handler() { echo "my_handler"}# SIGTERM-handlerterm_handler() { if [ $pid -ne 0 ]; then kill -SIGTERM "$pid" wait "$pid" fi exit 143; # 128 + 15 -- SIGTERM}# setup handlers# on callback, kill the last background process, which is `tail -f /dev/null` and execute the specified handlertrap 'kill ${!}; my_handler' SIGUSR1trap 'kill ${!}; term_handler' SIGTERM# run applicationnode app &pid="$! "# wait foreverwhile truedo tail -f /dev/null & wait ${!} done
This script file captures the SIGTERM and SIGUSR1 signals sent to it while launching the application and adds handlers to them. The SIGTERM signal handler sends the SIGTERM signal to our node application.
Then create Dockerfile2 with the following content:
FROM iojs:onbuildCOPY ./ app.js ./ app.jsCOPY ./ app2.sh ./ app2.shCOPY ./ package.json ./ package.jsonRUN chmod +x ./ app2.shEXPOSE 3000ENTRYPOINT ["./ app2.sh"]
Next, create a mirror:
$ docker build --no-cache -t signal-app2 -f Dockerfile2 .
Then launch the container to run the application:
$ docker run -it --rm -p 3000:3000 --name="my-app2" signal-app2
At this time, the process number of node application in the container is not 1, but it can receive the SIGTERM signal and exit gracefully:
conclusion
Process #1 in the container is important because if it fails to handle the relevant signals correctly, the application exits almost always by force killing rather than graceful exit. Which process is No. 1 is mainly determined by the writing of instructions such as EntryPoint, CMD, RUN, etc., so the use of these instructions is very particular.
The above is all the content of this article, I hope to help everyone's study, but also hope that everyone a lot of support.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.