CI와 함께 docker-compose 사용-종료 코드 및 데몬 화 된 연결된 컨테이너를 처리하는 방법은 무엇입니까?


89

지금 Jenkins 에이전트는 각 Rails 프로젝트에 대해 docker-compose.yml을 생성 한 다음 docker-compose up을 실행합니다. docker-compose.yml에는 rbenv 및 기타 모든 Rails 종속성이 내부에있는 기본 "웹"컨테이너가 있습니다. 테스트 Postgres DB를 포함하는 DB 컨테이너에 연결됩니다.

문제는 실제로 테스트를 실행하고 종료 코드를 생성해야 할 때 발생합니다. CI 서버는 테스트 스크립트가 exit 0을 반환하는 경우에만 배포되지만 docker-compose는 컨테이너 명령 중 하나가 실패하더라도 항상 0을 반환합니다.

다른 문제는 웹 컨테이너가 테스트를 실행 한 후에도 DB 컨테이너가 무기한 실행되므로 docker-compose up반환되지 않는다는 것입니다.

이 프로세스에 docker-compose를 사용할 수있는 방법이 있습니까? 컨테이너를 실행할 수 있어야하지만 웹 컨테이너가 완료되면 종료하고 종료 코드를 반환해야합니다. 지금 당장은 Docker를 사용하여 DB 컨테이너를 회전하고 --link 옵션으로 웹 컨테이너를 실행하는 데 수동으로 멈춰 있습니다.

답변:


77

버전부터 옵션을 1.12.0사용할 수 있습니다 --exit-code-from.

에서 문서 :

-서비스에서 코드 종료

선택한 서비스 컨테이너의 종료 코드를 반환합니다. --abort-on-container-exit를 의미합니다.


1
docker-compose1.12.0 이상을 사용하는 경우 올바른 방법입니다 . 어쩌면 당신의 경우 일 수도 있습니다. 예 : docker-compose up --exit-code-from test-unit. set -e스크립트 시작 부분에를 추가하기 전까지는 작동하지 않았습니다 .
아드리안 Antunez

--exit-code-from-d그래도 작동하지 않습니다 . 다음 using --exit-code-from implies --abort-on-container-exit과 같은 오류가 발생합니다.--abort-on-container-exit and -d cannot be combined.
ericat

3
Travis CI에서이 작업을 수행 할 수있었습니다 : travis-ci.org/coyote-team/coyote/builds/274582053 여기 travis.yml : github.com/coyote-team/coyote/blob/master/.travis.yml # L12
subelsky

2
문서는 끔찍합니다. 이것은 어떤 플래그와 호환됩니까? 하나의 서비스입니까 아니면 여러 번 통과 할 수 있습니까?
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 해야 하지만 지금 의도 한대로 작동하지 못하게하는 버그에 대한 이야기를 들었습니다.


도커 실행의 문제점은 -T로 실행할 때 출력을 제공하지 않으며 실패한 빌드를 검사 할 수 있도록 출력을 원한다는 것입니다.
Logan Serman

1
@LoganSerman 당신은 출력을 검사 할 수 있습니다docker-compose logs
kojiro

CI 빌드가 진행되는 동안 볼 수 있도록 실행 중에 이러한 로그를 STDOUT에 지속적으로 파이프하는 방법이 있습니까?
Logan Serman 2015

나는 당신이 왜 달리고 있는지 이해가 안 돼요-T
kojiro

테스트를 실행하기 위해 컨테이너 내부에서 실행하는 일부 명령은 입력을 요청할 가능성이 있으므로이를 방지하기 위해 -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"표시에서 "Exit 1"이 일치하는 개수 docker-compose ps를 제공합니다 (예쁘게 인쇄 된 결과 요약 테이블 제공). 종료 코드는 "상태"열에 나열됩니다.
eharik

이것은 정말 대단합니다. 내 경우 컨테이너에서 실행되는 테스트 스위트가 실패하면 컨테이너가 코드 1로 종료되지 않습니다. 코드 1로 종료 된 경우 집계 할 수 없습니다. 케이스?
walkerrandophsmith

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당신이 완료 모든 컨테이너를 실행할 수 있지만 그 중 하나가 조기 종료 경우 실패 할 필요가 시나리오에서 작업을하지 않습니다. 예를 들어 서로 다른 컨테이너에서 동시에 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
다른 컨테이너 (예 : 데이터베이스, 웹 앱)가 영구적으로 실행되므로이 ​​스크립트는 종료 섹션에 도달하지 않습니다. 분리 모드로 실행하면 컨테이너가 올라 오자마자 종료됩니다
Baldy

맞습니다 . 모든 컨테이너를 완료 하여 실행하려는 경우에만 작동합니다 . 특별히 흔하지는 않지만 글을 쓰는 시점에서 유용했고 공유 할 것이라고 생각했습니다.
매트 콜

어쨌든 당신의 답변을 찬성했습니다. 분리 모드에서 각 테스트 컨테이너에 Docker 대기를 추가하면 작동합니다. 공유해 주셔서 감사합니다 :)
Baldy

2

docker-rails를 사용하면 기본 프로세스에 반환되는 컨테이너의 오류 코드를 지정할 수 있으므로 CI 서버가 결과를 확인할 수 있습니다. Docker를 사용한 레일 개발 및 CI를위한 훌륭한 솔루션입니다.

예를 들면

exit_code: web

당신의 docker-rails.yml수율 것이다 web명령의 결과로 컨테이너 종료 코드를 docker-rails ci test. 다른 환경 (예 : 개발 대 테스트 대 parallel_tests)에 대해 동일한 기본 구성을 상속 / 재사용 할 수있는 잠재력을 제공 docker-rails.yml하는 표준에 대한 메타 래퍼 docker-compose.yml입니다.


2

하나의 도커 엔진에서 동일한 이름으로 더 많은 도커 작성 서비스를 실행할 수 있고 정확한 이름을 모르는 경우 :

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

echo %? -테스트 크롬 서비스에서 종료 코드를 반환합니다.

혜택:

  • 정확한 서비스가 종료 될 때까지 기다립니다.
  • 컨테이너 이름이 아닌 서비스 이름을 사용합니다.

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
DTrejo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.