1つのDockerコンテナで複数のサービスを実行する方法

公開: 2022-06-30

Dockerのロゴを示す図

Dockerは、スタックのコンポーネントを分離されたコンテナーとしてパッケージ化するためのテクノロジーです。 各プロセスを独自のコンテナで実行し、コンポーネント間を明確に分割するのが一般的な方法です。 これにより、モジュール性が強化され、コンテナー化のスケーラビリティーの利点にアクセスできるようになります。

1つのコンテナ内で複数のサービスを実行したい場合もあります。 これはDockerエコシステムでは自然に発生するものではありませんが、複数の長期的なプロセスでコンテナーを作成するために使用できるいくつかの異なるアプローチを示します。

問題の特定

Dockerコンテナーは、単一のフォアグラウンドプロセスを実行します。 これは、イメージのENTRYPOINTおよびCMD命令によって定義されます。 ENTRYPOINTはイメージのDockerfile内に設定されますが、コンテナーの作成時にCMDをオーバーライドできます。 コンテナは、フォアグラウンドプロセスが終了すると自動的に停止します。

CMDから他のプロセスを起動できますが、コンテナーは元のフォアグラウンドプロセスが動作している間のみ実行を継続します。 ENTRYPOINT/CMDメカニズムを使用して、2つの独立したサービスを組み合わせたライフスパンを通じてコン​​テナーを操作可能に保つことは、直接不可能です。

1つのエントリポイントで複数のプロセスをラップする

ラッパースクリプトは、この問題の最も簡単な解決策です。 すべてのプロセスを開始し、それらが終了するのを待つスクリプトを書くことができます。 スクリプトをENTRYPOINTとして設定すると、スクリプトがコンテナーのフォアグラウンドプロセスとして実行され、ラップされたスクリプトの1つが終了するまでコンテナーが実行され続けます。

 #!/ bin / bash

/ opt / first-process&

/ opt / second-プロセス&

待つ-n

$を終了しますか?

このスクリプトは、コンテナー内の/opt/first-processおよび/opt/second-processバイナリーを開始します。 &を使用すると、各プロセスが終了するのを待たずにスクリプトを続行できます。 waitは、プロセスの1つが終了するまでスクリプトを一時停止するために使用されます。 その後、スクリプトは、終了したスクリプトによって発行されたステータスコードで終了します。

このモデルでは、コンテナーの1つが終了するまで、コンテナーはfirst-processsecond-processプロセスの両方を実行します。 その時点で、他のプロセスがまだ実行されている場合でも、コンテナーは停止します。

このスクリプトを使用するには、DockerイメージのENTRYPOINTCMDを変更して、コンテナーのフォアグラウンドプロセスにします。

 ENTRYPOINT ["/ bin / sh"]
CMD ["./path/to/script.sh"]

--initコンテナオプション

コンテナプロセスの管理に関する1つの課題は、コンテナプロセスが終了するときに効果的にクリーンアップすることです。 DockerはCMDをプロセスID1として実行し、シグナルの処理とゾンビの排除を担当します。 スクリプトにこれらの機能がない場合、孤立した子プロセスがコンテナ内に存続する可能性があります。

docker docker runコマンドには、エントリポイントを変更してtiniをPID 1として使用する--initフラグがあります。これは、 CMDを実行し、シグナル転送を処理し、ゾンビを継続的に刈り取る最小限のinitプロセス実装です。

多くのプロセスを生成することが予想され、手動でクリーンアップを処理したくない場合は、 --initを使用する価値があります。 Tiniは、コンテナ用に設計された軽量のinitフレーバーです。 systemdupstartのような本格的な代替手段よりもはるかに小さいです。

専用プロセスマネージャーの使用

管理するプロセスが多い場合、手動スクリプトはすぐに最適ではなくなります。 プロセスマネージャーを採用することは、Dockerコンテナー内でいくつかのサービスを実行するもう1つの方法です。 プロセスマネージャはENTRYPOINTになり、ワーカープロセスの開始、保守、およびクリーンアップを担当します。

このアプローチを実装するときに利用できるいくつかのオプションがあります。 supervisordは、 /etc/supervisor/conf.d/supervisord.confファイルを介して簡単に構成できる一般的な選択肢です。

 [プログラム:apache2]
