docker-compose with CIの使用-終了コードとデーモン化されたリンクされたコンテナーを処理する方法は?


87

現在、JenkinsエージェントはRailsプロジェクトごとにdocker-compose.ymlを生成してから、docker-composeupを実行します。docker-compose.ymlには、rbenvと他のすべてのRails依存関係を内部に持つメインの「web」コンテナーがあります。これは、テストPostgresDBを含むDBコンテナーにリンクされています。

問題は、実際にテストを実行して終了コードを生成する必要がある場合に発生します。CIサーバーは、テストスクリプトがexit 0を返した場合にのみデプロイされますが、docker-composeは、コンテナーコマンドの1つが失敗した場合でも、常に0を返します。

もう1つの問題は、Webコンテナーがテストの実行を完了した後でも、DBコンテナーが無期限に実行されるため、docker-compose up戻らないことです。

このプロセスにdocker-composeを使用する方法はありますか?コンテナを実行できる必要がありますが、Webコンテナが完了したら終了し、その終了コードを返します。現在、dockerを使用して手動でスタックし、DBコンテナーを起動し、-linkオプションを指定してWebコンテナーを実行しています。

回答:


76

バージョン以降1.12.0--exit-code-fromオプションできます。

ドキュメントから:

-終了コード-SERVICEから

選択したサービスコンテナの終了コードを返します。--abort-on-container-exitを意味します。


1
docker-compose1.12.0以降を使用している場合は、これが正しい方法です。多分それはあなたの場合でもあります。例は次のとおりdocker-compose up --exit-code-from test-unitです。set -eスクリプトの最初にを追加するまで、機能しなかったことに注意してください。
Adrian Antunez 2017

--exit-code-from-dただし、動作しません。これらのエラーがスローされます:using --exit-code-from implies --abort-on-container-exitおよび --abort-on-container-exit and -d cannot be combined.
ericat 2017

3
これをTravisCI で機能させることができました:travis-ci.org/coyote-team/coyote/builds/274582053これがtravis.ymlです:github.com/coyote-team/coyote/blob/master/.travis.yml #L12
subelsky 2017

2
ドキュメントはひどいです。これはどのフラグと互換性がありますか?それはたった1つのサービスですか、それとも複数のサービスに合格できますか?
worc

42

docker-compose run希望する終了ステータスを取得する簡単な方法です。例えば:

$ cat docker-compose.yml 
roit:
    image: busybox
    command: 'true'
naw:
    image: busybox
    command: 'false'
$ docker-compose run --rm roit; echo $?
Removing test_roit_run_1...
0
$ docker-compose run --rm naw; echo $?
Removing test_naw_run_1...
1

または、デッドコンテナを検査するオプションがあります。-fフラグを使用して、終了ステータスのみを取得できます。

$ docker-compose up
Creating test_naw_1...
Creating test_roit_1...
Attaching to test_roit_1
test_roit_1 exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
$ docker-compose ps -q | xargs docker inspect -f '{{ .Name }} exited with status {{ .State.ExitCode }}'
/test_naw_1 exited with status 1
/test_roit_1 exited with status 0

戻らないdbコンテナについては、使用するdocker-compose up場合はそのコンテナをsigkillする必要があります。それはおそらくあなたが望むものではありません。代わりに、docker-compose up -dデーモン化されたコンテナーを実行し、テストが完了したら手動でコンテナーを強制終了するために使用できます。リンクされたコンテナを実行するdocker-compose run 必要がありますが、SOで、バグが意図したとおりに機能しないというおしゃべりを聞いたことがあります。


docker runの問題は、-Tを指定して実行すると出力が得られないことです。失敗したビルドを検査できるように、出力が必要です。
Logan Serman 2015

1
あなたが出力を検査することができます@LoganSermandocker-compose logs
小次郎

CIビルドの進行中にログを確認できるように、実行中にこれらのログを常にSTDOUTにパイプする方法はありますか?
Logan Serman 2015

なぜあなたが一緒に走っているのか理解できないと思います-T
kojiro 2015

テストを実行するためにコンテナ内で実行するコマンドの中には、入力を要求する可能性があるものがあります。これを回避するには、-Tを指定して実行します。たとえば、Rbenvは、Rubyバージョンがすでに存在する場合に再インストールするかどうかを尋ねます。
Logan Serman 2015

23

小次郎の答えに基づいて:

docker-compose ps -q | xargs docker inspect -f '{{ .State.ExitCode }}' | grep -v '^0' | wc -l | tr -d ' '

  1. コンテナIDを取得する
  2. 各コンテナIDの最後の実行終了コードを取得します
  3. 「0」で始まらないステータスコードのみ
  4. 0以外のステータスコードのカウント数
  5. 空白を削除する

