Home Operation and Maintenance Docker Do you know how to catch signals in docker containers?

Do you know how to catch signals in docker containers?

Feb 22, 2021 am 10:29 AM
docker Signal container

Do you know how to catch signals in docker containers?

I believe you must have used the docker stop command to stop a running container. Sometimes we may also use the docker kill command to forcefully close the container or pass a signal to the process in the container.

In fact, the operations we perform are essentially the interaction between the host and the program in the container by sending signals from the host to the container. For example, if we send a reload signal to the application in the container, then the application in the container will execute the corresponding handler to complete the task of reloading the configuration file after receiving the signal.

Signal (linux)

Signal is a form of inter-process communication. A signal is a message sent by the kernel to a process to tell the process that a certain event has occurred. When a signal is sent to a process, the process will immediately interrupt the current execution flow and start executing the signal handler (it is not accurate to say that the signal is processed at a specific time). If no handler is specified for this signal, the default handler is executed.
The process needs to register handlers for the signals it is interested in. For example, in order to allow the program to exit gracefully (to clean up resources after receiving the exit request), generally the program will handle the SIGTERM signal. Unlike the SIGTERM signal, the SIGKILL signal will violently end a process. Therefore, our application should implement a directory that captures and handles the SIGTERM signal to exit the program gracefully. If we fail, the user will have to resort to the SIGKILL signal as a last resort. In addition to SIGTERM and SIGKILL, there are signals like SIGUSR1 that specifically support user-defined behavior. The following code simply explains how to register a handler for a signal in nodejs:

process.on('SIGTERM', function() {
  console.log('shutting down...');
});
Copy after login

For more information about signals, the author mentioned it in the article "linux kill command" and will not be repeated here.

Signals in the container

Docker’s stop and kill commands are used to send signals to the container. Note that only process No. 1 in the container can receive the signal, this is very critical!
The stop command will first send the SIGTERM signal and wait for the application to end gracefully. If it is found that the application has not ended (the user can specify the waiting time), then send another SIGKILL signal to forcefully end the program.
The kill command sends the SIGKILL signal by default. Of course, you can specify any signal through the -s option.

Below we use a nodejs application to demonstrate the working process of signals in the container. Create an app.js file with the following content:

'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]);
  });
});
Copy after login

This application is an http server, listening on port 3000, with handlers registered for the SIGINT and SIGTERM signals. Next we will introduce how signals are handled when running programs in containers in different ways.

The application is used as process No. 1 in the container

Create a Dockerfile file and package the above application into the image:

FROM iojs:onbuild
COPY ./app.js ./app.js
COPY ./package.json ./package.json
EXPOSE 3000ENTRYPOINT ["node", "app"]
Copy after login

Please pay attention to the way of writing the ENTRYPOINT instruction. This The way it is written will make node run as process No. 1 in the container.

Next create the image:

$ docker build --no-cache -t signal-app -f Dockerfile .
Copy after login

Then start the container and run the application:

请注意 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:
Copy after login

At this time, the process number of the node application in the container is 1:

Do you know how to catch signals in docker containers?

Now we let the program exit and execute the command:

$ docker container kill --signal="SIGTERM" my-app
Copy after login

At this time the application will exit in the way we expect:

Do you know how to catch signals in docker containers?

The application is not process No. 1 in the container

Create a script file app1.sh that starts the application, with the following content:

#!/usr/bin/env bash
node app
Copy after login

Then create a Dockerfile1 file with the following content:

FROM iojs:onbuild
COPY ./app.js ./app.js
COPY ./app1.sh ./app1.sh
COPY ./package.json ./package.json
RUN chmod +x ./app1.sh
EXPOSE 3000
ENTRYPOINT ["./app1.sh"]
Copy after login

Next create the image:

$ docker build --no-cache -t signal-app1 -f Dockerfile1 .
Copy after login

Then start the container and run the application:

$ docker run -it --rm -p 3000:3000 --name="my-app1" signal-app1
Copy after login

At this time, the process number of the node application in the container is no longer 1:

Do you know how to catch signals in docker containers?

现在给 my-app1 发送 SIGTERM 信号试试,已经无法退出程序了!在这个场景中,应用程序由 bash 脚本启动,bash 作为容器中的 1 号进程收到了 SIGTERM 信号,但是它没有做出任何的响应动作。
我们可以通过:

$ docker container stop my-app1
# or
$ docker container kill --signal="SIGKILL" my-app1
Copy after login

退出应用,它们最终都是向容器中的 1 号进程发送了 SIGKILL 信号。很显然这不是我们期望的,我们希望程序能够收到 SIGTERM 信号优雅的退出。

在脚本中捕获信号

