Docker-compose'u CI ile kullanma - çıkış kodları ve arka planda çalışan bağlantılı konteynerlerle nasıl başa çıkılır?


90

Şu anda, Jenkins temsilcilerimiz Rails projelerimizin her biri için bir docker-compose.yml oluşturuyor ve ardından docker-compose up çalıştırıyor. Docker-compose.yml, içinde rbenv ve diğer tüm Rails bağımlılıklarının bulunduğu bir ana "web" kabına sahiptir. Test Postgres DB'yi içeren bir DB kapsayıcısına bağlıdır.

Sorun, testleri gerçekten çalıştırmamız ve çıkış kodları oluşturmamız gerektiğinde ortaya çıkar. CI sunucumuz yalnızca test komut dosyası çıkış 0'ı döndürürse devreye girer, ancak docker-compose, kapsayıcı komutlarından biri başarısız olsa bile her zaman 0 döndürür.

Diğer bir sorun da, DB kapsayıcısının, web kapsayıcısı testleri çalıştırdıktan sonra bile süresiz olarak çalışmasıdır, bu nedenle docker-compose upasla geri dönmez.

Bu işlem için docker-compose kullanmanın bir yolu var mı? Kapsayıcıları çalıştırabilmemiz gerekir, ancak web kapsayıcısı tamamlandıktan ve çıkış kodunu döndürdükten sonra çıkın. Şu anda, DB kapsayıcısını döndürmek ve web kapsayıcısını --link seçeneğiyle çalıştırmak için docker'ı manuel olarak kullanıyoruz.

Yanıtlar:


78

Versiyondan bu yana seçeneği 1.12.0kullanabilirsiniz --exit-code-from.

Gönderen belgeler :

- servis-çıkış kodu

Seçili servis kabının çıkış kodunu döndür. --Abort-on-container-exit anlamına gelir.


1
docker-compose1.12.0 ve üstünü kullanıyorsanız bunu yapmanın doğru yolu bu olmalıdır . Belki de senin davan. Bir örnek olabilir: docker-compose up --exit-code-from test-unit. Senaryomun set -ebaşına bir ekleyene kadar benim için çalışmadığını unutmayın .
Adrian Antunez

--exit-code-fromyine de çalışmıyor -d. Bu hataları atacak: using --exit-code-from implies --abort-on-container-exitve --abort-on-container-exit and -d cannot be combined.
ericat


2
belgeler iğrenç. bu hangi bayraklarla uyumludur? bu sadece bir hizmet mi yoksa birkaçını iletebilir misin?
worc

42

docker-compose runarzu ettiğiniz çıkış durumlarını almanın basit yoludur. Örneğin:

$ 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

Alternatif olarak, ölü kapları inceleme seçeneğiniz de vardır . Yalnızca -fçıkış durumunu almak için bayrağı kullanabilirsiniz .

$ 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

Asla geri dönmeyen db konteynerine gelince, kullanıyorsanız docker-compose upo konteyneri sigkill etmeniz gerekecek; Muhtemelen istediğin bu değil. Bunun yerine, docker-compose up -dkapsayıcılarınızı daemonize etmek için kullanabilir ve testiniz tamamlandığında kapsayıcıları manuel olarak öldürebilirsiniz. docker-compose run gerektiğini sizin için bağlantılı konteyner çalıştırmak, ancak bir hata şu anda olması gerektiği gibi çalıştığından olmasını engelliyor hakkında SO üzerinde sohbet eden duymuş.


Docker run ile ilgili problem, -T ile çalıştırıldığında herhangi bir çıktı vermemesi ve başarısız derlemeleri inceleyebilmemiz için çıktıyı istiyoruz.
Logan Serman

1
@LoganSerman ile çıktıyı inceleyebilirsinizdocker-compose logs
kojiro

CI oluşturma işlemi devam ederken görebilmemiz için çalışma sırasında bu günlükleri STDOUT'a sürekli olarak aktarmanın bir yolu var mı?
Logan Serman

Sanırım neden koştuğunuzu anlamıyorum-T
kojiro

Testleri çalıştırmak için konteynerin içinde çalıştırdığımız bazı komutların girdi isteme potansiyeli var, bundan kaçınmak için -T ile çalıştırmak istiyoruz. Örneğin Rbenv, eğer zaten mevcutsa bir Ruby sürümünü yeniden yüklemek isteyip istemediğinizi sorar.
Logan Serman

24

Kojiro'nun cevabına dayanarak:

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

  1. kapsayıcı kimliklerini al
  2. her kapsayıcı kimliği için son çalıştırma çıkış kodunu al
  3. yalnızca '0' ile başlamayan durum kodları
  4. 0 olmayan durum kodlarının sayısını say
  5. beyaz alanı kırp

