JUnit GitLab CI ar Kubernetes

Neskatoties uz to, ka visi lieliski zina, ka programmatūras testēšana ir svarīga un nepieciešama, un daudzi to jau ilgu laiku ir darījuši automātiski, Habras plašumos nebija nevienas receptes, kā izveidot tik populāru produktu kombināciju. šo nišu kā (mūsu iecienītāko) GitLab un JUnit. Aizpildīsim šo robu!

JUnit GitLab CI ar Kubernetes

Ievads

Vispirms ļaujiet man sniegt kontekstu:

  • Tā kā visas mūsu lietojumprogrammas darbojas Kubernetes, mēs apsvērsim iespēju veikt testus atbilstošajā infrastruktūrā.
  • Montāžai un izvietošanai mēs izmantojam werf (infrastruktūras komponentu ziņā tas automātiski nozīmē arī Helma iesaistīšanos).
  • Es neiedziļināšos detaļās par reālo testu izveidi: mūsu gadījumā klients pats raksta testus, un mēs nodrošinām tikai to palaišanu (un atbilstoša ziņojuma esamību apvienošanas pieprasījumā).


Kāda izskatīsies vispārējā darbību secība?

  1. Lietojumprogrammas izveide – šī posma aprakstu izlaidīsim.
  2. Izvietojiet lietojumprogrammu atsevišķā Kubernetes klastera nosaukumvietā un sāciet testēšanu.
  3. Artefaktu meklēšana un JUnit pārskatu parsēšana, izmantojot GitLab.
  4. Iepriekš izveidotās nosaukumvietas dzēšana.

Tagad - pie ieviešanas!

koriģēšana

GitLab CI

Sāksim ar fragmentu .gitlab-ci.yaml, kurā aprakstīta lietojumprogrammas izvietošana un testu izpilde. Saraksts izrādījās diezgan apjomīgs, tāpēc tas tika rūpīgi papildināts ar komentāriem:

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

Tagad direktorijā .helm/templates izveidosim YAML ar Jobu - tests-job.yaml — veikt testus un tai nepieciešamos Kubernetes resursus. Skatiet paskaidrojumus pēc iekļaušanas sarakstā:

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

Kādi resursi aprakstīts šajā konfigurācijā? Izvietojot, mēs izveidojam unikālu projekta nosaukumvietu (tas ir norādīts .gitlab-ci.yaml Sākot no tests-${CI_COMMIT_REF_SLUG}) un izrullējiet to:

  1. ConfigMap ar testa skriptu;
  2. Darbs ar pod aprakstu un norādīto direktīvu command, kas tikai palaiž testus;
  3. PV un PVC, kas ļauj saglabāt testa datus.

Pievērsiet uzmanību ievada nosacījumam ar if manifesta sākumā - attiecīgi citi Helm diagrammas YAML faili ar lietojumprogrammu ir jāiesaiņo otrādi dizains tā, lai tie netiktu izvietoti testēšanas laikā. Tas ir:

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

Tomēr, ja pārbaudes nepieciešama noteikta infrastruktūra (piemēram, Redis, RabbitMQ, Mongo, PostgreSQL...) - to YAML var būt izslēgt. Izvietojiet tos arī testa vidē... protams, pielāgojiet tos pēc saviem ieskatiem.

Galīgais pieskāriens

Jo montāža un izvietošana, izmantojot werf, joprojām darbojas tikai būvēšanas serverī (ar gitlab-runner), un pods ar testiem tiek palaists galvenajā datorā, jums būs jāizveido direktorijs /mnt/tests uz meistara un iedod to skrējējam, piemēram, izmantojot NFS. Detalizētu piemēru ar paskaidrojumiem var atrast K8s dokumentācija.

Rezultāts būs:

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

Neviens neaizliedz izveidot NFS koplietojumu tieši gitlab-runner un pēc tam uzstādīt to podiņos.

Piezīme

Iespējams, jūs jautāsiet, kāpēc visu sarežģīt, izveidojot darbu, ja varat vienkārši palaist skriptu ar testiem tieši čaulas palaidējā? Atbilde ir diezgan triviāla...

Dažiem testiem ir nepieciešama piekļuve infrastruktūrai (MongoDB, RabbitMQ, PostgreSQL utt.), lai pārbaudītu, vai tie darbojas pareizi. Mēs padarām testēšanu vienotu — ar šo pieeju ir viegli iekļaut šādas papildu entītijas. Papildus tam mēs iegūstam standarts izvietošanas pieeja (pat ja tiek izmantota NFS, papildu direktoriju montāža).

Piedzīvojiet efektīvu rezultātu spēku

Ko mēs redzēsim, kad izmantosim sagatavoto konfigurāciju?

Apvienošanas pieprasījumā tiks rādīta jaunākajā konveijerā veikto testu statistikas kopsavilkums:

JUnit GitLab CI ar Kubernetes

Par katru kļūdu var noklikšķināt šeit, lai iegūtu sīkāku informāciju:

JUnit GitLab CI ar Kubernetes

NB: Vērīgs lasītājs pamanīs, ka mēs testējam NodeJS aplikāciju, un ekrānšāviņos - .NET... Nebrīnieties: vienkārši gatavojot rakstu, pirmās aplikācijas testēšanā kļūdas netika atrastas, taču tās tika atrasti citā.

Secinājums

Kā redzat, nekas sarežģīts!

Principā, ja jums jau ir čaulas savācējs un tas darbojas, bet jums nav nepieciešams Kubernetes, testēšanas pievienošana tam būs vēl vienkāršāka, nekā šeit aprakstīts. Un iekšā GitLab CI dokumentācija jūs atradīsiet piemērus Ruby, Go, Gradle, Maven un dažiem citiem.

PS

Lasi arī mūsu emuārā:

Avots: www.habr.com

Pievieno komentāru