exit code 0...
毎度毎度あーでもないこーでもないと書いてみて、オラッとupした時にこれが出ると本当に頭が飛び散っていきそうな気持ちになります。これはそんな最近ハマったexit code 0の状態をどう突破したかの話です。
commandのフィールドの特性
commandフィールドは、文字通り、コマンドを設定してあげると、docker-compose upした際にコンテナをイメージから立ち上げてくれる時に記述されたコマンドを自動的に実行してくれるものですが、コマンドを指定する、とだけで覚えてしまうと、どんなコマンドでも自動的に実行してくれそうな気がしてしまいます。
確かに記述したコマンドは全て実行してくれるのですが、コマンドを実行し終わった後、コンテナを終了させてしまうという隠れ機能があります。故に、dockerが実行処理のプロセスをhookできるようなコマンドを指定してあげないと、コマンドの実行終了時に同時にコンテナまで終了してしまうので、いつまでたってもupできない状態が続きます。
具体的にdockerはコマンドのどの部分を使って処理しているのか
簡単にいうと、docker は実行したコマンドのプロセスidを見ています。そして、コマンドを使うのと、バイナリファイル(bin等)を直接打つのとでは生み出されるプロセスidが異なるのです。
つまり、
$ sudo service httpd start
とした場合httpdのプロセスは一切見ておらず、service
のプロセスを見ています。
何故このような事が起こるのかというと、serviceコマンドを打った時と打たない時の違いは、コマンドの定義として、コマンドサーチパスを使用しているかしていないかの違いが存在します。今回のserviceコマンドを含め、多くのコマンドは実行ファイルに紐づいたパスを叩きに行くものが存在します。(他にもシェルに内包されたビルトイン型のコマンドやエイリアスで設定されたコマンドなどもありますが今回は関係ないのでこの2つの説明は省略します。)
コマンドサーチパスを使用するserviceコマンドを未使用の場合、/usr/sbin/httpd
の実行ファイルのあるパスを直に叩きますが、
$ sudo service httpd start
を実行すると一旦、serviceコマンドのバイナリファイルに渡される形になっています。dockerは、serviceで叩かれたコマンドのプロセスid(以下pid)を検知するので、バックグラウンドの場合実処理のpidはserviceのパスを叩いた処理であるため、docker側で実際のバイナリファイルを実行したpidを検知できないということになります。
例えば、下記のようなcommandフィールドは一見、httpdを起動させたコンテナを立ててくれそうですが、exit code 0を出してしまいます。serviceコマンド自体のプロセスidをhookしてしまうからです。
web:
build: .
command: service httpd restart
environment:
BUNDLE_APP_CONFIG: /web/.bundle
volumes:
- .:/app-space/
ports:
- "3000:3000"
depends_on:
- db
正解は下記の第一のプロセスでバイナリファイルが実行されると認識できるコマンドを使う必要があります。
web:
build: .
command: ["/bin/sh", "-c", "yarn install && cd product_name && bundle exec rails s -p 3000 -b '0.0.0.0'"]
environment:
BUNDLE_APP_CONFIG: /web/.bundle
volumes:
- .:/app-space/
ports:
- "3000:3000"
depends_on:
- db