web-dev-qa-db-ja.com

ドッカーでのスーパーバイザーの使用

監督者と港湾労働者の使用については質問していませんが、自分の理解を検証したいだけです。

Dockerは、実行時に単一のプロセスを実行することを理解しています。また、スーパーバイザーは、コンテナ内で複数のプロセスを実行する必要があるときに使用されます。

コンテナがベースイメージから開始され、いくつかのサービスがインストールされ、コンテナがすべてスーパーバイザなしで新しいイメージを作成するようにコミットされるいくつかの例を見てきました。

したがって、私の基本的な疑問は、両方のアプローチの違いは何でしたか。

私の理解では、Dockerコンテナが停止すると、PID 1のプロセスにkill信号を送信し、PID 1は子プロセスを管理し、スーパーバイザによって行われているすべての子を停止しますが、スーパーバイザなしで複数のプロセスをインストールできますdocker runが発行され、コンテナが停止すると、PID 1のみがシグナルを送信し、他の実行中のプロセスは正常に停止しません。

supervisordの使用に関する私の理解がどれだけ正しいかを確認してください。

33
user3275095

スーパーバイザーなしで複数のプロセスをインストールできますが、docker runが発行されたときに実行できるプロセスは1つだけで、コンテナーが停止するとPID 1のみがシグナルを送信し、他の実行中のプロセスは正常に停止しません。

はい。ただし、メインプロセスの実行方法(フォアグラウンドまたはバックグラウンド)、および子プロセスの収集方法によって異なります。

これは、「 Dockerコンテナー内の信号のトラップ 」で詳しく説明されています。

_docker stop_は、SIGTERM信号を送信して実行中のコンテナを停止し、メインプロセスに処理させ、猶予期間が経過したらSIGKILLを使用してアプリケーションを終了します。

コンテナに送信される信号は、実行中のメインプロセス(PID 1)によって処理されます。

アプリケーションがフォアグラウンドにある場合、つまりアプリケーションがコンテナ(PID1)のメインプロセスである場合、信号を直接処理できます。

しかし:

シグナルを送信するプロセスはバックグラウンドプロセスであり、シグナルを直接送信することはできません。この場合の1つの解決策は、シェルスクリプトをエントリポイントとして設定し、そのスクリプト内のすべての信号処理を調整することです。

この問題の詳細については、「 DockerおよびPID 1ゾンビの収獲問題

Unixは、終了ステータスを収集するために、親プロセスが子プロセスの終了を明示的に「待機」するように設計されています。ゾンビプロセスは、waitpid()ファミリのシステムコールを使用して、親プロセスがこのアクションを実行するまで存在します。

ゾンビを排除するために子プロセスでwaitpid()を呼び出すアクションは、「リーピング」と呼ばれます。

initプロセス-PID 1-には特別なタスクがあります。そのタスクは、孤立した子プロセスを「採用」することです。

https://blog.phusion.nl/wp-content/uploads/2015/01/adoption.png

オペレーティングシステムは、initプロセスが採用された子も刈り取ることを期待しています

Dockerの問題:

多くの人がコンテナ内で1つのプロセスのみを実行していることがわかり、この単一のプロセスを実行すると完了したと考えています。
しかし、ほとんどの場合、このプロセスは適切なinitプロセスのように動作するようには書かれていません。
それは、採用されたプロセスを適切に刈り取る代わりに、おそらく別のinitプロセスがその仕事をすることを期待していることです。

_phusion/baseimage-docker_ のようなイメージを使用すると、メインプロセスをinit準拠に保ちながら、1つ(または複数)のプロセスを管理できます。

マルチプロセス管理の場合、runit)ではなく supervisord を使用します。

Runit は、収獲問題を解決するためのものではありません。むしろ、複数のプロセスをサポートすることです。セキュリティのために、複数のプロセスが推奨されます(プロセスとユーザーの分離を通じて)。
Runitは Supervisord よりも少ないメモリを使用します。これは、RunitがCで記述され、Pythonで監視されるためです。

そのイメージには、「リーピング」問題を処理する _my_init_スクリプト が含まれています。

Baseimage-dockerでは、単一のコンテナで複数のプロセスを実行することをお勧めします。ただし、必ずしも複数のサービスではありません。
論理サービスは複数のOSプロセスで構成でき、簡単にそれを行うための機能を提供します。

50
VonC

Docker 1.12の2016年9月の更新(2016年第4四半期/ 2017年第1四半期)

Arnaud Porterie just twitted

[????]単にマージ:docker run --initで、 Rick Grimes がすべてのゾンビを処理します。

eabae09をコミット

PR 26061 を参照してください: "ゾンビの戦闘と信号処理のための初期化プロセスを追加"(および PR 26736

これにより、ゾンビと戦うための小さなCバイナリが追加されます。/dev/initの下にマウントされ、ユーザーが指定した引数の前に追加されます。後方互換性のためにデフォルトで無効になっているため、デーモンフラグdockerd --initを使用して有効にします。

デーモンオプションをオーバーライドするか、docker run --init=true|falseを使用してコンテナごとにこれを指定することもできます。

これをテストするには、コンテナのpid 1としてこのようなプロセスを実行し、実行中にコンテナに表示される余分なゾンビを確認します。

int main(int argc, char ** argv) {
    pid_t pid = fork();
    if (pid == 0) {
        pid = fork();
        if (pid == 0) {
            exit(0);
        }
        sleep(3);
        exit(0);
    }
    printf("got pid %d and exited\n", pid);
    sleep(20);
}

dockerデーモン にオプションが追加されました

--init

コンテナ内でinitを実行してシグナルを転送し、プロセスを取得します

17
VonC