1つのDockerコンテナで複数のサービスを実行する方法
公開: 2022-06-30Dockerは、スタックのコンポーネントを分離されたコンテナーとしてパッケージ化するためのテクノロジーです。 各プロセスを独自のコンテナで実行し、コンポーネント間を明確に分割するのが一般的な方法です。 これにより、モジュール性が強化され、コンテナー化のスケーラビリティーの利点にアクセスできるようになります。
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-process
とsecond-process
プロセスの両方を実行します。 その時点で、他のプロセスがまだ実行されている場合でも、コンテナーは停止します。
このスクリプトを使用するには、DockerイメージのENTRYPOINT
とCMD
を変更して、コンテナーのフォアグラウンドプロセスにします。
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フレーバーです。 systemd
やupstart
のような本格的な代替手段よりもはるかに小さいです。
専用プロセスマネージャーの使用
管理するプロセスが多い場合、手動スクリプトはすぐに最適ではなくなります。 プロセスマネージャーを採用することは、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
フラグと組み合わせる必要がある場合があります。