JUnit GitLab CI-n Kubernetes-ekin

Nahiz eta denek ondo daki zure softwarea probatzea garrantzitsua eta beharrezkoa dela, eta askok denbora luzez automatikoki egiten duten arren, Habr-en zabaltasunean ez zegoen errezeta bakar bat ere produktu ezagunen konbinazio bat ezartzeko. nitxo hau (gure gogokoena) GitLab eta JUnit gisa. Bete dezagun hutsune hau!

JUnit GitLab CI-n Kubernetes-ekin

Sarrera

Lehenik eta behin, testuinguru bat emango dut:

  • Gure aplikazio guztiak Kubernetesen exekutatzen direnez, azpiegitura egokian probak egitea kontuan hartuko dugu.
  • Muntatzeko eta hedatzeko erabiltzen dugu werf (azpiegitura osagaiei dagokienez, honek automatikoki ere esan nahi du Helm parte hartzen duela).
  • Ez naiz proben benetako sorreraren xehetasunetan sartuko: gure kasuan, bezeroak berak idazten ditu probak, eta haien abiaraztearen (eta bateratze-eskaeran dagokion txostena egotea) bermatzen dugu soilik.


Nolakoa izango da ekintzen sekuentzia orokorra?

  1. Aplikazioa eraikitzea - ​​etapa honen deskribapena alde batera utziko dugu.
  2. Inplementatu aplikazioa Kubernetes klusterraren izen-eremu bereizi batean eta hasi probak egiten.
  3. Artefaktuak bilatzea eta JUnit txostenak analizatzea GitLab-ekin.
  4. Aurretik sortutako izen-espazio bat ezabatzea.

Orain - inplementaziora!

doikuntza

GitLab CI

Has gaitezen zati batekin .gitlab-ci.yaml, aplikazioa zabaldu eta probak exekutatzen deskribatzen dituena. Zerrenda nahiko handia izan zen, beraz, iruzkinekin osatu zen:

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

Orain direktorioan .helm/templates sor dezagun YAML Jobekin - tests-job.yaml — probak eta behar dituen Kubernetes baliabideak exekutatzeko. Ikusi azalpenak zerrendatu ondoren:

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

Nolako baliabideak konfigurazio honetan deskribatuta? Inplementatzean, proiekturako izen-espazio esklusibo bat sortzen dugu (hau atalean adierazten da .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) eta zabaldu:

  1. ConfigMap probako gidoiarekin;
  2. Lana podaren deskribapenarekin eta zehaztutako zuzentarauarekin command, probak bakarrik egiten dituena;
  3. PV eta PVC, probaren datuak gordetzeko aukera ematen dutenak.

Erreparatu hasierako baldintzarekin if manifestuaren hasieran - horren arabera, aplikazioarekin Helm diagramaren beste YAML fitxategiak bildu behar dira. alderantziz diseinatu, probak zehar hedatu ez daitezen. Hori da:

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

Hala ere, probak bada azpiegitura batzuk behar ditu (adibidez, Redis, RabbitMQ, Mongo, PostgreSQL...) - haien YAMLak izan daitezke ez itzali. Inplementatu itzazu proba-ingurune batean ere... egoki deritzon moduan egokituz, noski.

Azken ukitua

Zeren werf lanak erabiliz muntaia eta hedapena oraingoz bakarrik eraikitzeko zerbitzarian (gitlab-runner-ekin), eta probak dituen poda maisuan abiarazten da, direktorioa sortu beharko duzu /mnt/tests maisuaren gainean eta eman korrikalariari, adibidez, NFS bidez. Adibide zehatza azalpenekin aurki daiteke K8s dokumentazioa.

Emaitza hau izango da:

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

Inork ez du debekatzen NFS partekatze bat zuzenean gitlab-runner-en egitea, eta gero podetan muntatzea.

Kontuan izan

Galdetuko duzu zergatik zaildu dena Lan bat sortuz, probak dituen script bat exekutatu besterik ez baduzu shell runner-ean? Erantzuna nahiko hutsala da...

Proba batzuek azpiegiturarako sarbidea behar dute (MongoDB, RabbitMQ, PostgreSQL, etab.) behar bezala funtzionatzen dutela egiaztatzeko. Probak bateratu egiten ditugu; ikuspegi honekin, erraza da horrelako entitate gehigarriak sartzea. Honetaz gain, lortzen dugu estandarra inplementazio ikuspegia (nahiz eta NFS erabili, direktorioen muntaketa gehigarria).

Emaitza

Zer ikusiko dugu prestatutako konfigurazioa aplikatzen dugunean?

Batzeko eskaerak bere azken kanalean exekutatzen diren proben laburpen-estatistikak erakutsiko ditu:

JUnit GitLab CI-n Kubernetes-ekin

Akats bakoitza hemen klik egin daiteke xehetasunetarako:

JUnit GitLab CI-n Kubernetes-ekin

NB: Irakurle adiak NodeJS aplikazio bat probatzen ari garela ohartuko da, eta pantaila-argazkietan - .NET... Ez harritu: artikulua prestatzerakoan ez dela akatsik aurkitu lehen aplikazioa probatzean, baina beste batean aurkitu ziren.

Ondorioa

Ikusten duzun bezala, ezer konplikatua!

Printzipioz, lehendik shell biltzaile bat baduzu eta funtzionatzen badu, baina ez baduzu Kubernetes behar, probak eranstea hemen deskribatzen dena baino zeregin are errazagoa izango da. Eta barruan GitLab CI dokumentazioa Ruby, Go, Gradle, Maven eta beste batzuen adibideak aurkituko dituzu.

PS

Irakurri ere gure blogean:

Iturria: www.habr.com

Gehitu iruzkin berria