JUnit f'GitLab CI ma' Kubernetes

Minkejja l-fatt li kulħadd jaf perfettament li l-ittestjar tas-softwer tiegħek huwa importanti u meħtieġ, u ħafna ilhom jagħmlu dan b’mod awtomatiku għal żmien twil, fil-kobor ta’ Habr ma kienx hemm riċetta waħda biex titwaqqaf taħlita ta’ prodotti popolari bħal dawn f’ din in-niċċa bħala (favoriti tagħna) GitLab u JUnit . Ejja nimlew dan il-vojt!

JUnit f'GitLab CI ma' Kubernetes

Introduttorja

L-ewwel, ħalluni nagħti xi kuntest:

  • Peress li l-applikazzjonijiet kollha tagħna jaħdmu fuq Kubernetes, se nikkunsidraw li nwettqu testijiet fuq l-infrastruttura xierqa.
  • Għall-assemblaġġ u l-iskjerament nużaw werf (f'termini ta' komponenti infrastrutturali, dan ifisser ukoll awtomatikament li Helm huwa involut).
  • Mhux se nidħol fid-dettalji tal-ħolqien attwali tat-testijiet: fil-każ tagħna, il-klijent jikteb it-testijiet huwa stess, u aħna niżguraw biss it-tnedija tagħhom (u l-preżenza ta 'rapport korrispondenti fit-talba għall-għaqda).


Kif se tkun is-sekwenza ġenerali ta' azzjonijiet?

  1. Nibnu l-applikazzjoni - aħna se nħallu barra d-deskrizzjoni ta 'dan l-istadju.
  2. Uża l-applikazzjoni fi spazju tal-isem separat tal-cluster Kubernetes u ibda l-ittestjar.
  3. Tiftix għal artifacts u parsing tar-rapporti JUnit ma 'GitLab.
  4. Tħassir ta' namespace maħluq qabel.

Issa - għall-implimentazzjoni!

aġġustament

GitLab CI

Nibdew bi framment .gitlab-ci.yaml, li jiddeskrivi l-iskjerament tal-applikazzjoni u t-tmexxija tat-testijiet. L-elenkar irriżulta li kien pjuttost voluminuż, għalhekk ġie supplimentat bir-reqqa b'kummenti:

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

Issa fid-direttorju .helm/templates ejja noħolqu YAML b'Job - tests-job.yaml — biex imexxi testijiet u r-riżorsi Kubernetes li jeħtieġ. Ara spjegazzjonijiet wara l-elenkar:

{{- 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/
          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 }}

X'tip ta' riżorsi deskritt f'din il-konfigurazzjoni? Waqt l-iskjerament, noħolqu spazju tal-isem uniku għall-proġett (dan huwa indikat fi .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) u roll out:

  1. ConfigMap b'kitba tat-test;
  2. Job b'deskrizzjoni tal-pod u d-direttiva speċifikata command, li jmexxi biss it-testijiet;
  3. PV u PVC, li jippermettulek taħżen data tat-test.

Oqgħod attent għall-kundizzjoni tal-bidu bil if fil-bidu tal-manifest - għaldaqstant, fajls YAML oħra tat-tabella Helm mal-applikazzjoni għandhom ikunu mgeżwra f' bil-maqlub disinn sabiex ma jiġux skjerati waqt l-ittestjar. Jiġifieri:

{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}

Madankollu, jekk it-testijiet jeħtieġu xi infrastruttura (pereżempju, Redis, RabbitMQ, Mongo, PostgreSQL...) - il-YAMLs tagħhom jistgħu jkunu ebda itfi. Tiskjerahom f'ambjent tat-test ukoll... aġġustahom kif jidhirlek xieraq, ovvjament.

Touch finali

Għax assemblaġġ u skjerament bl-użu ta 'xogħlijiet werf għalissa biss fuq is-server tal-bini (bil-gitlab-runner), u l-pod bit-testijiet huwa mniedi fuq il-kaptan, ser ikollok bżonn toħloq direttorju /mnt/tests fuq il-kaptan u agħtiha lill-runner, per eżempju, permezz NFS. Eżempju dettaljat bi spjegazzjonijiet jista’ jinstab fi Dokumentazzjoni K8s.

Ir-riżultat se jkun:

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

Ħadd ma jipprojbixxi li jagħmel sehem NFS direttament fuq gitlab-runner, u mbagħad iwaħħalha fil-miżwed.

Innota

Inti tista 'tistaqsi għaliex tikkomplika kollox billi toħloq Impjiegi jekk inti tista' sempliċiment tmexxi script b'testijiet direttament fuq il-shell runner? It-tweġiba hija pjuttost trivjali...

Xi testijiet jeħtieġu aċċess għall-infrastruttura (MongoDB, RabbitMQ, PostgreSQL, eċċ.) biex jivverifikaw li jaħdmu b'mod korrett. Aħna nagħmlu l-ittestjar unifikat - b'dan l-approċċ, isir faċli li jiġu inklużi entitajiet addizzjonali bħal dawn. B'żieda ma 'dan, aħna tikseb standard approċċ ta 'skjerament (anke jekk tuża NFS, immuntar addizzjonali ta' direttorji).

Riżultat

X'se naraw meta napplikaw il-konfigurazzjoni ppreparata?

It-talba għall-għaqda se turi statistika fil-qosor għat-testijiet imwettqa fl-aħħar pipeline tagħha:

JUnit f'GitLab CI ma' Kubernetes

Kull żball jista’ jiġi kklikkjat hawn għad-dettalji:

JUnit f'GitLab CI ma' Kubernetes

NB: Il-qarrej attent jinduna li qed nittestjaw applikazzjoni NodeJS, u fil-screenshots - .NET... Tiskantax: huwa biss li waqt il-preparazzjoni tal-artiklu, ma nstabu l-ebda żbalji fl-ittestjar tal-ewwel applikazzjoni, iżda dawn instabu f’ieħor.

Konklużjoni

Kif tistgħu taraw, xejn ikkumplikat!

Fil-prinċipju, jekk diġà għandek kollettur tal-qoxra u taħdem, iżda m'għandekx bżonn Kubernetes, it-twaħħil tal-ittestjar miegħu se jkun kompitu saħansitra aktar sempliċi minn dak deskritt hawn. U fi Dokumentazzjoni GitLab CI issib eżempji għal Ruby, Go, Gradle, Maven u xi wħud oħrajn.

PS

Aqra wkoll fuq il-blog tagħna:

Sors: www.habr.com

Żid kumment