ホームページ 運用・保守 Docker Docker コンテナーでシグナルをキャッチする方法を知っていますか?

Docker コンテナーでシグナルをキャッチする方法を知っていますか?

Feb 22, 2021 am 10:29 AM
docker 信号 容器

Docker コンテナーでシグナルをキャッチする方法を知っていますか?

実行中のコンテナを停止するには docker stop コマンドを使用したはずですが、場合によっては docker kill コマンドを使用してコンテナを強制的に閉じたり、プロセスにシグナルを渡したりすることもあります。コンテナ。

実際、私たちが実行する操作は基本的に、ホストからコンテナーに信号を送信することによる、ホストとコンテナー内のプログラム間の対話です。たとえば、コンテナ内のアプリケーションにリロード信号を送信すると、コンテナ内のアプリケーションは、信号の受信後に対応するハンドラを実行して、構成ファイルをリロードするタスクを完了します。

Signal (linux)

Signal はプロセス間通信の形式です。シグナルは、特定のイベントが発生したことをプロセスに伝えるために、カーネルからプロセスに送信されるメッセージです。シグナルがプロセスに送信されると、プロセスは現在の実行フローを直ちに中断し、シグナル ハンドラーの実行を開始します (シグナルが特定の時間に処理されるというのは正確ではありません)。このシグナルにハンドラーが指定されていない場合は、デフォルトのハンドラーが実行されます。
プロセスは、対象となるシグナルのハンドラーを登録する必要があります。たとえば、プログラムが正常に終了できるようにする (終了要求を受信した後にリソースをクリーンアップするため) ため、通常、プログラムは SIGTERM シグナルを処理します。 SIGTERM シグナルとは異なり、SIGKILL シグナルはプロセスを強制的に終了します。したがって、プログラムを正常に終了するには、アプリケーションで SIGTERM シグナルをキャプチャして処理するディレクトリを実装する必要があります。失敗した場合、ユーザーは最後の手段として SIGKILL シグナルに頼らなければなりません。 SIGTERM と SIGKILL に加えて、特にユーザー定義の動作をサポートする SIGUSR1 のようなシグナルがあります。次のコードは、nodejs でシグナルのハンドラーを登録する方法を簡単に説明しています。

process.on('SIGTERM', function() {
  console.log('shutting down...');
});
ログイン後にコピー

シグナルの詳細については、著者が記事「linux kill コマンド」で言及しているため、ここでは繰り返しません。

コンテナ内のシグナル

Docker の stop および kill コマンドは、コンテナにシグナルを送信するために使用されます。コンテナ内のプロセス No. 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]);
  });
});
ログイン後にコピー

このアプリケーションは、SIGINT および SIGTERM シグナル用に登録されたハンドラーを備えたポート 3000 でリッスンする http サーバーです。次に、さまざまな方法でコンテナー内でプログラムを実行するときにシグナルがどのように処理されるかを紹介します。

アプリケーションはコンテナ内のプロセス 1 として使用されます

Dockerfile ファイルを作成し、上記のアプリケーションをイメージにパッケージ化します:

FROM iojs:onbuild
COPY ./app.js ./app.js
COPY ./package.json ./package.json
EXPOSE 3000ENTRYPOINT ["node", "app"]
ログイン後にコピー

方法に注意してくださいENTRYPOINT命令の書き方 この書き方ではノードがコンテナ内のプロセス1番として動作します。

次にイメージを作成します:

$ docker build --no-cache -t signal-app -f Dockerfile .
ログイン後にコピー

次にコンテナを起動してアプリケーションを実行します:

请注意 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:
ログイン後にコピー

この時点で、コンテナ内のノード アプリケーションのプロセス番号は 1 です。 :

Docker コンテナーでシグナルをキャッチする方法を知っていますか?

次に、プログラムを終了してコマンドを実行します:

$ docker container kill --signal="SIGTERM" my-app
ログイン後にコピー

この時点で、アプリケーションは期待どおりに終了します:

Docker コンテナーでシグナルをキャッチする方法を知っていますか?

アプリケーションはコンテナ内のプロセス No. 1 ではありません

次の内容でアプリケーションを起動するスクリプト ファイル app1.sh を作成します:

#!/usr/bin/env bash
node app
ログイン後にコピー

次に、次の内容を含む Dockerfile1 ファイルを作成します:

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"]
ログイン後にコピー

次にイメージを作成します:

$ docker build --no-cache -t signal-app1 -f Dockerfile1 .
ログイン後にコピー

次にコンテナを起動してアプリケーションを実行します:

