JUnit GitLab CI-s Kubernetesiga

Hoolimata asjaolust, et kõik teavad suurepäraselt, et teie tarkvara testimine on oluline ja vajalik ning paljud on seda juba pikka aega automaatselt teinud, polnud Habri avarustes ühestki retsepti, kuidas nii populaarsete toodete kombinatsiooni seadistada. see nišš (meie lemmikuna) GitLab ja JUnit . Täidame selle tühimiku!

JUnit GitLab CI-s Kubernetesiga

Sissejuhatav

Esiteks lubage mul tuua veidi konteksti:

  • Kuna kõik meie rakendused töötavad Kubernetesis, kaalume testide läbiviimist sobivas infrastruktuuris.
  • Monteerimiseks ja kasutuselevõtuks kasutame werf (infrastruktuuri komponentide osas tähendab see automaatselt ka Helmi kaasamist).
  • Testide tegeliku loomise detailidesse ma ei lasku: meie puhul kirjutab klient testid ise ja meie tagame vaid nende käivitamise (ja vastava raporti olemasolu liitmistaotluses).


Milline näeb välja üldine toimingute jada?

  1. Rakenduse koostamine – jätame selle etapi kirjelduse välja.
  2. Juurutage rakendus Kubernetese klastri eraldi nimeruumi ja alustage testimist.
  3. Artefaktide otsimine ja JUniti aruannete sõelumine GitLabiga.
  4. Varem loodud nimeruumi kustutamine.

Nüüd - rakendamiseni!

reguleerimine

GitLab CI

Alustame fragmendiga .gitlab-ci.yaml, mis kirjeldab rakenduse juurutamist ja testide käitamist. Nimekiri osutus üsna mahukaks, nii et seda täiendati põhjalikult kommentaaridega:

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

Nüüd kataloogis .helm/templates loome YAMLi koos Jobiga - tests-job.yaml — testide ja Kubernetese ressursside käitamiseks. Vaadake selgitusi pärast loetlemist:

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

Millised ressursid selles konfiguratsioonis kirjeldatud? Juurutamisel loome projektile ainulaadse nimeruumi (see on märgitud .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) ja rulli see välja:

  1. ConfigMap testskriptiga;
  2. töö koos kauna kirjelduse ja täpsustatud käskkirjaga command, mis lihtsalt käivitab testid;
  3. PV ja PVC, mis võimaldavad salvestada testiandmeid.

Pöörake tähelepanu sissejuhatavale tingimusele if manifesti alguses - vastavalt tuleb rakendusega Helmi diagrammi muud YAML-failid pakkida tagurpidi kujundada nii, et need ei satuks testimise ajal kasutusele. See on:

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

Kui aga testid nõuavad teatud infrastruktuuri (näiteks Redis, RabbitMQ, Mongo, PostgreSQL...) – nende YAML-id võivad olla ei Lülita välja. Rakendage need ka testkeskkonda... muidugi kohandades neid oma äranägemise järgi.

Lõplik puudutus

Sest kokkupanek ja kasutuselevõtt, kasutades praegu werfi töid ainult ehitusserveris (koos gitlab-runneriga) ja testidega pod käivitatakse masteris, peate looma kataloogi /mnt/tests meistrile ja anna see jooksjale, näiteks NFS-i kaudu. Üksikasjaliku näite koos selgitustega leiate aadressilt K8s dokumentatsioon.

Tulemuseks on:

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 NFS-i jagamist otse gitlab-runneris ja seejärel kaustadesse paigaldamist.

Märkus

Võib-olla küsite, miks teha töö loomisega kõike keeruliseks, kui saate lihtsalt käivitada skripti koos testidega otse shell runneris? Vastus on üsna triviaalne...

Mõned testid nõuavad juurdepääsu infrastruktuurile (MongoDB, RabbitMQ, PostgreSQL jne), et kontrollida nende korrektset toimimist. Muudame testimise ühtseks – selle lähenemisviisiga on selliste täiendavate üksuste kaasamine lihtne. Lisaks sellele saame standardne juurutamise lähenemisviis (isegi kui kasutate NFS-i, kataloogide täiendav ühendamine).

Tulemus

Mida me näeme, kui rakendame ettevalmistatud konfiguratsiooni?

Ühendamistaotlus näitab kokkuvõtvat statistikat viimases konveieris tehtud testide kohta:

JUnit GitLab CI-s Kubernetesiga

Üksikasjade vaatamiseks saab iga vea kohta klõpsata siin:

JUnit GitLab CI-s Kubernetesiga

NB: Tähelepanelik lugeja märkab, et testime NodeJS rakendust ja ekraanipiltidel - .NET... Ärge imestage: lihtsalt artiklit koostades ei leitud esimese rakenduse testimisel vigu, kuid need leiti teisest.

Järeldus

Nagu näete, pole midagi keerulist!

Põhimõtteliselt, kui teil on shell-kollektor juba olemas ja see töötab, kuid te ei vaja Kubernetest, on selle külge testimise kinnitamine veelgi lihtsam ülesanne, kui siin kirjeldatud. Ja sisse GitLab CI dokumentatsioon leiate näiteid Ruby, Go, Gradle, Maven ja mõnede teiste kohta.

PS

Loe ka meie blogist:

Allikas: www.habr.com

Lisa kommentaar