JUnit katika GitLab CI pamoja na Kubernetes

Licha ya ukweli kwamba kila mtu anajua vizuri kwamba kupima programu yako ni muhimu na ni muhimu, na wengi wamekuwa wakifanya moja kwa moja kwa muda mrefu, katika ukubwa wa Habr hapakuwa na kichocheo kimoja cha kuanzisha mchanganyiko wa bidhaa hizo maarufu. niche hii kama (tuipendayo) GitLab na JUnit . Hebu tujaze pengo hili!

JUnit katika GitLab CI pamoja na Kubernetes

Utangulizi

Kwanza, wacha nitoe muktadha fulani:

  • Kwa kuwa maombi yetu yote yanatumia Kubernetes, tutazingatia kuendesha majaribio kwenye miundombinu inayofaa.
  • Kwa mkusanyiko na kupeleka tunatumia werf (kwa upande wa vipengele vya miundombinu, hii pia ina maana kwamba Helm inahusika).
  • Sitaingia katika maelezo ya uumbaji halisi wa vipimo: kwa upande wetu, mteja anaandika vipimo mwenyewe, na tunahakikisha tu uzinduzi wao (na kuwepo kwa ripoti inayofanana katika ombi la kuunganisha).


Je, mlolongo wa jumla wa vitendo utaonekanaje?

  1. Kuunda programu - tutaacha maelezo ya hatua hii.
  2. Sambaza programu kwenye nafasi tofauti ya majina ya nguzo ya Kubernetes na uanze kujaribu.
  3. Inatafuta vizalia vya programu na kuchanganua ripoti za JUnit na GitLab.
  4. Inafuta nafasi ya majina iliyoundwa hapo awali.

Sasa - kwa utekelezaji!

marekebisho

GitLab CI

Wacha tuanze na kipande .gitlab-ci.yaml, ambayo inaelezea kupeleka programu na kufanya majaribio. Orodha hiyo iligeuka kuwa kubwa sana, kwa hivyo iliongezewa kabisa na maoni:

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

Mabernet

Sasa kwenye saraka .helm/templates wacha tuunde YAML na Job - tests-job.yaml - kufanya majaribio na rasilimali za Kubernetes inazohitaji. Tazama maelezo baada ya kuorodhesha:

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

Rasilimali za aina gani ilivyoelezwa katika usanidi huu? Wakati wa kupeleka, tunaunda nafasi ya kipekee ya jina la mradi (hii imeonyeshwa katika .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) na kuifungua:

  1. ConfigMap na hati ya mtihani;
  2. Kazi na maelezo ya ganda na maagizo maalum command, ambayo inaendesha tu vipimo;
  3. PV na PVC, ambayo hukuruhusu kuhifadhi data ya jaribio.

Zingatia hali ya utangulizi na if mwanzoni mwa faili ya maelezo - ipasavyo, faili zingine za YAML za chati ya Helm na programu lazima zimefungwa kinyume kubuni ili wasiweze kupelekwa wakati wa kupima. Hiyo ni:

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

Walakini, ikiwa vipimo zinahitaji miundombinu fulani (kwa mfano, Redis, RabbitMQ, Mongo, PostgreSQL...) - YAML zao zinaweza kuwa hakuna kuzima. Zipeleke katika mazingira ya majaribio pia... kuzirekebisha unavyoona inafaa, bila shaka.

mguso wa mwisho

Kwa sababu kukusanyika na kupeleka kwa kutumia kazi za werf kwa sasa tu kwenye seva ya ujenzi (na gitlab-runner), na pod iliyo na vipimo imezinduliwa kwa bwana, utahitaji kuunda saraka. /mnt/tests juu ya bwana na kumpa mkimbiaji, kwa mfano, kupitia NFS. Mfano wa kina na maelezo unaweza kupatikana katika Nyaraka za K8s.

Matokeo yake yatakuwa:

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

Hakuna mtu anayekataza kushiriki NFS moja kwa moja kwenye gitlab-runner, na kisha kuiweka kwenye maganda.

Kumbuka

Unaweza kuwa unauliza kwa nini ugumu kila kitu kwa kuunda Kazi ikiwa unaweza tu kuendesha hati na vipimo moja kwa moja kwenye kiendesha ganda? Jibu ni dogo sana...

Baadhi ya majaribio yanahitaji ufikiaji wa miundombinu (MongoDB, RabbitMQ, PostgreSQL, n.k.) ili kuthibitisha kwamba yanafanya kazi kwa usahihi. Tunafanya majaribio kuwa ya umoja - kwa mbinu hii, inakuwa rahisi kujumuisha huluki kama hizo za ziada. Mbali na hili, tunapata kiwango mbinu ya kupeleka (hata ikiwa unatumia NFS, uwekaji wa ziada wa saraka).

Matokeo

Tutaona nini tunapotumia usanidi uliotayarishwa?

Ombi la kuunganisha litaonyesha muhtasari wa takwimu za majaribio yanayotekelezwa hivi punde:

JUnit katika GitLab CI pamoja na Kubernetes

Kila kosa linaweza kubofya hapa kwa maelezo:

JUnit katika GitLab CI pamoja na Kubernetes

NB: Msomaji makini ataona kwamba tunajaribu programu ya NodeJS, na katika skrini - .NET... Usistaajabu: ni kwamba tu wakati wa kuandaa makala, hakuna makosa yaliyopatikana katika kupima programu ya kwanza, lakini wao. zilipatikana katika nyingine.

Hitimisho

Kama unaweza kuona, hakuna kitu ngumu!

Kimsingi, ikiwa tayari unayo mtoza ganda na inafanya kazi, lakini hauitaji Kubernetes, kuambatanisha majaribio nayo itakuwa kazi rahisi zaidi kuliko ilivyoelezwa hapa. Na katika Nyaraka za GitLab CI utapata mifano ya Ruby, Go, Gradle, Maven na wengine wengine.

PS

Soma pia kwenye blogi yetu:

Chanzo: mapenzi.com

Kuongeza maoni