JUnit yn GitLab CI gyda Kubernetes

Er gwaethaf y ffaith bod pawb yn gwybod yn iawn bod profi eich meddalwedd yn bwysig ac yn angenrheidiol, ac mae llawer wedi bod yn ei wneud yn awtomatig ers amser maith, yn ehangder Habr nid oedd un rysáit sengl ar gyfer sefydlu cyfuniad o gynhyrchion mor boblogaidd yn y gilfach hon fel (ein ffefryn) GitLab a JUnit . Gadewch i ni lenwi'r bwlch hwn!

JUnit yn GitLab CI gyda Kubernetes

Rhagarweiniol

Yn gyntaf, gadewch imi roi rhywfaint o gyd-destun:

  • Gan fod ein holl gymwysiadau yn rhedeg ar Kubernetes, byddwn yn ystyried cynnal profion ar y seilwaith priodol.
  • Ar gyfer cydosod a lleoli rydym yn defnyddio werff (o ran cydrannau seilwaith, mae hyn hefyd yn awtomatig yn golygu bod Helm yn cymryd rhan).
  • Ni fyddaf yn mynd i mewn i fanylion creu profion gwirioneddol: yn ein hachos ni, mae'r cleient yn ysgrifennu'r profion ei hun, a byddwn ond yn sicrhau eu lansiad (a phresenoldeb adroddiad cyfatebol yn y cais uno).


Sut olwg fydd ar y dilyniant cyffredinol o gamau gweithredu?

  1. Adeiladu'r cais - byddwn yn hepgor y disgrifiad o'r cam hwn.
  2. Gosodwch y cymhwysiad i ofod enw ar wahân o glwstwr Kubernetes a dechrau profi.
  3. Chwilio am arteffactau a dosrannu adroddiadau JUnit gyda GitLab.
  4. Wrthi'n dileu gofod enw a grëwyd yn flaenorol.

Nawr - i weithredu!

addasiad

GitLab CI

Gadewch i ni ddechrau gyda darn .gitlab-ci.yaml, sy'n disgrifio defnyddio'r cais a rhedeg profion. Trodd y rhestriad allan i fod yn eithaf swmpus, felly ategwyd yn drylwyr gyda sylwadau:

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

Nawr yn y cyfeiriadur .helm/templates gadewch i ni greu YAML gyda Job - tests-job.yaml - cynnal profion a'r adnoddau Kubernetes sydd eu hangen arno. Gweler yr esboniadau ar ôl rhestru:

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

Pa fath o adnoddau a ddisgrifir yn y cyfluniad hwn? Wrth ddefnyddio, rydym yn creu gofod enw unigryw ar gyfer y prosiect (nodir hyn yn .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) a'i gyflwyno:

  1. configMap gyda sgript prawf;
  2. Swyddi gyda disgrifiad o'r pod a'r gyfarwyddeb benodedig command, sydd ond yn rhedeg y profion;
  3. PV a PVC, sy'n eich galluogi i storio data prawf.

Rhowch sylw i'r cyflwr rhagarweiniol gyda if ar ddechrau'r maniffest - yn unol â hynny, rhaid lapio ffeiliau YAML eraill o'r siart Helm gyda'r cais gwrthdroi dylunio fel nad ydynt yn cael eu defnyddio yn ystod profion. Hynny yw:

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

Fodd bynnag, os bydd y profion angen rhywfaint o seilwaith (er enghraifft, Redis, RabbitMQ, Mongo, PostgreSQL ...) - gall eu YAMLs fod dim diffodd. Gosodwch nhw mewn amgylchedd prawf hefyd ... gan eu haddasu fel y gwelwch yn dda, wrth gwrs.

cyffwrdd terfynol

Achos cydosod a defnyddio gwaith werff am y tro yn unig ar y gweinydd adeiladu (gyda rhedwr gitlab), ac mae'r pod gyda phrofion yn cael ei lansio ar y meistr, bydd angen i chi greu cyfeiriadur /mnt/tests ar y meistr a'i roi i'r rhedwr, er enghraifft, trwy NFS. Ceir enghraifft fanwl gydag esboniadau yn K8s dogfennaeth.

Y canlyniad fydd:

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

Nid oes neb yn gwahardd gwneud cyfran NFS yn uniongyrchol ar gitlab-runner, ac yna ei osod mewn codennau.

Nodyn

Efallai eich bod yn gofyn pam cymhlethu popeth trwy greu Swydd os gallwch chi redeg sgript gyda phrofion yn uniongyrchol ar y rhedwr cragen? Mae'r ateb yn eithaf dibwys ...

Mae rhai profion yn gofyn am fynediad i'r seilwaith (MongoDB, RabbitMQ, PostgreSQL, ac ati) i wirio eu bod yn gweithio'n gywir. Rydym yn gwneud profion yn unedig - gyda'r dull hwn, mae'n dod yn hawdd cynnwys endidau ychwanegol o'r fath. Yn ychwanegol at hyn, rydym yn cael safonol dull defnyddio (hyd yn oed os ydych yn defnyddio NFS, gosod cyfeiriaduron ychwanegol).

Canlyniad

Beth a welwn pan fyddwn yn cymhwyso'r cyfluniad parod?

Bydd y cais uno yn dangos ystadegau cryno ar gyfer y profion sydd ar y gweill:

JUnit yn GitLab CI gyda Kubernetes

Gellir clicio ar bob gwall yma am fanylion:

JUnit yn GitLab CI gyda Kubernetes

NB: Bydd y darllenydd sylwgar yn sylwi ein bod yn profi cymhwysiad NodeJS, ac yn y sgrinluniau - .NET ... Peidiwch â synnu: dim ond wrth baratoi'r erthygl, ni ddarganfuwyd unrhyw wallau wrth brofi'r cais cyntaf, ond maent eu cael mewn un arall.

Casgliad

Fel y gwelwch, dim byd cymhleth!

Mewn egwyddor, os oes gennych gasglwr cregyn eisoes a'i fod yn gweithio, ond nad oes angen Kubernetes arnoch chi, bydd cysylltu profion ag ef yn dasg symlach fyth na'r hyn a ddisgrifir yma. Ac yn Dogfennaeth GitLab CI fe welwch enghreifftiau ar gyfer Ruby, Go, Gradle, Maven a rhai eraill.

PS

Darllenwch hefyd ar ein blog:

Ffynhonnell: hab.com

Ychwanegu sylw