サービスを開始した後、Dockerコンテナーを実行し続ける方法は?


155

私がやろうとしていることと同じように見える一連のチュートリアルを見てきましたが、何らかの理由でDockerコンテナーが終了します。基本的に、私はDockerコンテナー内にWebサーバーといくつかのデーモンをセットアップしています。この最後の部分はrun-all.sh、DockerfileのCMDで実行するというbashスクリプトを使用して行います。run-all.shこのようになります:

service supervisor start
service nginx start

そして、次のようにDockerfile内で開始します。

CMD ["sh", "/root/credentialize_and_run.sh"]

手動で実行すると(つまり、-i -t / bin / bashを使用してイメージにアクセスすると)すべてのサービスが正しく起動し、イメージを実行するとすべてが正しく実行されているように見えますが、一度終了すると、プロセスの起動が完了します。プロセスを無期限に実行したいのですが、私が理解している限り、コンテナはこれを実行するために実行し続ける必要があります。それにもかかわらず、実行するとdocker ps -a、次のようになります。

➜  docker_test  docker ps -a
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS                      PORTS               NAMES
c7706edc4189        some_name/some_repo:blah   "sh /root/run-all.sh   8 minutes ago       Exited (0) 8 minutes ago                        grave_jones

何ができますか?なぜ存在するのですか?私はbashスクリプトの最後にwhileループを置くだけでそれを維持できることを知っていますが、終了しないようにする正しい方法は何ですか?


1
サービスのポートを外部に公開していますか(docker runの-pオプション)?(もちろん、これで終了するのを防ぐことはできません)
リバマー2016

1
DockerfileでENTRYPOINTを使用していて、ENTRYPOINTで定義されたスクリプト(私のinitスクリプト)を実行した後、それがログに表示されましたが、コンテナーが終了しているように見えました。そのため、ENTRYPOINTの代わりに、RUNコマンドを使用してスクリプトを実行しましたが、コンテナーはまだバックグラウンドで実行されています。
ypahalajani

回答:


49

これは、実際にDockerコンテナーを設計する方法ではありません。

Dockerコンテナを設計するときは、実行中のプロセスが1つだけになるように構築する必要があります(つまり、Nginx用に1つのコンテナと、実行中のスーパーバイザまたはアプリ用に1つのコンテナが必要です)。さらに、そのプロセスはフォアグラウンドで実行する必要があります。

コンテナーは、プロセス自体が終了すると「終了」します(あなたの場合、そのプロセスはbashスクリプトです)。


ただし、Dockerコンテナーで実際に複数のサービスを実行する必要がある(または希望する)場合は、疑似初期プロセスとして使用される「Docker Base Image」から開始することを検討してくださいrunitrunitNginxとスーパーバイザーの実行中はオンラインのままです)。フォアグラウンドで他のプロセスが処理を行います。

彼らは実質的なドキュメントを持っているので、あなたが合理的に簡単にしようとしていることを達成できるはずです。


1
サービスを1つだけ実行する必要がある理由を説明できますか?必要に応じてnginxをスーパーバイザーに追加できますが、なぜこれが必要なのかはわかりません。
Eli

3
@Eli簡単に言えば、これがDockerの動作方法です。Dockerはコンテナーごとに1つのプロセス(およびその子)のみを実行します。このプロセスを実際のアプリケーションプロセスにすることをお勧めします(そのため、存在する場合はDockerが認識します)が、実際にそのプロセスとして監視プログラムを使用できます。オプションを使用して、フォアグラウンドで実行する(つまり、デーモン化しない)ようにスーパーバイザーを構成する必要があることに注意してください--nodaemon
Thomas Orozco、2014

1
@Eli このDockerブログの投稿では、複数のプロセスを実行すること(そして、大まかに言って、コンテナーを「小さなVPS」として表示すること)は最適とは言えない場合があります。あなたの場合、コメントスレッドは実際のブログ投稿よりも関連性が高いでしょう。
Thomas Orozco、2014