创建另外一个启动应用程序的脚本文件 app2.sh,内容如下:

#!/usr/bin/env bash
set -x

pid=0

# SIGUSR1-handler
my_handler() {
  echo "my_handler"
}

# SIGTERM-handler
term_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 handler
trap 'kill ${!}; my_handler' SIGUSR1
trap 'kill ${!}; term_handler' SIGTERM

# run application
node app &
pid="$!"

# wait forever
while true
do
  tail -f /dev/null & wait ${!}
done
Copy after login

这个脚本文件在启动应用程序的同时可以捕获发送给它的 SIGTERM 和 SIGUSR1 信号,并为它们添加了处理程序。其中 SIGTERM 信号的处理程序就是向我们的 node 应用程序发送 SIGTERM 信号。

然后创建 Dockerfile2 文件,内容如下:

FROM iojs:onbuild
COPY ./app.js ./app.js
COPY ./app2.sh ./app2.sh
COPY ./package.json ./package.json
RUN chmod +x ./app2.sh
EXPOSE 3000
ENTRYPOINT ["./app2.sh"]
Copy after login

接下来创建镜像:

$ docker build --no-cache -t signal-app2 -f Dockerfile2 .
Copy after login

然后启动容器运行应用程序:

$ docker run -it --rm -p 3000:3000 --name="my-app2" signal-app2
Copy after login

此时 node 应用在容器中的进程号也不是 1,但是它却可以接收到 SIGTERM 信号并优雅的退出了:

Do you know how to catch signals in docker containers?

结论

容器中的 1 号进程是非常重要的,如果它不能正确的处理相关的信号,那么应用程序退出的方式几乎总是被强制杀死而不是优雅的退出。究竟谁是 1 号进程则主要由 EntryPoint, CMD, RUN 等指令的写法决定,所以这些指令的使用是很有讲究的。

相关推荐:docker入门教程

The above is the detailed content of Do you know how to catch signals in docker containers?. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to update the image of docker How to update the image of docker Apr 15, 2025 pm 12:03 PM

The steps to update a Docker image are as follows: Pull the latest image tag New image Delete the old image for a specific tag (optional) Restart the container (if needed)

How to use docker desktop How to use docker desktop Apr 15, 2025 am 11:45 AM

How to use Docker Desktop? Docker Desktop is a tool for running Docker containers on local machines. The steps to use include: 1. Install Docker Desktop; 2. Start Docker Desktop; 3. Create Docker image (using Dockerfile); 4. Build Docker image (using docker build); 5. Run Docker container (using docker run).

How to create a mirror in docker How to create a mirror in docker Apr 15, 2025 am 11:27 AM

Steps to create a Docker image: Write a Dockerfile that contains the build instructions. Build the image in the terminal, using the docker build command. Tag the image and assign names and tags using the docker tag command.

How to exit the container by docker How to exit the container by docker Apr 15, 2025 pm 12:15 PM

Four ways to exit Docker container: Use Ctrl D in the container terminal Enter exit command in the container terminal Use docker stop <container_name> Command Use docker kill <container_name> command in the host terminal (force exit)

How to check the name of the docker container How to check the name of the docker container Apr 15, 2025 pm 12:21 PM

You can query the Docker container name by following the steps: List all containers (docker ps). Filter the container list (using the grep command). Gets the container name (located in the "NAMES" column).

What to do if the docker image fails What to do if the docker image fails Apr 15, 2025 am 11:21 AM

Troubleshooting steps for failed Docker image build: Check Dockerfile syntax and dependency version. Check if the build context contains the required source code and dependencies. View the build log for error details. Use the --target option to build a hierarchical phase to identify failure points. Make sure to use the latest version of Docker engine. Build the image with --t [image-name]:debug mode to debug the problem. Check disk space and make sure it is sufficient. Disable SELinux to prevent interference with the build process. Ask community platforms for help, provide Dockerfiles and build log descriptions for more specific suggestions.

How to copy files in docker to outside How to copy files in docker to outside Apr 15, 2025 pm 12:12 PM

Methods for copying files to external hosts in Docker: Use the docker cp command: Execute docker cp [Options] <Container Path> <Host Path>. Using data volumes: Create a directory on the host, and use the -v parameter to mount the directory into the container when creating the container to achieve bidirectional file synchronization.

How to save docker image How to save docker image Apr 15, 2025 am 11:54 AM

To save the image in Docker, you can use the docker commit command to create a new image, containing the current state of the specified container, syntax: docker commit [Options] Container ID Image name. To save the image to the repository, you can use the docker push command, syntax: docker push image name [: tag]. To import saved images, you can use the docker pull command, syntax: docker pull image name [: tag].

See all articles