JUnit GitLab CI-ում Kubernetes-ի հետ

Չնայած այն հանգամանքին, որ բոլորը հիանալի գիտեն, որ ձեր ծրագրաշարի փորձարկումը կարևոր և անհրաժեշտ է, և շատերը դա անում են ավտոմատ կերպով երկար ժամանակ, Habr-ի հսկայական տարածքում չկար նման հանրաճանաչ արտադրանքների համադրություն ստեղծելու ոչ մի բաղադրատոմս: այս տեղը որպես (մեր սիրելի) GitLab և JUnit: Եկեք լրացնենք այս բացը։

JUnit GitLab CI-ում Kubernetes-ի հետ

Ներածական

Նախ, թույլ տվեք որոշակի ենթատեքստ տալ.

  • Քանի որ մեր բոլոր հավելվածներն աշխատում են Kubernetes-ով, մենք կքննարկենք համապատասխան ենթակառուցվածքի վրա թեստերի անցկացումը:
  • Հավաքման և տեղակայման համար մենք օգտագործում ենք վերֆ (ենթակառուցվածքի բաղադրիչների առումով սա նաև ինքնաբերաբար նշանակում է, որ Helm-ը ներգրավված է):
  • Ես չեմ խորանա թեստերի իրական ստեղծման մանրամասների մեջ. մեր դեպքում հաճախորդը ինքն է գրում թեստերը, և մենք միայն ապահովում ենք դրանց գործարկումը (և միաձուլման հարցումում համապատասխան զեկույցի առկայությունը):


Ինչպիսի՞ն կլինի գործողությունների ընդհանուր հաջորդականությունը:

  1. Հավելվածի կառուցում - մենք բաց կթողնենք այս փուլի նկարագրությունը:
  2. Տեղադրեք հավելվածը Kubernetes կլաստերի առանձին անվանատարածքում և սկսեք փորձարկումը:
  3. Արտեֆակտների որոնում և JUnit հաշվետվությունների վերլուծություն GitLab-ի հետ:
  4. Նախկինում ստեղծված անվանատարածքի ջնջում:

Այժմ՝ դեպի իրականացում:

հարմարեցում

GitLab CI

Սկսենք մի հատվածից .gitlab-ci.yaml, որը նկարագրում է հավելվածի տեղակայումը և թեստերը: Ցուցակը բավականին ծավալուն է ստացվել, ուստի այն մանրակրկիտ համալրվել է մեկնաբանություններով.

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

Կուբերնետես

Այժմ գրացուցակում .helm/templates եկեք ստեղծենք YAML Job-ի հետ - tests-job.yaml — թեստեր և Kubernetes-ի համար անհրաժեշտ ռեսուրսներ գործարկելու համար: Դիտեք բացատրությունները ցուցակագրելուց հետո.

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

Ինչպիսի ռեսուրսներ նկարագրված է այս կազմաձևում. Տեղադրելիս մենք ստեղծում ենք եզակի անվանատարածք նախագծի համար (սա նշված է .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) և տարածիր այն.

  1. ConfigMap թեստային սցենարով;
  2. Աշխատանք պատի նկարագրությամբ և նշված հրահանգով command, որը պարզապես կատարում է թեստերը;
  3. PV և PVC, որը թույլ է տալիս պահպանել թեստի տվյալները:

Ուշադրություն դարձրեք ներածական պայմանի հետ if մանիֆեստի սկզբում, համապատասխանաբար, Helm աղյուսակի այլ YAML ֆայլերը դիմումի հետ պետք է փաթաթվեն հակադարձ նախագծել այնպես, որ դրանք չտեղակայվեն փորձարկման ընթացքում: Այն է:

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

Այնուամենայնիվ, եթե թեստերը պահանջում են որոշակի ենթակառուցվածք (օրինակ՝ Redis, RabbitMQ, Mongo, PostgreSQL...) - նրանց YAML-ները կարող են լինել. ոչ անջատել. Տեղադրեք դրանք նաև թեստային միջավայրում…, իհարկե, հարմարեցնելով դրանք, ինչպես ձեզ հարմար է:

Վերջնական հպում

Որովհետեւ հավաքում և տեղակայում` օգտագործելով werf-ի աշխատանքները միայն build սերվերի վրա (gitlab-runner-ով), և թեստերով pod-ը գործարկվում է վարպետի վրա, ձեզ հարկավոր է ստեղծել գրացուցակ /mnt/tests վարպետի վրա և տվեք այն վազորդին, օրինակ՝ NFS-ի միջոցով. Բացատրություններով մանրամասն օրինակ կարելի է գտնել այստեղ K8s փաստաթղթեր.

Արդյունքը կլինի.

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

Ոչ ոք չի արգելում NFS-ի բաժնետոմս պատրաստել անմիջապես gitlab-runner-ում, այնուհետև տեղադրել այն pods-ում:

Նշում

Դուք կարող եք հարցնել, թե ինչու՞ ամեն ինչ բարդացնել՝ ստեղծելով Աշխատանք, եթե դուք կարող եք պարզապես գործարկել սկրիպտը թեստերով անմիջապես shell runner-ի վրա: Պատասխանը բավականին տրիվիալ է...

Որոշ թեստեր պահանջում են մուտք դեպի ենթակառուցվածք (MongoDB, RabbitMQ, PostgreSQL և այլն)՝ ստուգելու, որ դրանք ճիշտ են աշխատում: Մենք թեստավորումը դարձնում ենք միասնական. այս մոտեցմամբ հեշտ է դառնում նման լրացուցիչ սուբյեկտների ընդգրկումը: Բացի սրանից, մենք ստանում ենք ստանդարտ տեղակայման մոտեցումը (նույնիսկ եթե օգտագործում եք NFS, դիրեկտորիաների լրացուցիչ տեղադրում):

Արդյունք

Ի՞նչ կտեսնենք, երբ կիրառենք պատրաստված կոնֆիգուրացիան:

Միաձուլման հարցումը ցույց կտա ամփոփ վիճակագրություն իր վերջին խողովակաշարում իրականացվող թեստերի համար.

JUnit GitLab CI-ում Kubernetes-ի հետ

Մանրամասների համար յուրաքանչյուր սխալ կարող եք սեղմել այստեղ՝

JUnit GitLab CI-ում Kubernetes-ի հետ

NBՈւշադիր ընթերցողը կնկատի, որ մենք փորձարկում ենք NodeJS հավելվածը, իսկ սքրինշոթներում՝ .NET... Չզարմանաք, պարզապես հոդվածը պատրաստելիս սխալներ չեն հայտնաբերվել առաջին հավելվածի փորձարկման ժամանակ, սակայն դրանք. հայտնաբերվել են մեկ այլ.

Ամփոփում

Ինչպես տեսնում եք, ոչ մի բարդ բան չկա:

Սկզբունքորեն, եթե դուք արդեն ունեք կեղևի կոլեկցիոներ, և այն աշխատում է, բայց ձեզ Kubernetes-ի կարիք չկա, դրա վրա թեստավորումը կցելը նույնիսկ ավելի պարզ խնդիր կլինի, քան նկարագրված է այստեղ: Եվ մեջ GitLab CI փաստաթղթեր Դուք կգտնեք օրինակներ Ruby-ի, Go-ի, Gradle-ի, Maven-ի և մի քանիսի համար:

PS

Կարդացեք նաև մեր բլոգում.

Source: www.habr.com

Добавить комментарий