1
Dockerベースイメージは、ubuntuを使用する真面目な企業はほとんどなく、代わりにRHEL / Centosツリーを使用するため、多くの企業の問題に対する恐ろしいソリューションです。
ソフトウェアエンジニア

9
「真面目な会社はほとんどない」と言い表せないようです。OSの選択は、完全にユースケースに基づいているようです。特定の会社には、内部の開発者の使用、内部の従業員の使用、販売サポート、ステージング、POC、そして最終的には生産(そしてそれさえ曖昧な用語です)を含む多くの異なる環境があります。OPがそのユースケースについて言及しているとは思いませんが(申し訳ありませんが)、この種のコメントは、理由について議論のない非常に意見の高い情報を広めるタイプのようです。
ジョンカレル2018年

154

Dockerfileを使用している場合は、以下を試してください。

ENTRYPOINT ["tail", "-f", "/dev/null"]

(明らかにこれは開発のみを目的としています。例えば、nginx ...などのプロセスを実行していない限り、コンテナを存続させる必要はありません。)


5
私は使用してCMD["sleep", "1d"]いましたが、あなたの解決策はより良いようです
ジョージ・プリゴロプロス2018

@GeorgiosPligoropoulosこれはその行に留まります。おそらくバックグラウンドで実行するとうまくいくでしょう
Prashanth Sams

5
も使用できますCMD["sleep", "infinity"]
ロメイン

5
または「猫」ですが、人々はそれが動物虐待だと言うかもしれません。xD
lawphotog

エントリポイントスクリプトはで終了できますexec tail -f /dev/nulltail、エントリポイントとして使用するのは間違った答えです。
Torsten Bronger

86

同じ問題が発生しましたが、-tand -dフラグを指定してコンテナーを実行している場合、コンテナーが引き続き実行されることがわかりました。

docker run -td <image>

フラグの機能はdocker run --help次のとおりです(に従って):

-d, --detach=false         Run container in background and print container ID
-t, --tty=false            Allocate a pseudo-TTY

最も重要なのは-t旗です。-dコンテナーをバックグラウンドで実行するだけです。


3
これは再現できません。例を挙げていただけますか?これが機能するために必要なDockerfileについて何か特定のもの(例:CMD)がありますか
Matheus Santana

2
これは私にはうまくいきませんでした。コマンドを使用してdocker logs <image>、Dockerコンテナーが終了する原因となったエラーであることを確認しました。終了ステータスがあり0、最後の出力は私のことをconfimationあるlighttpdサーバが稼働している:[ ok ] Starting web server: lighttpd.
OB1

私はしばらくの間Dockerを使用していません。そのため、コマンドラインインターフェイスが変更され、このコマンドが機能しなくなった可能性があります。
arne.z 2017

4
これが実際に最新のdockerバージョンで動作していることを確認できます。後でこのセッションに接続する場合は、-ditを使用しても機能します。
ジョンハミルトン

1
スクリプトを@Longする端末を受け入れない、追加exec bashまたはexec shbashがインストールされていない場合、start.shの終わりまで。次に、-tフラグを使用できます
123

43

それが終了する理由は、シェルスクリプトが最初にPID 1として実行され、それが完了するとPID 1がなくなり、DockerはPID 1が実行されている間のみ実行されるためです。

デーモン化しないように指示された「-n」フラグを指定して実行すると、スーパーバイザーを使用してすべてを実行できるため、最初のプロセスのままになります。

CMD ["/usr/bin/supervisord", "-n"]

そして、あなたのsupervisord.conf:

[supervisord]
nodaemon=true

[program:startup]
priority=1
command=/root/credentialize_and_run.sh
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false
startsecs=0

[program:nginx]
priority=10
command=nginx -g "daemon off;"
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.log
autorestart=true

次に、他のプロセスをいくつでも持つことができ、スーパーバイザは必要に応じてそれらの再起動を処理します。

そうすれば、nginxとphp5-fpmが必要になる可能性があり、それらを別々にしても意味がない場合に、supervisordを使用できます。


PID 1が終了するとドッカーコンテナーが実行を停止した場合、ドキュメントのどこに記載されていますか?
8oh8

@ 8oh8基本的にはプロセスの名前空間が機能する方法です。「すべてのコンテナーの基礎となるもの」ほど、Docker固有ではありません。man7.org/linux/man-pages/man7/pid_namespaces.7.htmlから:If the "init" process of a PID namespace terminates, the kernel terminates all of the processes in the namespace via a SIGKILL signal. This behavior reflects the fact that the "init" process is essential for the correct operation of a PID namespace.
dannysauer

40

catブロ@ Sa'adで述べられているように、引数なしで単純に実行して、コンテナを単に動作させ続けることができます[実際には何もせずにユーザー入力を待つ](JenkinsのDockerプラグインも同じことを行います)


私の回答に加えて:しかし、Docker-compose(デーモン化されていない)がコンテナーのワークフローを示すために使用されていることを理解してください。したがって、開始されたサービスのログファイルを追跡するのに便利です。歓声
Serge Velikanov

1
またはcat。jenkinのdockerプラグインはそうします。
Sa'ad

12

daemon off;nginx.confに追加するかCMD ["nginx", "-g", "daemon off;"]、公式のnginxイメージに従って実行するようにしてください

次に、以下を使用して、スーパーバイザーをサービスとして実行し、nginxをフォアグラウンドプロセスとして実行して、コンテナーが終了しないようにします

service supervisor start && nginx

場合によっては、コンテナーに複数のプロセスが必要になることがあります。そのため、コンテナーに1つのプロセスのみを強制することは機能せず、デプロイメントでさらに問題が発生する可能性があります。

したがって、トレードオフを理解し、それに応じて決定を行う必要があります。


7

動機:

Dockerコンテナ内で複数のプロセスを実行しても問題はありません。軽量のVMとしてdockerを使用したい場合-そうです。アプリケーションをマイクロサービスに分割したい人もいます。私が考える:1つのコンテナー内のLAMPスタック?ただ素晴らしい。

答え:

スティックの良いベースイメージのようなのPhusionベースイメージ。他にもあるかもしれません。コメントしてください。

そして、これはまだ監督者のためのもう一つの懇願です。なぜなら、phusionベースのイメージは、cronやロケールのセットアップなどの他のいくつかのほかにスーパーバイザーを提供しているからです。このような軽量のVMを実行するときにセットアップしたいもの。それだけの価値がある場合は、コンテナーへのssh接続も提供します。

この基本的なdocker runステートメントを発行すると、phusionイメージ自体が起動して実行を継続します。

moin@stretchDEV:~$ docker run -d phusion/baseimage
521e8a12f6ff844fb142d0e2587ed33cdc82b70aa64cce07ed6c0226d857b367
moin@stretchDEV:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS
521e8a12f6ff        phusion/baseimage   "/sbin/my_init"     12 seconds ago      Up 11 seconds

またはまったくシンプル:

ベースイメージが適切でない場合...迅速なCMDで実行を継続するには、bashで次のようなものを想定します。

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

または、busyboxの場合:

CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"

すぐ終了するため、これは便利ですdocker stop。単純であるsleepcat、コンテナが終了するまで数秒かかります。


centos7ベースイメージをカスタマイズしてPostgreSQL 11をロードしました。/usr/pgsql-11/bin/pg_ctlを呼び出して開始しますが、サーバーが実行されるとpg_ctlが終了します。トラップを使用するというあなたの提案はうまくいきました。それは私のスクリプトpgstartwait.shの最後の行です
Alchemistmatt

6

ngnixプロセスのPIDを変数(たとえば、$ NGNIX_PID)にキャプチャし、エントリポイントファイルの最後に行います。

wait $NGNIX_PID 

このようにして、コンテナーはngnixがアクティブになるまで実行する必要があります。ngnixが停止すると、コンテナーも停止します


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.