返された0以外の終了コードの数を返します。すべてがコード0で終了した場合、0になります。


からの静かでない出力を使用することもできます。docker-compose psたとえば、:docker-compose ps | grep -c "Exit 1"からの表示で「Exit1」が一致するカウントが表示docker-compose psされます(結果の要約表がきれいに印刷されます)。終了コードは「状態」列にリストされています。
eharik 2015年

これは本当に素晴らしいです。私の場合、コンテナーで実行されているテストスイートが失敗しても、コンテナーはコード1で終了しません。コード1で終了したコンテナーはないため、集計できません。これを処理する方法はありません。場合?
walkerrandophsmith 2018

9

docker-compose run手動でテストを開始するために使用する場合は、--rm、奇妙なフラグを Composeがコマンドの終了ステータスを正確に反映します。

これが私の例です:

$ docker-compose -v
docker-compose version 1.7.0, build 0d7bf73

$ (docker-compose run bash false) || echo 'Test failed!'  # False negative.

$ (docker-compose run --rm bash false) || echo 'Test failed!'  # True positive.
Test failed!

$ (docker-compose run --rm bash true) || echo 'Test failed!'  # True negative.

1
または(docker-compose run --rm ...) || exit $?エラーの場合の終了。bashスクリプトで役立ちます。
Amirreza Nasiri

8

docker wait終了コードを取得するために使用します。

$ docker-compose -p foo up -d
$ ret=$(docker wait foo_bar_1)

foo「プロジェクト名」です。上記の例では、明示的に指定しましたが、指定しない場合はディレクトリ名になります。 bardocker-compose.ymlでテスト対象のシステムに付ける名前です。

ご了承ください docker logs -fコンテナが停止すると終了するということも正しいことであることにて。だからあなたは置くことができます

$ docker logs -f foo_bar_1

docker-compose updocker waitあなたが見ることができるので、あなたのテストが実行されます。


8

--exit-code-from SERVICE そして --abort-on-container-exitすべてのコンテナーを最後まで実行する必要があるシナリオでは機能しませんが、コンテナーの1つが早期に終了した場合は失敗します。例としては、2つのテストスーツを異なるコンテナで同時に実行する場合があります。

@spenthilの提案により、docker-composeコンテナが失敗した場合に失敗するスクリプトでラップすることができます。

#!/bin/bash
set -e

# Wrap docker-compose and return a non-zero exit code if any containers failed.

docker-compose "$@"

exit $(docker-compose -f docker-compose.ci.build.yml ps -q | tr -d '[:space:]' |
  xargs docker inspect -f '{{ .State.ExitCode }}' | grep -v 0 | wc -l | tr -d '[:space:]')

次に、CIサーバーで単にに変更docker-compose up./docker-compose.sh upます。


1
他のコンテナ(データベース、Webアプリなど)が永続的に実行されるため、このスクリプトが終了セクションに到達することはありません。デタッチモードで実行すると、コンテナが起動するとすぐに終了します
Baldy 2018年

そうです、これはすべてのコンテナを最後まで実行たい場合にのみ機能します。あまり一般的ではないかもしれませんが、執筆時点では役に立ち、共有したいと思いました。
マットコール

とにかくあなたの答えに賛成してくれました。デタッチモードの各テストコンテナにDocker待機を追加すると、機能するようになりました。共有してくれてありがとう:)
Baldy 2018年

2

docker-railsを使用すると、メインプロセスに返されるコンテナーのエラーコードを指定できるため、CIサーバーが結果を判断できます。これは、Dockerを使用したレールのCIおよび開発に最適なソリューションです。

例えば

exit_code: web

コマンドの結果としてdocker-rails.ymlwebコンテナの終了コードが生成されますdocker-rails ci testdocker-rails.ymlは、標準のメタラッパーであり、docker-compose.yml開発、テスト、parallel_testsなど、さまざまな環境で同じ基本構成を継承/再利用できる可能性があります。


2

1つのDockerエンジンで同じ名前のdocker-composeサービスをさらに実行する可能性があり、正確な名前がわからない場合:

docker-compose up -d
(exit "${$(docker-compose logs -f test-chrome)##* }")

echo %? -test-chromeサービスから終了コードを返します

利点:

  • 正確なサービスが終了するのを待つ
  • コンテナ名ではなくサービス名を使用

2

次のコマンドで終了ステータスを確認できます。

echo $(docker-compose ps | grep "servicename" | awk '{print $4}')

これを始めてくれてありがとう。これが私のバージョンです(これは私にとってよりうまく機能しますb / cこの回答が書かれてからコマンド出力フォーマットが変更されたと思います)docker-compose ps | grep servicename | grep -v 'Exit 0' && echo "Automation or integration tests failed." && exit 1
–DTrejo19年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.