0 olmayan kaç çıkış kodunun döndürüldüğünü döndürür. Her şey 0 koduyla çıkılırsa 0 olur.


docker-compose psÖrneğin, sessiz olmayan çıktıyı da kullanabilirsiniz : docker-compose ps | grep -c "Exit 1"size ekranda "Çıkış 1" in eşleştiği yerin sayısını verir docker-compose ps(sonuçların oldukça basılmış bir özet tablosunu sağlar). Çıkış kodları "Durum" sütununda listelenmiştir.
eharik

Bu gerçekten harika. Benim durumumda, kapsayıcılarda çalışan test paketinin başarısız olması, kapsayıcıların 1 koduyla çıkmasına neden olmaz. Hiçbiri yapmadığından, herhangi biri 1 koduyla çıkarsa bir araya gelemem .... Bunu nasıl halledeceğime dair herhangi bir fikir durum?
2018

9

docker-compose runTestlerinizi manuel olarak başlatmak için kullanmak istiyorsanız --rm, garip bir şekilde bayrağı eklemek Compose'un komutunuzun çıkış durumunu doğru şekilde yansıtmasına neden olur.

İşte örneğim:

$ 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
Veya (docker-compose run --rm ...) || exit $?hata durumunda fesih için. Bash betiklerinde kullanışlıdır.
Amirreza Nasiri

8

docker waitÇıkış kodunu almak için kullanın :

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

foo"proje adı" dır. Yukarıdaki örnekte bunu açıkça belirttim, ancak siz sağlamazsanız, dizin adıdır. bardocker-compose.yml dosyanızda test edilen sisteme verdiğiniz addır.

docker logs -fKonteyner durduğunda çıkmanın da doğru olanı yaptığını unutmayın . Böylece koyabilirsin

$ docker logs -f foo_bar_1

docker-compose upve arasında. docker waitBöylece testlerinizin çalışmasını izleyebilirsiniz.


8

--exit-code-from SERVICEve --abort-on-container-exittüm kapsayıcıları sonuna kadar çalıştırmanız gereken senaryolarda çalışmayın, ancak bunlardan biri erken çıkarsa başarısız olur. Bir örnek, farklı konteynerlerde aynı anda 2 test takımı çalıştırılması olabilir.

@ Spenthil'in önerisiyle, docker-composeherhangi bir kap varsa başarısız olacak bir komut dosyasını sarmalayabilirsiniz .

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

Sonra CI sunucuda basitçe değiştirmek docker-compose upiçin ./docker-compose.sh up.


1
bu komut dosyası, diğer kapsayıcılar (veritabanları, web uygulamaları gibi) sürekli olarak çalıştığı için asla çıkış bölümüne ulaşmaz. bağımsız modda çalışıyor, konteyner yukarı kalkar
Baldy

Doğru, bu yalnızca tüm kapsayıcıları sonuna kadar çalıştırmak istiyorsanız işe yarar . Muhtemelen pek yaygın değil, ama yazarken benim için yararlıydı ve paylaşacağımı düşündüm.
Matt Cole

Yine de cevabını oyladı, çünkü beni oraya en çok götürdü! Bağımsız modda her test konteynerinde Docker bekleme eklenmesi, çalışmasını sağladı.
Baldy

2

docker-rails , ana işleme hangi kapsayıcı hata kodunun döndürüleceğini belirlemenize olanak tanır, böylece CI sunucusu sonucu belirleyebilir. Docker'lı raylar için CI ve geliştirme için harika bir çözümdür.

Örneğin

exit_code: web

içinde komutun bir sonucu olarak konteyner çıkış kodunu docker-rails.ymlverecektir . size aynı temel yapılandırmayı farklı ortamlar için devralma / yeniden kullanma potansiyeli sunan, yani geliştirmeye karşı teste karşı paralel testlere karşı standart bir meta sarmalayıcıdır .webdocker-rails ci testdocker-rails.ymldocker-compose.yml


2

Bir docker motorunda aynı ada sahip daha fazla docker-compose hizmeti çalıştırmanız ve tam adı bilmediğiniz durumda:

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

echo %? - test-chrome hizmetinden çıkış kodunu döndürür

Faydaları:

  • kesin hizmetin çıkmasını bekleyin
  • kapsayıcı adını değil, hizmet adını kullanır

2

Çıkış durumunu şununla görebilirsiniz:

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

Bunu başlattığınız için teşekkürler. İşte bunun benim versiyonum (bu benim için daha iyi çalışıyor, b / c Bu cevabın yazıldığından beri komut çıktı formatının değiştiğini düşünüyorum) -docker-compose ps | grep servicename | grep -v 'Exit 0' && echo "Automation or integration tests failed." && exit 1
DTrejo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.