Malgradu u fattu chì ognunu sapi perfettamente chì a prova di u vostru software hè impurtante è necessariu, è parechji l'anu fattu automaticamente per un bellu pezzu, in l'immensità di Habr ùn ci era micca una sola ricetta per a creazione di una cumminazione di tali prudutti populari. questu nichu cum'è (u nostru favuritu) GitLab è JUnit . Rimpiemu sta lacuna !
Intruduzioni
Prima, lasciami dà un pocu di cuntestu:
Siccomu tutte e nostre applicazioni funzionanu nantu à Kubernetes, cunsideremu l'esecuzione di teste nantu à l'infrastruttura adatta.
Per assemblea è implementazione avemu aduprà werf (in termini di cumpunenti infrastrutturali, questu significa ancu automaticamente chì Helm hè implicatu).
Ùn andaraghju micca in i dettagli di a creazione attuale di teste: in u nostru casu, u cliente scrive i testi stessu, è avemu assicuratu solu u so lanciu (è a prisenza di un rapportu currispundente in a dumanda di fusione).
Chì serà a sequenza generale di l'azzioni cum'è?
Custruisce l'applicazione - omettemu a descrizzione di sta tappa.
Implementa l'applicazione in un spaziu di nomi separatu di u cluster Kubernetes è cumincianu a prova.
Ricerca di artefatti è analizà i rapporti JUnit cù GitLab.
Eliminazione di un spaziu di nome creatu prima.
Avà - à l'implementazione!
cutter
GitLab CI
Cuminciamu cù un fragmentu .gitlab-ci.yaml, chì descrive l'implementazione di l'applicazione è l'esecuzione di teste. A lista hè stata abbastanza voluminosa, cusì hè stata cumplementata cù cumenti:
variables:
# объявляем версию werf, которую собираемся использовать
WERF_VERSION: "1.0 beta"
.base_deploy: &base_deploy
script:
# создаем namespace в K8s, если его нет
- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# загружаем werf и деплоим — подробнее об этом см. в документации
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#deploy-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf deploy --stages-storage :local
--namespace ${CI_ENVIRONMENT_SLUG}
--set "global.commit_ref_slug=${CI_COMMIT_REF_SLUG:-''}"
# передаем переменную `run_tests`
# она будет использоваться в рендере Helm-релиза
--set "global.run_tests=${RUN_TESTS:-no}"
--set "global.env=${CI_ENVIRONMENT_SLUG}"
# изменяем timeout (бывают долгие тесты) и передаем его в релиз
--set "global.ci_timeout=${CI_TIMEOUT:-900}"
--timeout ${CI_TIMEOUT:-900}
dependencies:
- Build
.test-base: &test-base
extends: .base_deploy
before_script:
# создаем директорию для будущего отчета, исходя из $CI_COMMIT_REF_SLUG
- mkdir /mnt/tests/${CI_COMMIT_REF_SLUG} || true
# вынужденный костыль, т.к. GitLab хочет получить артефакты в своем build-dir’е
- mkdir ./tests || true
- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
after_script:
# после окончания тестов удаляем релиз вместе с Job’ом
# (и, возможно, его инфраструктурой)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf dismiss --namespace ${CI_ENVIRONMENT_SLUG} --with-namespace
# мы разрешаем падения, но вы можете сделать иначе
allow_failure: true
variables:
RUN_TESTS: 'yes'
# задаем контекст в werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
WERF_KUBE_CONTEXT: 'admin@stage-cluster'
tags:
# используем раннер с тегом `werf-runner`
- werf-runner
artifacts:
# требуется собрать артефакт для того, чтобы его можно было увидеть
# в пайплайне и скачать — например, для более вдумчивого изучения
paths:
- ./tests/${CI_COMMIT_REF_SLUG}/*
# артефакты старше недели будут удалены
expire_in: 7 day
# важно: эти строки отвечают за парсинг отчета GitLab’ом
reports:
junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml
# для упрощения здесь показаны всего две стадии
# в реальности же у вас их будет больше — как минимум из-за деплоя
stages:
- build
- tests
build:
stage: build
script:
# сборка — снова по документации по werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#build-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf build-and-publish --stages-storage :local
tags:
- werf-runner
except:
- schedules
run tests:
<<: *test-base
environment:
# "сама соль" именования namespace’а
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
name: tests-${CI_COMMIT_REF_SLUG}
stage: tests
except:
- schedules
Kubernetes
Avà in u cartulare .helm/templates criemu YAML cù Job - tests-job.yaml - per eseguisce e teste è e risorse Kubernetes chì hà bisognu. Vede spiegazioni dopu a lista:
Chì tipu di risorse descrittu in sta cunfigurazione? Quandu implementate, creemu un spaziu di nome unicu per u prugettu (questu hè indicatu in .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) è stende:
ConfigMap cù script di prova;
Job cù una descrizzione di u pod è a direttiva specifica command, chì solu corre i testi;
PV è PVC, chì permettenu di almacenà dati di prova.
Prestate attenzione à a cundizione introduttiva cù if à l'iniziu di u manifestu - per quessa, altri schedarii YAML di u graficu Helm cù l'applicazione deve esse impannillati in inverse cuncepimentu in modu chì ùn sò micca implementati durante a prova. Hè:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
Tuttavia, se i testi richiede una certa infrastruttura (per esempiu, Redis, RabbitMQ, Mongo, PostgreSQL ...) - i so YAML ponu esse ùn chjode. Impulsate ancu in un ambiente di prova ... aghjustendu cum'è vede bè, sicuru.
Toccu finale
Perchè assemblea è implementazione cù werf travaglia per avà solu nant'à u servitore di custruzzione (cù gitlab-runner), è u pod cù testi hè lanciatu nantu à u maestru, vi tuccherà à creà un cartulare /mnt/tests nantu à u maestru è dà à u corridore, per esempiu, via NFS. Un esempiu detallatu cù spiegazioni pò esse truvatu in K8s documentazione.
Nimu ùn pruibisce di fà una spartera NFS direttamente nantu à gitlab-runner, è dopu muntallu in pods.
Vita
Puderete esse dumandate perchè complicate tuttu creendu un Job se pudete simpricimenti eseguisce un script cù testi direttamente nantu à u shell runner? A risposta hè abbastanza triviale ...
Certi testi necessitanu accessu à l'infrastruttura (MongoDB, RabbitMQ, PostgreSQL, etc.) per verificà chì travaglianu bè. Facemu a prova unificata - cù questu approcciu, diventa faciule d'include tali entità supplementari. In più di questu, avemu standard approcciu di implementazione (ancu s'ellu si usa NFS, muntazione supplementu di cartulari).
risultatu
Chì vedemu quandu applichemu a cunfigurazione preparata?
A dumanda di fusione mostrarà statistiche riassuntu per e teste eseguite in u so ultimu pipeline:
Ogni errore pò esse clicatu quì per i dettagli:
NB: U lettore attentu s'avvisarà chì avemu pruvatu una applicazione NodeJS, è in i screenshots - .NET... Ùn vi maravigliate : hè solu chì durante a preparazione di l'articulu, ùn ci hè statu trovu errori in a prova di a prima applicazione, ma sò sò stati truvati in un altru.
cunchiusioni
Comu pudete vede, nunda di complicatu!
In principiu, s'è vo avete digià un cullettore di cunchiglia è funziona, ma ùn avete micca bisognu di Kubernetes, attaccà a prova à questu serà un compitu ancu più simplice di ciò chì hè descrittu quì. È in Documentazione GitLab CI truverete esempi per Ruby, Go, Gradle, Maven è altri.