Unatoč činjenici da svi vrlo dobro znaju da je testiranje vašeg softvera važno i potrebno, a mnogi to rade automatski već duže vrijeme, u prostranstvima Habra nije bilo niti jednog recepta za postavljanje kombinacije tako popularnih proizvoda u ovu nišu kao (naš omiljeni) GitLab i JUnit. Popunimo ovu prazninu!
Uvodni
Prvo, dopustite mi da dam malo konteksta:
Budući da sve naše aplikacije rade na Kubernetesu, razmotrit ćemo izvođenje testova na odgovarajućoj infrastrukturi.
Za montažu i postavljanje koristimo werf (što se tiče infrastrukturnih komponenti, to također automatski znači da je Helm uključen).
Neću ulaziti u detalje stvarnog stvaranja testova: u našem slučaju klijent sam piše testove, a mi osiguravamo samo njihovo pokretanje (i prisutnost odgovarajućeg izvješća u zahtjevu za spajanje).
Kako će izgledati opći slijed radnji?
Izrada aplikacije - izostavit ćemo opis ove faze.
Implementirajte aplikaciju u zasebni prostor naziva Kubernetes klastera i počnite s testiranjem.
Traženje artefakata i analiziranje JUnit izvješća s GitLabom.
Brisanje prethodno stvorenog imenskog prostora.
Sada - na implementaciju!
podešavanje
GitLab CI
Počnimo s fragmentom .gitlab-ci.yaml, koji opisuje postavljanje aplikacije i izvođenje testova. Popis se pokazao prilično opsežnim, pa je temeljito dopunjen komentarima:
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
Sada u imeniku .helm/templates stvorimo YAML s Jobom - tests-job.yaml — za pokretanje testova i potrebnih Kubernetes resursa. Pogledajte objašnjenja nakon popisa:
Kakva sredstva opisan u ovoj konfiguraciji? Prilikom implementacije stvaramo jedinstveni prostor imena za projekt (ovo je naznačeno u .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) i razvaljajte:
ConfigMap s testnom skriptom;
Posao s opisom mahune i navedenom direktivom command, koji samo pokreće testove;
PV i PVC, koji vam omogućuju pohranu testnih podataka.
Obratite pažnju na uvodni uvjet sa if na početku manifesta - sukladno tome, druge YAML datoteke Helmovog grafikona s aplikacijom moraju biti zamotane u obrnuti dizajnirati tako da se ne aktiviraju tijekom testiranja. To je:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
Međutim, ako testovi zahtijevaju određenu infrastrukturu (na primjer, Redis, RabbitMQ, Mongo, PostgreSQL...) - njihovi YAML-ovi mogu biti ne isključiti. Također ih implementirajte u testno okruženje... prilagođavajući ih kako vama odgovara, naravno.
Završni dodir
Jer montaža i implementacija pomoću werf-a za sada radi samo na poslužitelju za izgradnju (s gitlab-runnerom), a pod s testovima je pokrenut na masteru, morat ćete stvoriti direktorij /mnt/tests na gospodara i daj ga trkaču, na primjer, putem NFS-a. Detaljan primjer s objašnjenjima nalazi se u K8s dokumentacija.
Nitko ne zabranjuje pravljenje NFS dijeljenja izravno na gitlab-runner, a zatim ga montirati u podove.
Primijetiti
Možda se pitate zašto sve komplicirati stvaranjem Joba ako jednostavno možete pokrenuti skriptu s testovima izravno na pokretaču ljuske? Odgovor je prilično trivijalan...
Neki testovi zahtijevaju pristup infrastrukturi (MongoDB, RabbitMQ, PostgreSQL itd.) kako bi se provjerilo rade li ispravno. Testiranje činimo objedinjenim - s ovim pristupom postaje lako uključiti takve dodatne entitete. Osim ovoga, dobivamo standard pristup implementacije (čak i ako koristite NFS, dodatno montiranje direktorija).
Rezultirati
Što ćemo vidjeti kada primijenimo pripremljenu konfiguraciju?
Zahtjev za spajanje prikazat će sažetak statistike za testove koji se izvode u najnovijem cjevovodu:
Svaku grešku možete kliknuti ovdje za detalje:
NB: Pažljivi čitatelj primijetit će da testiramo NodeJS aplikaciju, a na snimkama zaslona - .NET... Nemojte se iznenaditi: samo tijekom pripreme članka nisu pronađene greške u testiranju prve aplikacije, ali su pronađeni su u drugom.
Zaključak
Kao što vidite, ništa komplicirano!
U principu, ako već imate shell collector i on radi, ali vam ne treba Kubernetes, prilaganje testiranja na njega bit će još jednostavniji zadatak nego što je ovdje opisano. I u GitLab CI dokumentacija naći ćete primjere za Ruby, Go, Gradle, Maven i neke druge.