Kubernetes-тэй GitLab CI дахь JUnit

Хэдийгээр таны програм хангамжийг турших нь чухал бөгөөд шаардлагатай гэдгийг хүн бүр маш сайн мэддэг бөгөөд олон хүмүүс үүнийг удаан хугацааны турш автоматаар хийдэг байсан ч Хабрын өргөн уудам нутагт ийм алдартай бүтээгдэхүүнийг хослуулан тохируулах ганц жор байдаггүй байв. Энэ нь (бидний дуртай) GitLab болон JUnit юм. Энэ орон зайг нөхцгөөе!

Kubernetes-тэй GitLab CI дахь JUnit

Танилцуулга

Эхлээд би зарим нэг контекстийг хэлье:

  • Манай бүх програмууд Kubernetes дээр ажилладаг тул тохирох дэд бүтцэд туршилт хийх талаар авч үзэх болно.
  • Бид угсрах, байрлуулахад ашигладаг верф (дэд бүтцийн бүрэлдэхүүн хэсгүүдийн хувьд энэ нь мөн автоматаар Helm оролцож байна гэсэн үг).
  • Би туршилтыг бодитоор бий болгох нарийн ширийн зүйлийг ярихгүй: манай тохиолдолд үйлчлүүлэгч өөрөө тест бичдэг бөгөөд бид зөвхөн тэдгээрийг эхлүүлэх (мөн нэгтгэх хүсэлтэд холбогдох тайлан байгаа эсэхийг) баталгаажуулдаг.


Үйлдлүүдийн ерөнхий дараалал ямар байх вэ?

  1. Програмыг бүтээх - бид энэ үе шатны тайлбарыг орхих болно.
  2. Аппликешныг Кубернетес кластерын тусдаа нэрийн талбарт байрлуулж, туршилтыг эхлүүлнэ үү.
  3. Олдворуудыг хайж, GitLab ашиглан JUnit тайланг задлан шинжилж байна.
  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

Kubernetes

Одоо лавлахад байна .helm/templates Ажлын хамт YAML үүсгэцгээе - 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. Ажлын байр pod-ийн тодорхойлолт болон заасан удирдамжийн хамт command, энэ нь зүгээр л туршилтуудыг явуулдаг;
  3. PV ба PVC, энэ нь танд туршилтын өгөгдлийг хадгалах боломжийг олгоно.

-тэй танилцуулах нөхцөлийг анхаарч үзээрэй if манифестын эхэнд - үүний дагуу Helm диаграмын бусад YAML файлуудыг програмын хамт ороосон байх ёстой. урвуу туршилтын явцад тэдгээрийг байрлуулахгүй байхаар загварчлах. Тэр бол:

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

Гэсэн хэдий ч, хэрэв туршилтууд зарим дэд бүтэц шаардлагатай (жишээ нь, Redis, RabbitMQ, Mongo, PostgreSQL...) - тэдгээрийн YAML нь байж болно. үгүй хаах. Тэдгээрийг мөн туршилтын орчинд байрлуулна уу ... мэдээжийн хэрэг өөрийн үзэмжээр тохируулна уу.

эцсийн мэдрэгч

Учир нь werf ашиглан угсрах, байршуулах ажил одоогоор байна зөвхөн бүтээх сервер дээр (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 ашиглаж байсан ч лавлах нэмэлт холболт).

үр дүн

Бид бэлтгэсэн тохиргоог ашиглах үед юу харах вэ?

Нэгтгэх хүсэлт нь хамгийн сүүлд хийгдсэн туршилтуудын хураангуй статистикийг харуулах болно:

Kubernetes-тэй GitLab CI дахь JUnit

Алдаа бүрийг энд дарж дэлгэрэнгүй үзэх боломжтой:

Kubernetes-тэй GitLab CI дахь JUnit

NB: Анхааралтай уншигч бид NodeJS програмыг туршиж байгааг анзаарах бөгөөд дэлгэцийн агшинд - .NET... Гайхах хэрэггүй: зүгээр л нийтлэлийг бэлтгэх явцад эхний програмыг туршиж үзэхэд алдаа гараагүй, гэхдээ тэд өөр газраас олдсон.

дүгнэлт

Таны харж байгаагаар ямар ч төвөгтэй зүйл байхгүй!

Зарчмын хувьд хэрэв танд бүрхүүл цуглуулагч байгаа бөгөөд энэ нь ажиллаж байгаа боловч танд Кубернетес хэрэггүй бол тестийг хавсаргах нь энд тайлбарласнаас хамаагүй хялбар ажил байх болно. Тэгээд дотор GitLab CI баримт бичиг Та Ruby, Go, Gradle, Maven болон бусад хүмүүсийн жишээг олох болно.

PS

Мөн манай блог дээрээс уншина уу:

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх