Sử dụng docker-soạn với CI - làm thế nào để xử lý các mã thoát và các vùng chứa được liên kết daemonized?


87

Ngay bây giờ các đại lý Jenkins của chúng tôi tạo ra một docker-compost.yml cho mỗi dự án Rails của chúng tôi và sau đó chạy docker-compile lên. Docker-compos.yml có một vùng chứa "web" chính có rbenv và tất cả các phụ thuộc Rails khác của chúng tôi bên trong. Nó được liên kết với một vùng chứa DB có chứa DB Postgres thử nghiệm.

Vấn đề xảy ra khi chúng ta cần thực sự chạy các bài kiểm tra và tạo mã thoát. Máy chủ CI của chúng tôi sẽ chỉ triển khai nếu tập lệnh kiểm tra trả về lối ra 0, nhưng docker-compile luôn trả về 0, ngay cả khi một trong các lệnh vùng chứa không thành công.

Vấn đề khác là vùng chứa DB chạy vô thời hạn, ngay cả sau khi vùng chứa web chạy xong các bài kiểm tra, vì vậy docker-compose upkhông bao giờ trả lại.

Có cách nào để chúng tôi có thể sử dụng docker-soạn cho quá trình này không? Chúng tôi cần có thể chạy các vùng chứa, nhưng hãy thoát sau khi vùng chứa web hoàn tất và trả lại mã thoát của nó. Hiện tại, chúng tôi đang gặp khó khăn khi sử dụng docker theo cách thủ công để quay lên vùng chứa DB và chạy vùng chứa web với tùy chọn --link.

Câu trả lời:


76

Kể từ phiên bản 1.12.0, bạn có thể sử dụng --exit-code-fromtùy chọn.

Từ tài liệu :

--exit-code-from SERVICE

Trả lại mã thoát của vùng chứa dịch vụ đã chọn. Ngụ ý --abort-on-container-exit.


1
Đó sẽ là cách làm đúng nếu bạn đang sử dụng docker-compose1.12.0 trở lên. Có lẽ nó cũng là trường hợp của bạn. Một ví dụ có thể là: docker-compose up --exit-code-from test-unit. Lưu ý rằng nó không hoạt động với tôi cho đến khi tôi thêm một set -evào đầu tập lệnh của mình.
Adrian Antunez,

--exit-code-fromkhông hoạt động với -dmặc dù. Nó sẽ gây ra những lỗi này: using --exit-code-from implies --abort-on-container-exit--abort-on-container-exit and -d cannot be combined.
ericat 29/08/17

3
Tôi có thể làm cho điều này hoạt động trên Travis CI: travis-ci.org/coyote-team/coyote/builds/274582053 đây là travis.yml: github.com/coyote-team/coyote/blob/master/.travis.yml # L12
subelsky

2
tài liệu là tàn bạo. cờ này tương thích với những gì? nó chỉ là một dịch vụ hay bạn có thể vượt qua nó một số?
worc

42

docker-compose runlà cách đơn giản để có được trạng thái thoát mà bạn mong muốn. Ví dụ:

$ 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

Ngoài ra, bạn có tùy chọn kiểm tra các thùng chứa đã chết. Bạn có thể sử dụng -fcờ để chỉ nhận trạng thái thoát.

$ 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

Đối với vùng chứa db không bao giờ trả lại, nếu bạn sử dụng docker-compose upthì bạn sẽ cần phải ký tên vào vùng chứa đó; đó có lẽ không phải là điều bạn muốn. Thay vào đó, bạn có thể sử dụng docker-compose up -dđể chạy các vùng chứa của mình được daemonized và tắt các vùng chứa theo cách thủ công khi quá trình kiểm tra của bạn hoàn tất. docker-compose run nên chạy các vùng chứa được liên kết cho bạn, nhưng tôi đã nghe nói chuyện trên SO về một lỗi ngăn điều đó hoạt động như dự định ngay bây giờ.


Vấn đề với việc chạy docker là nó không cung cấp bất kỳ đầu ra nào khi chạy với -T, và chúng tôi muốn đầu ra để chúng tôi có thể kiểm tra các bản dựng bị lỗi.
Logan Serman

1
@LoganSerman bạn có thể kiểm tra kết quả đầu ra vớidocker-compose logs
kojiro

Có cách nào để liên tục chuyển các nhật ký đó đến STDOUT trong quá trình chạy để chúng tôi có thể thấy nó trong khi quá trình xây dựng CI đang diễn ra không?
Logan Serman

Tôi đoán tôi không hiểu tại sao bạn lại chạy với-T
kojiro

Một số lệnh chúng tôi chạy bên trong vùng chứa để chạy thử nghiệm có khả năng yêu cầu đầu vào, chúng tôi muốn chạy với -T để tránh điều này. Ví dụ, Rbenv hỏi bạn có muốn cài đặt lại phiên bản Ruby nếu nó đã tồn tại hay không.
Logan Serman

23

Dựa trên câu trả lời của kojiro:

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

  1. nhận ID vùng chứa
  2. lấy mã thoát lần chạy cuối cùng cho mỗi ID vùng chứa
  3. chỉ những mã trạng thái không bắt đầu bằng '0'
  4. đếm số mã trạng thái khác 0
  5. cắt bỏ khoảng trắng

