JUnit GitLab CI-s koos Kubernetesega

Kuigi kĂ”ik teavad, et oma tarkvara testimine on oluline ja vajalik, ning paljud teevad seda automaatselt, ei leidunud Habras ĂŒhtegi retsepti, kuidas seadistada selliste populaarsete toodete nagu (meie lemmik) GitLab ja JUnit kombinatsiooni. TĂ€idame selle tĂŒhiku!

JUnit GitLab CI-s koos Kubernetesega

Sissejuhatus

Alustuseks mÀÀratlen konteksti:

  • Kuna kĂ”ik meie rakendused töötavad Kuberneteses, kĂ€sitleme testide kĂ€ivitamist vastavas infrastruktuuris.
  • Kogumise ja juurutamise jaoks kasutame werf (infrastruktuuri komponente arvestades tĂ€hendab see automaatselt, et on kaasatud ka Helm).
  • Ei sĂŒvene testide loomise ĂŒksikasjadesse: meie puhul kirjutab klient testid ise ja me tagame vaid nende kĂ€ivitamise (ja vastava aruande olemasolu merge request'is).


Milline nĂ€eb vĂ€lja ĂŒldine tegevuste jĂ€rjekord?

  1. Rakenduse kogumine — selle etapi kirjeldust jĂ€tame vĂ€lja.
  2. Rakenduse juurutamine Kubernetes klastris eraldi namespace'i ja testimise kÀivitamine.
  3. Artefaktide otsimine ja JUnit aruande parsimine GitLabis.
  4. Varasemalt loodud namespace'i kustutamine.

NĂŒĂŒd — elluviimise juurde!

Seadistamine

GitLab CI-d

Alustame fragmentist .gitlab-ci.yaml, mis kirjeldab rakenduse juurutamist ja testide kĂ€ivitamist. Loetelu osutus ĂŒsna mahukaks ning on seetĂ”ttu pĂ”hjalikult tĂ€iendatud kommentaaridega:

muutujad:
# deklareerime werf versiooni, mida kavatseme kasutada
  WERF_VERSION: "1.0 beta"

.base_deploy: &base_deploy
  skript:
# loome namespace K8s, kui seda ei ole
    - kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# laadime werfi ja deploime — rohkem selle kohta leiate dokumentatsioonist
# (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:-''}"
# edastame muutujat `run_tests`
# seda kasutatakse Helm-release'i renderdamisel
      --set "global.run_tests=${RUN_TESTS:-no}"
      --set "global.env=${CI_ENVIRONMENT_SLUG}"
# muudame timeout'i (mÔnikord on testid pikad) ja edastame selle release'ile
      --set "global.ci_timeout=${CI_TIMEOUT:-900}"
     --timeout ${CI_TIMEOUT:-900}
  sÔltuvused:
    - Build

.test-base: &test-base
  laiendab: .base_deploy
  before_script:
# loome kausta tulevase raporti jaoks, lÀhtudes $CI_COMMIT_REF_SLUG'ist
    - mkdir /mnt/tests/${CI_COMMIT_REF_SLUG} || true
# sunnitud lahendus, kuna GitLab tahab saada artefakte oma build-dir’ist
    - mkdir ./tests || true
    - ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
  after_script:
# pÀrast testide lÔppu eemaldame release koos Job'iga
# (ja vÔimalikult ka selle infrastruktuuriga)
    - 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
# lubame tÔrkeid, kuid saate teha teisiti
  allow_failure: true
  muutujad:
    RUN_TESTS: 'yes'
# seadistame konteksti werf'is
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
    WERF_KUBE_CONTEXT: 'admin@stage-cluster'
  sildid:
# kasutame runnerit sildiga `werf-runner`
    - werf-runner
  artefaktid:
# vajalik on koguda artefakt, et seda vÔiks nÀha
# pipeline'is ja alla laadida — nĂ€iteks pĂ”hjalikumaks uurimiseks
    paths:
      - ./tests/${CI_COMMIT_REF_SLUG}/*
# artefaktid, mis on vanemad kui nÀdal, kustutatakse
    expire_in: 7 day
# oluline: need read vastutavad GitLabi raporti töötlemise eest
    reports:
      junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml

# lihtsustamiseks on siin nÀidatud vaid kaks etappi
# tegelikult on teil neid rohkem — vĂ€hemalt deploimise tĂ”ttu
etapid:
  - build
  - tests

build:
  etapp: build
  skript:
# ehitamine — uuesti vastavalt werfi dokumentatsioonile
# (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
  sildid:
    - werf-runner
  vÀlja arvatud:
    - schedules

kÀivita testid:
  <<: *test-base
  keskkond:
# "endiselt sool" namespace'i nimetamisel
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
    name: tests-${CI_COMMIT_REF_SLUG}
  etapp: tests
  vÀlja arvatud:
    - schedules

Kubernetes

NĂŒĂŒd kaustas .helm/templates loome YAML Job'iga — tests-job.yaml — testide kĂ€ivitamiseks ja vajalikeks Kubernetes'i ressurssideks. Selgitused on loetletud jĂ€rgnevalt:

{{- if eq .Values.global.run_tests "yes" }}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: tests-script
data:
  tests.sh: |
    echo "======================"
    echo "${APP_NAME} TESTID"
    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/
          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/
  nodeAffinity:
   required:
     nodeSelectorTerms:
     - matchExpressions:
       - key: kubernetes.io/hostname
         operator: In
         values:
         - kube-master
  persistentVolumeReclaimPolicy: Delete
  storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }}
{{- end }}

Milliseid ressursse on selles konfiguratsioonis kirjeldatud? Deployimisel loome projekti jaoks ainulaadse nimi ({see on juba loetletud .gitlab-ci.yaml — tests-${CI_COMMIT_REF_SLUG}) ja viime selle sisse:

  1. ConfigMap testiskripti;
  2. Töö pod'i kirjeldust ja mÀÀratud direktiivi kÀsk, mis kÀivitab testid;
  3. PV ja PVC, mis vÔimaldavad testide andmete salvestamist.

Pange tĂ€hele tingimuslauset if manifesti alguses — vastavalt sellele peavad teised Helm chart'i YAML-failid olema mĂ€hitud vastandlikku struktuuri, et need ei deployitaks testimise ajal. See tĂ€hendab:

{{- if ne .Values.global.run_tests "yes" }}
---
siin on teine yaml
{{- end }}

Siiski, kui testid nĂ”uavad mingit infrastruktuuri (nt Redis, RabbitMQ, Mongo, PostgreSQL
) — nende YAML-id vĂ”ivad ei vĂ€lja lĂŒlitama. Laadige ja neid testimiskeskkonnas
 muidugi kohandage vastavalt oma soovidele.

LÔppviimistlus

Kuna kogumine ja juurutamine werf'i abil töötab praegu seda build-serveris (gitlab-runner'i kaudu), samas kui pod testide jaoks kÀivitatakse masteris, tuleb luua kataloog /mnt/tests masteris ja anda see runner'ile, nÀiteks NFS kaudu. Lahtise nÀitena koos selgitustega leiate K8s dokumentatsioonist.

Tulemuseks saab olema:

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       0

Keegi ei keela teha NFS-shaari otse gitlab-runneris ja seejÀrel mountida see pod'idena.

MĂ€rkus

VĂ”ib-olla kĂŒsite, miks ĂŒldse keeruliseks teha Job'i loomisega, kui saab lihtsalt kĂ€ivitada skripti testide jaoks otse shell-runneris? Vastus on piisavalt triviaalne


MĂ”ned testid vajavad infrastruktuuri (MongoDB, RabbitMQ, PostgreSQL jne) poole pöördumist, et kontrollida nendega töötamise Ă”iguspĂ€rasust. Teeme testimise ĂŒhtseks — sellise lĂ€henemisega on sarnaste lisasĂŒsteemide kaasamine lihtne. Lisaks saame tavaline juurde lĂ€henemise juurutamisel (isegi kui kasutatakse NFS'i ning lisakatkeste monteerimist).

Tulemus

Mida me nÀeme, kui rakendame ettevalmistatud konfiguratsiooni?

Merge request'is kuvatakse kokkuvÔtlik statistika testide kohta, mis kÀivitati selle viimases torustikus:

JUnit GitLab CI-s koos Kubernetesega

Iga vea peal saab klikida, et saada rohkem detaile:

JUnit GitLab CI-s koos Kubernetesega

NB: Hoolikas lugeja mĂ€rkab, et testime NodeJS rakendust, samal ajal kui ekraanipiltidel on .NET... Ära ĂŒllatu, et lihtsalt artikli ettevalmistamisel ei olnud esimeses rakenduses vigu, kuid leidsime need teisest.

KokkuvÔte

Nagu nÀha, pole midagi keerulist!

PĂ”himĂ”tteliselt, kui teil on juba shell-kogum ja see töötab, ning Kubernetes pole vajalik — testimise lisamine sellele on veelgi lihtsam ĂŒlesanne, kui siin kirjeldatud. Ja GitLab CI dokumentatsioonist leiate Ruby, Go, Gradle, Maven ja teiste jaoks nĂ€iteid.

P.S.

Lugege ka meie blogist:

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster