Megjithëse të gjithë e dinë se është e rëndësishme dhe e nevojshme të testosh softuerin tënd, dhe shumë prej nesh e bëjnë këtë automatikisht, në hapësirat e Habrat nuk ka asnjë recetë për konfigurimin e lidhjes së produkteve kaq popullore në këtë fushë si (i preferuari ynë) GitLab dhe JUnit. Le të plotësojmë këtë boshllëk!

Hyrëse
Për të filluar, do të citoj kontekstin:
- Duke qenë se të gjitha aplikacionet tona funksionojnë në Kubernetes, do të shqyrtojmë ekzekutimin e testeve në infrastrukturën përkatëse.
- Për ndërtimin dhe shpërndarjen përdorim (në kuptimin e komponenteve infrastrukturore, kjo gjithashtu automatikisht nënkupton se është përdorur Helm).
- Nuk do të hyj në detaje të krijimit të testeve: në rastin tonë, klienti i shkruan testet vetë, dhe ne vetëm sigurojmë ekzekutim të tyre (dhe praninë e raportit përkatës në merge request).
Si do të duket sekuenca e përgjithshme e veprimeve?
- NdĂ«rtimi i aplikacionit â pĂ«rshkrimi i kĂ«tij faze do ta anashkalojmĂ«.
- Shpërndarja e aplikacionit në një namespace të veçantë të klasterit Kubernetes dhe fillimi i testimit.
- Gjetja e artefakteve dhe analizimi i raportit JUnit nga GitLab.
- Fshirja e namespace-it të krijuar më parë.
Tani, le të kalojmë te implementimi!
Konfigurimi
GitLab CI
Të fillojmë me fragmentin .gitlab-ci.yaml, që përshkruan shpërndarjen e aplikacionit dhe ekzekutimin e testeve. Lista doli mjaft e gjerë, prandaj është plotësuar qëllimisht me komentet:
variables:
# shpallim versionin e werf që do të përdorim
WERF_VERSION: "1.0 beta"
.base_deploy: &base_deploy
script:
# krijojmë namespace në K8s, nëse nuk ekziston
- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# ngarkojmĂ« werf dhe e shpĂ«rndajmĂ« â mĂ« shumĂ« rreth kĂ«saj shihni nĂ« dokumentacion
# (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:-''}"
# kalojmë variablin `run_tests`
# ai do të përdoret në renderimin e helm-release-it
--set "global.run_tests=${RUN_TESTS:-no}"
--set "global.env=${CI_ENVIRONMENT_SLUG}"
# ndryshojmë timeout (disa teste mund të zgjasin) dhe e kalojmë atë në release
--set "global.ci_timeout=${CI_TIMEOUT:-900}"
--timeout ${CI_TIMEOUT:-900}
dependencies:
- Build
.test-base: &test-base
extends: .base_deploy
before_script:
# krijojmë një dosje për raportin e ardhshëm, duke u bazuar në $CI_COMMIT_REF_SLUG
- mkdir /mnt/tests/${CI_COMMIT_REF_SL_SLUG} || true
# një zgjidhje e nevojshme, sepse GitLab dëshiron të marrë artefaktet në build-dir-in e tij
- mkdir ./tests || true
- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
after_script:
# pas përfundimit të testeve fshijmë release-in, së bashku me Job-in
# (dhe, ndoshta, infrastrukturen e tij)
- 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
# lejojmë rëniet, por ju mund ta bëni ndryshe
allow_failure: true
variables:
RUN_TESTS: 'yes'
# caktojmë kontekst në werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
WERF_KUBE_CONTEXT: 'admin@stage-cluster'
tags:
# përdorim runner-in me etiketën `werf-runner`
- werf-runner
artifacts:
# kërkohet të krijohet një artefakt që të mund të shfaqet
# nĂ« pipeline dhe tĂ« shkarkohet â p.sh., pĂ«r studime mĂ« tĂ« thella
paths:
- ./tests/${CI_COMMIT_REF_SLUG}/*
# artefaktet më të vjetra se një javë do të fshihen
expire_in: 7 day
# e rëndësishme: këto rreshta përgjigjen për analizen e raportit nga GitLab
reports:
junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml
# për thjeshtim, këtu tregohet vetëm dy faza
# nĂ« tĂ« vĂ«rtetĂ« do tĂ« keni mĂ« shumĂ« â sĂ« paku pĂ«r shkak tĂ« shpĂ«rndarjes
stages:
- build
- tests
build:
stage: build
script:
# ndĂ«rtimi â pĂ«rsĂ«ri sipas dokumentacionit tĂ« 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:
# "vetë kripa" e emërtimit të namespace-it
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
name: tests-${CI_COMMIT_REF_SLUG}
stage: tests
except:
- schedulesKubernetes
Tani nĂ« direktorinĂ« .helm/templates do tĂ« krijojmĂ« YAML me Job-in â tests-job.yaml â pĂ«r ekzekutimin e testeve dhe burimet e nevojshme pĂ«r tĂ« nĂ« Kubernetes. PĂ«rshtypjet shihni pas listĂ«s:
{{- if eq .Values.global.run_tests "yes" }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: tests-script
data:
tests.sh: |
echo "======================"
echo "${APP_NAME} TESTS"
echo "======================"
cd \/app
npm run test:ci
cp report.xml \/app\/test_results\/${CI_COMMIT_REF_SLUG}\/\n
echo ""
echo ""
echo ""
chown -R 999:999 \/app\/test_results\/${CI_COMMIT_REF_SLUG}
---
apiVersion: batch\/v1
kind: Job
metadata:
name: {{ .Chart.Name }}-test
annotations:
"helm.sh\/hook": post-install,post-upgrade
"helm.sh\/hook-weight": "2"
"werf\/watch-logs": "true"
spec:
activeDeadlineSeconds: {{ .Values.global.ci_timeout }}
backoffLimit: 1
template:
metadata:
name: {{ .Chart.Name }}-test
spec:
containers:
- name: test
command: ['bash', '-c', '/app/tests.sh']
{{ tuple "application" . | include "werf_container_image" | indent 8 }}
env:
- name: env
value: {{ .Values.global.env }}
- name: CI_COMMIT_REF_SLUG
value: {{ .Values.global.commit_ref_slug }}
- name: APP_NAME
value: {{ .Chart.Name }}
{{ tuple "application" . | include "werf_container_env" | indent 8 }}
volumeMounts:
- mountPath: \/app\/test_results\/\n name: data
- mountPath: \/app\/tests.sh
name: tests-script
subPath: tests.sh
tolerations:
- key: dedicated
operator: Exists
- key: node-role.kubernetes.io\/master
operator: Exists
restartPolicy: OnFailure
volumes:
- name: data
persistentVolumeClaim:
claimName: {{ .Chart.Name }}-pvc
- name: tests-script
configMap:
name: tests-script
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ .Chart.Name }}-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }}
volumeName: {{ .Values.global.commit_ref_slug }}
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: {{ .Values.global.commit_ref_slug }}
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Mi
local:
path: \/mnt\/tests\/\n nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io\/hostname
operator: In
values:
- kube-master
persistentVolumeReclaimPolicy: Delete
storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }}
{{- end }} ĂfarĂ« burimesh janĂ« pĂ«rshkruar nĂ« kĂ«tĂ« konfigurim? GjatĂ« implementimit krijojmĂ« njĂ« hapĂ«sirĂ« unike pĂ«r projektin (kjo Ă«shtĂ« e specifikuar edhe nĂ« .gitlab-ci.yaml â tests-${CI_COMMIT_REF_SLUG}) dhe nĂ« tĂ« nxjerrim:
- ConfigMap me skriptin e testit;
- Job me përshkrimin e pod-it dhe direktivën e specifikuar
command, e cila pikërisht aktivizon testet; - PV dhe PVC, që lejojnë ruajtjen e të dhënave të testeve.
Kujdesi ndaj kushtit tĂ« hyrjes me nĂ«se nĂ« fillim tĂ« manifestit â pĂ«rkatĂ«sisht, skedarĂ«t e tjerĂ« YAML tĂ« Helm-chart-it tĂ« aplikacionit duhet tĂ« mbyllen nĂ« ndihmĂ«sin e pĂ«r tĂ« mos u implementuar gjatĂ« testimit. Pra:
{{- if ne .Values.global.run_tests "yes" }}
---
jam ndihmë tjetër
{{- end }}MegjithatĂ«, nĂ«se testet kĂ«rkojnĂ« njĂ« infrastrukturĂ« tĂ« caktuar (p.sh., Redis, RabbitMQ, Mongo, PostgreSQLâŠ) â YAML-Ă«t e tyre mund tĂ« nuk çaktivizohen. Aktivizoni edhe ato nĂ« mjedisin e testimit⊠sigurisht, duke i modifikuar sipas dĂ«shirĂ«s tuaj.
Detaji përfundimtar
Duke qenë se ndërtimi dhe implementimi me ndihmën e werf aktualisht funksionon vetëm në serverin e ndërtimit (me gitlab-runner), dhe pod-i me testet aktivizohet në master, do të nevojitet të krijoni një direktori /mnt/tests në master dhe t'ia jepni atij në runner, p.sh., përmes NFS. Një shembull i përfunduar me shpjegime mund të gjendet në .
Si rezultat do të kemi:
user@kube-master:~$ cat \/etc\/exports | grep tests
\/mnt\/tests IP_gitlab-builder\/32(rw,nohide,insecure,no_subtree_check,sync,all_squash,anonuid=999,anongid=998)
user@gitlab-runner:~$ cat \/etc\/fstab | grep tests
IP_kube-master:\/mnt\/tests \/mnt\/tests nfs4 _netdev,auto 0 0Askush nuk ndalon që të bëni një NFS-share direkt në gitlab-runner, pas së cilës ta montoni atë në pod-e.
Shënim
Ndoshta do tĂ« pyesni, pse ta komplikohet gjithĂ« kjo krijimi i Job-it, nĂ«se mund tĂ« aktivizoni thjesht skriptin me testet direkt nĂ« shell-runner? PĂ«gjigjja Ă«shtĂ« mjaft e thjeshtĂ«âŠ
Disa teste kĂ«rkojnĂ« qasje nĂ« infrastrukturĂ«n (MongoDB, RabbitMQ, PostgreSQL etj.) pĂ«r tĂ« verifikuar funksionimin e duhur me to. Ne e bĂ«jmĂ« testimin tĂ« unifikuar â me kĂ«tĂ« qasje, pĂ«rfshirja e entiteteve tĂ« tilla tĂ« tjera bĂ«het e lehtĂ«. PĂ«r mĂ« tepĂ«r, ne pĂ«rfitojmĂ« qasje standarde nĂ« implementim (ndonĂ«se me pĂ«rdorimin e NFS, montimi tĂ« katalogĂ«ve tĂ« tjerĂ«).
Rezultati
ĂfarĂ« do tĂ« shohim, kur tĂ« aplikojmĂ« konfigurimin e pĂ«rgatitur?
Në kërkesën për bashkimin do të tregohet statistika përmbledhëse për testet, të cilat janë aktivizuar në pipeline-in e fundit të saj:

Për çdo gabim këtu mund të klikoni për të marrë detaje:

NB: Lexuesi i kujdesshëm do të vërejë, se po testojmë aplikacionin NodeJS, ndërsa në screenshot janë .NET⊠Mos u çuditni: thjesht në kuadër të përgatitjes së artikullit nuk u gjetën gabime në testimin e aplikacionit të parë, por u gjetën në një tjetër.
Përfundimi
Siç duket, nuk është asgjë e komplikuar!
NĂ« parim, nĂ«se ju tashmĂ« keni njĂ« ndĂ«rtues shell dhe ai funksionon, dhe Kubernetes nuk ju nevojitet â integrimi i testimit nĂ« tĂ« do tĂ« jetĂ« njĂ« detyrĂ« akoma mĂ« e thjeshtĂ« se ajo qĂ« Ă«shtĂ« pĂ«rshkruar kĂ«tu. Dhe nĂ« do tĂ« gjeni shembuj pĂ«r Ruby, Go, Gradle, Maven dhe disa tĂ« tjerĂ«.
P.S.
Lexoni gjithashtu në blogun tonë:
- «»;
- «»;
- «».
Burimi: habr.com
