JUnit በ GitLab CI ከኩበርኔትስ ጋር

ምንም እንኳን የሶፍትዌርዎን መሞከር አስፈላጊ እና አስፈላጊ መሆኑን ሁሉም ሰው በትክክል ቢያውቅም እና ብዙዎች በራስ-ሰር ለረጅም ጊዜ ሲያደርጉት የቆዩ ቢሆንም ፣ በሀብር ሰፊነት ውስጥ እንደዚህ ያሉ ታዋቂ ምርቶችን ጥምረት ለማዘጋጀት አንድ የምግብ አዘገጃጀት መመሪያ አልነበረም ። ይህ ቦታ እንደ (የእኛ ተወዳጅ) GitLab እና JUnit . ይህንን ክፍተት እንሙላው!

JUnit በ GitLab CI ከኩበርኔትስ ጋር

መግቢያ

በመጀመሪያ፣ አንዳንድ አውድ ልስጥ፡-

  • ሁሉም አፕሊኬሽኖቻችን በ Kubernetes ላይ ስለሚሰሩ በተገቢው መሠረተ ልማት ላይ ፈተናዎችን ማካሄድን እናስባለን።
  • ለመገጣጠም እና ለማሰማራት እንጠቀማለን werf (በመሠረተ ልማት ክፍሎች, ይህ በራስ-ሰር ሄልም ይሳተፋል ማለት ነው).
  • ወደ ትክክለኛ የፈተናዎች አፈጣጠር ዝርዝሮች ውስጥ አልገባም: በእኛ ሁኔታ, ደንበኛው ራሱ ፈተናዎችን ይጽፋል, እና የእነሱን ጅምር ብቻ እናረጋግጣለን (እና በውህደት ጥያቄ ውስጥ ተዛማጅ ዘገባ መኖሩን).


አጠቃላይ የድርጊቶች ቅደም ተከተል ምን ይመስላል?

  1. አፕሊኬሽኑን መገንባት - የዚህን ደረጃ መግለጫ እናስወግዳለን.
  2. አፕሊኬሽኑን ወደ የተለየ የኩበርኔትስ ክላስተር የስም ቦታ ያሰማሩት እና መሞከር ይጀምሩ።
  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ን ከኢዮብ ጋር እንፍጠር - tests-job.yaml - ሙከራዎችን እና የሚፈልገውን የኩበርኔትስ ሀብቶችን ለማሄድ። ከዝርዝሩ በኋላ ማብራሪያዎችን ይመልከቱ፡-

{{- 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 በማንፀባረቁ መጀመሪያ ላይ - በዚህ መሠረት ከመተግበሪያው ጋር ሌሎች የ YAML ፋይሎች የ Helm ገበታ መጠቅለል አለባቸው ተገላቢጦሽ በሙከራ ጊዜ እንዳይሰማሩ ዲዛይን ያድርጉ። ያውና:

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

ነገር ግን, ፈተናዎች ከሆነ አንዳንድ መሠረተ ልማት ያስፈልገዋል (ለምሳሌ፣ Redis፣ RabbitMQ፣ Mongo፣ PostgreSQL...) - YAMLs ሊሆኑ ይችላሉ። አይደለም ኣጥፋ. ወደ ለሙከራ አካባቢም ያሰፍሯቸው... እንደፈለጉት ማስተካከል እርግጥ ነው።

የመጨረሻ ንክኪ

ምክንያቱም ዌርፍን በመጠቀም መሰብሰብ እና ማሰማራት ለአሁን ይሰራል ብቻ በግንባታ አገልጋይ ላይ (ከgitlab-ሯጭ ጋር) ፣ እና ከሙከራዎች ጋር ያለው ፖድ በጌታው ላይ ተጀምሯል ፣ ማውጫ መፍጠር ያስፈልግዎታል /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-ሯነር ላይ ማድረግ እና ከዚያ በፖድ ውስጥ መጫንን አይከለክልም።

አመለከተ

በቀላሉ በሼል ሯጭ ላይ ስክሪፕት ከፈተናዎች ጋር መሮጥ ከቻሉ ስራ በመፍጠር ሁሉንም ነገር ለምን እንደሚያወሳስብ ትጠይቅ ይሆናል። መልሱ በጣም ቀላል ነው ...

አንዳንድ ሙከራዎች በትክክል መስራታቸውን ለማረጋገጥ የመሠረተ ልማት አውታሮችን (MongoDB፣ RabbitMQ፣ PostgreSQL፣ ወዘተ) ማግኘት ያስፈልጋቸዋል። ሙከራን አንድ ወጥ እናደርጋለን - በዚህ አቀራረብ ፣ እንደዚህ ያሉ ተጨማሪ አካላትን ማካተት ቀላል ይሆናል። ከዚህ በተጨማሪ, እናገኛለን መደበኛ የማሰማራት አቀራረብ (NFS ን ቢጠቀሙም, ተጨማሪ ማውጫዎችን መጫን).

ውጤት

የተዘጋጀውን ውቅረት ስንተገበር ምን እናያለን?

የውህደት ጥያቄው በመጨረሻው የቧንቧ መስመር ውስጥ ለሚካሄዱ ሙከራዎች ማጠቃለያ ስታቲስቲክስን ያሳያል፡

JUnit በ GitLab CI ከኩበርኔትስ ጋር

ለዝርዝሮች እያንዳንዱ ስህተት እዚህ ጠቅ ማድረግ ይቻላል፡

JUnit በ GitLab CI ከኩበርኔትስ ጋር

NB: በትኩረት የሚከታተለው አንባቢ የ NodeJS መተግበሪያን እየሞከርን መሆኑን ያስተውላል, እና በስክሪፕቶች ውስጥ - .NET ... አትደነቁ: ጽሑፉን በሚያዘጋጁበት ጊዜ, የመጀመሪያውን መተግበሪያ በመሞከር ላይ ምንም ስህተቶች አልተገኙም, ግን እነሱ በሌላ ውስጥ ተገኝተዋል.

መደምደሚያ

እንደምታየው, ምንም የተወሳሰበ ነገር የለም!

በመርህ ደረጃ, ቀድሞውኑ የሼል ሰብሳቢ ካለዎት እና ቢሰራ, ነገር ግን Kubernetes አያስፈልግዎትም, ሙከራን ከእሱ ጋር ማያያዝ እዚህ ከተገለፀው የበለጠ ቀላል ስራ ይሆናል. እና ውስጥ GitLab CI ሰነድ ለ Ruby, Go, Gradle, Maven እና አንዳንድ ሌሎች ምሳሌዎችን ያገኛሉ.

PS

በብሎጋችን ላይ ያንብቡ፡-

ምንጭ: hab.com

አስተያየት ያክሉ