MegjithĂ«se tĂ« gjithĂ« e dinĂ« se Ă«shtĂ« e rĂ«ndĂ«sishme dhe e nevojshme tĂ« testosh softuerin tĂ«nd, dhe shumĂ« e bĂ«jnĂ« kĂ«tĂ« automatikisht, nĂ« hapĂ«sirat e Habra nuk u gjet asnjĂ« recetĂ« pĂ«r konfigurimin e lidhjes sĂ« produkteve kaq tĂ« njohura nĂ« kĂ«tĂ« niĆĂ«, siç janĂ« (tĂ« preferuarit tanĂ«) GitLab dhe JUnit. Do ta plotĂ«sojmĂ« kĂ«tĂ« boshllĂ«k!

Hyrja
Fillimisht do të përcaktoj kontekstin:
- Duke pasur parasysh se të gjitha aplikacionet tona punojnë në Kubernetes, do të shqyrtohet ekzekutimi i testeve në infrastrukturën përkatëse.
- Për ndërtimin dhe deklerimin përdorim (në kuptimin e komponentëve të infrastrukturës, kjo gjithashtu automatikisht nënkupton se Helm është i angazhuar).
- Nuk do të thellohem në detajet e krijimit të testeve: në rastin tonë, klienti shkruan vetë testet, dhe ne vetëm sigurojmë ekzekutimin e 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 kalojmĂ«.
- Deklarimi i aplikacionit në një namespace të veçantë të klasterit Kubernetes dhe ekzekutimi i testimit.
- Kërkimi i artefakteve dhe analizimi i raportit JUnit nga GitLab.
- Fshirja e namespace të krijuar më parë.
Tani â nĂ« realizim!
Configuration
GitLab CI
Të fillojmë nga fragmente .gitlab-ci.yaml, që përshkruan deklerimin e aplikacionit dhe ekzekutimin e testeve. Listimi doli mjaft voluminoz, ndaj është thelluar ndjeshëm me komente:
variablat:
# shpallim versionin e werf që do të përdorim
WERF_VERSION: "1.0 beta"
.base_deploy: &base_deploy
skripti:
# krijojmë namespace në K8s, nëse nuk ekziston
- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# dĂ«rgojmĂ« werf dhe deploy â mĂ« shumĂ« rreth kĂ«saj 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ë variablën `run_tests`
# do të përdoret në renderimin e Helm-release
--set "global.run_tests=${RUN_TESTS:-no}"
--set "global.env=${CI_ENVIRONMENT_SLUG}"
# ndryshojmë timeout-in (ka teste që zgjasin)
# dhe e kalojmë në release
--set "global.ci_timeout=${CI_TIMEOUT:-900}"
--timeout ${CI_TIMEOUT:-900}
vargje:
- Build
.test-base: &test-base
zgjeron: .base_deploy
para_skripti:
# krijojmë një direktor për raportin e ardhshëm, duke u bazuar në $CI_COMMIT_REF_SLUG
- mkdir /mnt/tests/${CI_COMMIT_REF_SLUG} || true
# njĂ« workaround i domosdoshĂ«m, sepse GitLab dĂ«shiron tĂ« marrĂ« artefaktet nĂ« build-dirâĂ«n e saj
- mkdir ./tests || true
- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
pas_skripti:
# pas përfundimit të testeve, heqim release-in bashkë me Job-in
# (dhe ndoshta me infrastrukturën 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
# ne lejojmë dështimet, por ju mund të bëni ndryshe
lejo_dështimin: true
variablat:
RUN_TESTS: 'yes'
# caktojmë kontekstin në werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
WERF_KUBE_CONTEXT: 'admin@stage-cluster'
etiketa:
# përdorim runner-in me tag-un `werf-runner`
- werf-runner
artefaktet:
# është e nevojshme të krijohet një artefakt që të mund të shihet
# nĂ« pipeline dhe tĂ« shkarkohet â pĂ«r shembull, pĂ«r studim mĂ« tĂ« thellĂ«
rrugët:
- ./tests/${CI_COMMIT_REF_SLUG}/*
# artefaktet më të vjetra se një javë do të fshihen
skadon_në: 7 ditë
# e rëndësishme: këto rreshta janë përgjegjës për analizimin e raportit nga GitLab
raportet:
junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml
# për thjeshtësim këtu janë treguar vetëm dy etapa
# nĂ« realitet do tĂ« keni mĂ« shumĂ« â tĂ« paktĂ«n pĂ«r shkak tĂ« deploy-it
etapat:
- ndërtimi
- testet
ndertimi:
etapa: ndërtimi
skripti:
# ndĂ«rtimi â sĂ«rish 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
etiketa:
- werf-runner
përjashto:
- grafiket
kërko teste:
<<: *test-base
ambienti:
# "një aftësish" e emërtimit të namespace-it
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
emri: teste-${CI_COMMIT_REF_SLUG}
etapa: testet
përjashto:
- grafiketKubernetes
Tani nĂ« direktorinĂ« .helm/templates do tĂ« krijojmĂ« njĂ« YAML me njĂ« PunĂ« â tests-job.yaml â pĂ«r tĂ« ekzekutuar testet dhe burimet e nevojshme tĂ« Kubernetes. Shpjegimet 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}\/
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 }} Cilat janĂ« burimet tĂ« pĂ«rshkruara nĂ« kĂ«tĂ« konfigurim? GjatĂ« implementimit krijojmĂ« njĂ« namespace unik pĂ«r projektin (kjo Ă«shtĂ« e utur edhe nĂ« .gitlab-ci.yaml â tests-${CI_COMMIT_REF_SLUG}) dhe pĂ«r tĂ« dislokojmĂ«:
- ConfigMap me skriptin e testit;
- Job me përshkrimin e pod-it dhe direktivën e caktuar
command, e cila e ekzekuton testet; - PV dhe PVC, që lejojnë ruajtjen e të dhënave të testeve.
Vini re kushtin fillestar me nĂ«se nĂ« fillim tĂ« manifestit â pĂ«rkatĂ«sisht, YAML-fajlet e tjera tĂ« Helm-chart-it me aplikacionin duhet tĂ« mbĂ«shtillen nĂ« strukturĂ«n e kundĂ«rt , nĂ« mĂ«nyrĂ« qĂ« ato tĂ« mos aplikohen gjatĂ« testimit. Pra:
{{- if ne .Values.global.run_tests "yes" }}
---
ka një tjetër yaml
{{- end }}MegjithatĂ«, nĂ«se testet kĂ«rkojnĂ« njĂ« infrastrukturĂ« tĂ« caktuar (pĂ«r shembull, Redis, RabbitMQ, Mongo, PostgreSQLâŠ) â YAML-tĂ« e tyre mund tĂ« jo opĂ«r dhe ato nĂ« mjedisin e provĂ«s... natyrisht, duke i rregulluar sipas dĂ«shirĂ«s tuaj.
Përfundimi i fundit
Dhe për sa kohë që ndërtimi dhe shpërndarja me anë të werf funksionon ende të në serverin e ndërtimit (me gitlab-runner), dhe podi me testet fillohet në master, do të nevojitet të krijoni një drejtorinë /mnt/tests në master dhe t'ia jepni atë runner-it, për shembull, përmes NFS. Një shembull i zgjeruar me shpjegime mund të gjendet në .
Rezultati do të jetë:
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 të krijoni një NFS-share direkt në gitlab-runner, dhe pastaj ta montoni në podë.
Shënim
Mund të pyesni, përse të komplikoni gjithçka duke krijuar një Job nëse mund të thjesht të ekzekutoni skriptin me testet direkt në shell-runner? Përgjigja është mjaft triviale...
Disa teste kërkojnë qasje në infrastrukturën (MongoDB, RabbitMQ, PostgreSQL etj.) për të verifikuar korrektësinë e punës me to. Ne e bëjmë testimin të unifikuar - me këtë qasje, duke përfshirë entitete të tilla bëhet e lehtë. Përveç kësaj, ne marrim nivelin standard një qasje në shpërndarje (edhe pse me përdorimin e NFS, duke montuar katalogë shtesë).
Rezultati
ĂfarĂ« do tĂ« shohim kur aplikojmĂ« konfigurimin e pĂ«rgatitur?
Në kërkesën e bashkimit do të paraqitet një statistikë e përmbledhur për testet që u ekzekutuan në pipeline-n e saj të fundit:

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

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