$ docker run -it --rm -p 3000:3000 --name="my-app1" signal-app1
ログイン後にコピー

これでこの時点で、コンテナ内のノード アプリケーションのプロセス番号は 1:

ではなくなりました。

Docker コンテナーでシグナルをキャッチする方法を知っていますか?

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

$ docker container stop my-app1
# or
$ docker container kill --signal="SIGKILL" my-app1
ログイン後にコピー

退出应用,它们最终都是向容器中的 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
ログイン後にコピー

这个脚本文件在启动应用程序的同时可以捕获发送给它的 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"]
ログイン後にコピー

接下来创建镜像:

$ docker build --no-cache -t signal-app2 -f Dockerfile2 .
ログイン後にコピー

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

$ docker run -it --rm -p 3000:3000 --name="my-app2" signal-app2
ログイン後にコピー

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

Docker コンテナーでシグナルをキャッチする方法を知っていますか?

结论

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

相关推荐:docker入门教程

以上がDocker コンテナーでシグナルをキャッチする方法を知っていますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Dockerバージョンを読む方法 Dockerバージョンを読む方法 Apr 15, 2025 am 11:51 AM

Dockerバージョンを取得するには、次の手順を実行できます。Dockerコマンド「Docker -version」を実行して、クライアントバージョンとサーバーバージョンを表示します。 MacまたはWindowsの場合は、DockerデスクトップGUIのバージョンタブまたはDockerデスクトップメニューのバージョン情報を表示することもできます。

Dockerでミラーを作成する方法 Dockerでミラーを作成する方法 Apr 15, 2025 am 11:27 AM

Docker画像を作成する手順:ビルド命令を含むDockerFileを書きます。 Docker Buildコマンドを使用して、ターミナルで画像を作成します。画像にタグを付け、Dockerタグコマンドを使用して名前とタグを割り当てます。

Dockerデスクトップの使用方法 Dockerデスクトップの使用方法 Apr 15, 2025 am 11:45 AM

Dockerデスクトップの使用方法は? Dockerデスクトップは、ローカルマシンでDockerコンテナを実行するためのツールです。使用する手順には次のものがあります。1。Dockerデスクトップをインストールします。 2。Dockerデスクトップを開始します。 3。Docker Imageを作成します(DockerFileを使用); 4. Docker画像をビルド(Docker Buildを使用); 5。Dockerコンテナを実行します(Docker Runを使用)。

中国のDocker画像ソースを変更する方法 中国のDocker画像ソースを変更する方法 Apr 15, 2025 am 11:30 AM

国内のミラーソースに切り替えることができます。手順は次のとおりです。1。構成ファイル/etc/docker/daemon.jsonを編集し、ミラーソースアドレスを追加します。 2。保存して終了した後、Docker Service Sudo SystemCtlを再起動してDockerを再起動して、画像のダウンロード速度と安定性を改善します。

Dockerコンテナの名前を確認する方法 Dockerコンテナの名前を確認する方法 Apr 15, 2025 pm 12:21 PM

すべてのコンテナ(Docker PS)をリストする手順に従って、Dockerコンテナ名を照会できます。コンテナリストをフィルタリングします(GREPコマンドを使用)。コンテナ名(「名前」列にあります)を取得します。

Dockerからログを表示する方法 Dockerからログを表示する方法 Apr 15, 2025 pm 12:24 PM

Dockerログを表示する方法は次のとおりです。たとえば、Docker Logsコマンドを使用します。たとえば、Docker logs container_name docker execコマンドを使用して /bin /shを実行し、logファイルを表示します。 cat /var/log/container_name.log docker-compose -f docker-comのDocker ComposeのDocker-Composeログを使用します。

Dockerの画像を更新する方法 Dockerの画像を更新する方法 Apr 15, 2025 pm 12:03 PM

Docker画像を更新する手順は次のとおりです。最新の画像タグ新しい画像をプルする新しい画像は、特定のタグのために古い画像を削除します(オプション)コンテナを再起動します(必要に応じて)

Dockerによってコンテナを起動する方法 Dockerによってコンテナを起動する方法 Apr 15, 2025 pm 12:27 PM

Docker Containerの起動手順:コンテナ画像を引く:「Docker Pull [Mirror Name]」を実行します。コンテナの作成:「docker create [options] [mirror name] [コマンドとパラメーター]」を使用します。コンテナを起動します:「docker start [container name or id]」を実行します。コンテナのステータスを確認してください:コンテナが「Docker PS」で実行されていることを確認します。

See all articles