Trả về số lượng mã thoát không phải 0 đã được trả lại. Sẽ là 0 nếu mọi thứ thoát ra với mã 0.


Bạn cũng có thể sử dụng đầu ra không yên tĩnh từ docker-compose ps, ví dụ: docker-compose ps | grep -c "Exit 1"sẽ cung cấp cho bạn số lượng mà "Lối ra 1" được khớp trong màn hình từ docker-compose psđó (cung cấp bảng kết quả tóm tắt được in đẹp mắt). Các mã thoát được liệt kê trong cột "Trạng thái".
eharik

Điều này thực sự tuyệt vời. Trong trường hợp của tôi, bộ thử nghiệm không thành công khi chạy trong các vùng chứa không làm cho các vùng chứa thoát ra với mã là 1. Tôi không thể tổng hợp nếu có bất kỳ thoát nào được thoát với mã là 1 vì không ai trong số họ làm vậy .... vụ án?
walkerrandophsmith

9

Nếu bạn sẵn sàng sử dụng docker-compose runđể bắt đầu các thử nghiệm của mình theo cách thủ công, thì việc thêm --rmcờ, kỳ lạ thay, khiến Soạn phản ánh chính xác trạng thái thoát lệnh của bạn.

Đây là ví dụ của tôi:

$ 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
Hoặc (docker-compose run --rm ...) || exit $?để chấm dứt trong trường hợp do lỗi. Hữu ích trong các tập lệnh bash.
Amirreza Nasiri

8

Sử dụng docker waitđể lấy mã thoát:

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

foolà "tên dự án". Trong ví dụ trên, tôi đã chỉ định nó một cách rõ ràng, nhưng nếu bạn không cung cấp nó, đó là tên thư mục. barlà tên bạn đặt cho hệ thống đang được kiểm tra trong docker-compost.yml.

Lưu ý rằng điều đó docker logs -fcũng làm đúng, thoát ra khi vùng chứa dừng lại. Vì vậy, bạn có thể đặt

$ docker logs -f foo_bar_1

giữa docker-compose updocker waitđể bạn có thể xem các thử nghiệm của mình chạy.


8

--exit-code-from SERVICE--abort-on-container-exitkhông hoạt động trong các tình huống mà bạn cần chạy tất cả các vùng chứa để hoàn thành, nhưng không thành công nếu một trong số chúng thoát sớm. Một ví dụ có thể là nếu chạy đồng thời 2 bộ quần áo thử nghiệm trong các thùng chứa khác nhau.

Với gợi ý của @pendhil, bạn có thể bọc docker-composetrong một tập lệnh sẽ không thành công nếu có bất kỳ vùng chứa nào.

#!/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:]')

Sau đó, trên máy chủ CI của bạn chỉ cần thay đổi docker-compose upthành ./docker-compose.sh up.


1
tập lệnh này không bao giờ đến phần thoát vì các vùng chứa khác (chẳng hạn như cơ sở dữ liệu, ứng dụng web) chạy vĩnh viễn. chạy trong chế độ tách nó ra khỏi càng sớm càng container đang lên
Baldy

Đúng vậy, điều này chỉ hoạt động nếu bạn muốn chạy tất cả các vùng chứa đến khi hoàn thành. Có lẽ không đặc biệt phổ biến, nhưng nó hữu ích cho tôi tại thời điểm viết bài và tôi nghĩ tôi sẽ chia sẻ nó.
Matt Cole

Dù sao cũng đã ủng hộ câu trả lời của bạn vì nó đã giúp tôi gần hết con đường đó! Thêm Docker đợi trên mỗi vùng chứa thử nghiệm ở chế độ tách rời đã làm cho nó hoạt động. Cảm ơn vì đã chia sẻ :)
Baldy

2

docker-rails cho phép bạn chỉ định mã lỗi của vùng chứa nào được trả về quy trình chính, vì vậy máy chủ CI của bạn có thể xác định kết quả. Nó là một giải pháp tuyệt vời cho CI và phát triển cho đường ray với docker.

Ví dụ

exit_code: web

trong ý chí của bạn docker-rails.ymlmang lại webmã thoát vùng chứa là kết quả của lệnh docker-rails ci test. docker-rails.ymlchỉ là một trình bao bọc meta xung quanh tiêu chuẩn docker-compose.ymlcung cấp cho bạn khả năng kế thừa / sử dụng lại cùng một cấu hình cơ sở cho các môi trường khác nhau, tức là phát triển so với thử nghiệm và song song_tests.


2

Trong trường hợp bạn có thể chạy nhiều dịch vụ soạn thảo docker có cùng tên trên một công cụ docker và bạn không biết tên chính xác:

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

echo %? - trả về mã thoát khỏi dịch vụ test-chrome

Những lợi ích:

  • đợi dịch vụ chính xác thoát ra
  • sử dụng tên dịch vụ, không phải tên vùng chứa

2

Bạn có thể thấy trạng thái thoát với:

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

Cảm ơn vì đã bắt đầu. Dưới đây là phiên bản của tôi về cái này (mà làm việc tốt hơn cho tôi b / c tôi nghĩ định dạng đầu ra lệnh đã thay đổi kể từ khi câu trả lời này đã được viết) -docker-compose ps | grep servicename | grep -v 'Exit 0' && echo "Automation or integration tests failed." && exit 1
DTrejo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.