command = / usr / sbin / apache2 -DFOREGROUND

[プログラム:mysqld]
command = / usr / sbin / mysqld_safe

この設定ファイルは、ApacheとMySQLを起動するようにsupervisordを設定します。 Dockerコンテナーで使用するには、必要なすべてのパッケージをイメージに追加してから、 supervisord構成ファイルを正しい場所にコピーします。 コンテナーの起動時に自動的に実行されるように、イメージのCMDとしてsupervisordを設定します。

 Ubuntuから:最新
apt-get install -yapache2mysql-serversupervisorを実行します
COPYsupervisord.conf/etc/supervisor/conf.d/supervisord.conf
ENTRYPOINT ["/ bin / sh"]
CMD ["/ usr / bin / supervisord"]

supervisord対象は継続的に実行されるため、監視対象プロセスの1つが終了したときにコンテナーを停止することはできません。 別のオプションは、この機能を備えたs6-overlayです。 これは、サービススクリプトを/etc/services.dに直接配置する宣言型サービスモデルを使用します。

 #画像にs6-overlayを追加します
https://github.com/just-containers/s6-overlay/releases/download/v3.1.0.0/s6-overlay-noarch.tar.xz/tmpを追加します
tar -C /-Jxpf/tmp/s6-overlay-noarch.tar.xzを実行します

printf "#!/ bin / shn / usr / sbin / apache2-DFOREGROUND">/etc/services.d/first-service/runを実行します
chmod +x/etc/services.d/first-service/runを実行します

#画像のエントリポイントとしてs6-overlayを使用します
ENTRYPOINT ["/ init"]

サービスディレクトリ内に実行可能なfinishスクリプトを追加して、 docker stopでコンテナの停止を処理できます。 s6-overlayは、 stopコマンドが原因でプロセスがTERMシグナルを受信すると、これらのスクリプトを自動的に実行します。

終了スクリプトは、最初の引数としてサービスの終了コードを受け取ります。 キャッチされていない信号が原因でサービスが強制終了されると、コードは256に設定されます。 スクリプトは、最終的な終了コードを/run/s6-linux-init-container-results/exitcodeに書き込む必要があります。 s6-overlayはこのファイルを読み取り、その中の値で終了します。これにより、そのコードがコンテナーの停止コードとして使用されます。

 #!/ bin / sh
echo "$ 1"> / run / s6-linux-init-container-results / exitcode

コンテナで複数のプロセスを実行する必要があるのはいつですか?

この手法は、独立したコンテナーとして実行するために分離できない緊密に結合されたプロセスで最もよく使用されます。 バックグラウンドヘルパーユーティリティまたは個々のプロセスの独自の管理を実行するモノリシックアプリケーションに依存するプログラムがある場合があります。 上記の手法は、これらのタイプのソフトウェアをコンテナ化するのに役立ちます。

コンテナ内で複数のプロセスを実行することは、可能な限り避ける必要があります。 単一のフォアグラウンドプロセスに固執することで、分離が最大化され、コンポーネントが相互に干渉するのを防ぎ、特定の部分をデバッグおよびテストする能力が向上します。 コンテナオーケストレータを使用してコンポーネントを個別にスケーリングできるため、最もリソースを消費するプロセスのインスタンスをより多く実行できる柔軟性が得られます。

結論

コンテナには通常、フォアグラウンドプロセスが1つあり、存続している限り実行されます。 このモデルは、コンテナー化のベストプラクティスに沿っており、テクノロジーから最大のメリットを得ることができます。

状況によっては、コンテナで実行するために複数のプロセスが必要になる場合があります。 すべてのイメージには最終的に単一のエントリポイントがあるため、ラッパースクリプトを作成するか、ターゲットバイナリの起動を担当するプロセスマネージャーを追加する必要があります。

プロセスマネージャーは、必要なものすべてを提供しますが、追加のパッケージと構成でイメージを肥大化します。 ラッパースクリプトはより単純ですが、ゾンビプロセスの急増を防ぐために、Dockerの--initフラグと組み合わせる必要がある場合があります。