JUnit ing GitLab CI karo Kubernetes

Senadyan kasunyatan manawa kabeh wong ngerti yen nguji piranti lunak sampeyan penting lan perlu, lan akeh sing wis nindakake kanthi otomatis kanggo wektu sing suwe, ing jembar Habr ora ana resep siji kanggo nyetel kombinasi produk populer kasebut ing niche iki minangka (favorit kita) GitLab lan JUnit. Ayo padha isi longkangan iki!

JUnit ing GitLab CI karo Kubernetes

pambuka

Pisanan, aku menehi sawetara konteks:

  • Amarga kabeh aplikasi kita mlaku ing Kubernetes, kita bakal nimbang kanggo nganakake tes ing infrastruktur sing cocog.
  • Kanggo perakitan lan penyebaran kita digunakake werf (ing babagan komponen infrastruktur, iki uga kanthi otomatis tegese Helm melu).
  • Aku ora bakal njlèntrèhaké rinci babagan nggawe tes sing nyata: ing kasus kita, klien nulis tes kasebut dhewe, lan kita mung njamin peluncuran kasebut (lan anané laporan sing cocog ing panyuwunan gabungan).


Kaya apa urutan umum tumindak?

  1. Mbangun aplikasi - kita bakal ngilangi deskripsi tahap iki.
  2. Nyebarake aplikasi menyang ruang jeneng sing kapisah saka kluster Kubernetes lan miwiti nyoba.
  3. Nggoleki artefak lan parsing laporan JUnit karo GitLab.
  4. Mbusak spasi jeneng sing wis digawe sadurunge.

Saiki - kanggo implementasine!

imbuhan

GitLab CI

Ayo dadi miwiti karo pecahan .gitlab-ci.yaml, kang njlèntrèhaké deploying aplikasi lan mbukak tes. Dhaptar kasebut katon akeh banget, mula ditambahi kanthi lengkap karo komentar:

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

Saiki ing direktori .helm/templates ayo nggawe YAML karo Ayub - tests-job.yaml - kanggo mbukak tes lan sumber daya Kubernetes sing dibutuhake. Deleng panjelasan sawise dhaptar:

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

Apa jenis sumber daya diterangake ing konfigurasi iki? Nalika nyebarake, kita nggawe ruang jeneng unik kanggo proyek kasebut (iki dituduhake ing .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) lan gulung metu:

  1. ConfigMap karo script test;
  2. Job kanthi katrangan saka pod lan arahan sing ditemtokake command, sing mung mbukak tes;
  3. PV lan PVC, sing ngidini sampeyan nyimpen data tes.

Pay manungsa waé menyang kondisi pambuka karo if ing wiwitan manifest - miturut, file YAML liyane saka bagan Helm karo aplikasi kudu dibungkus mbalikke desain supaya padha ora njaluk disebarake sak testing. Iku:

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

Nanging, yen tes mbutuhake sawetara infrastruktur (contone, Redis, RabbitMQ, Mongo, PostgreSQL ...) - YAMLs bisa ora mateni. Nyebarake menyang lingkungan tes uga ... nyetel kaya sing dikarepake, mesthine.

tutul pungkasan

Amarga Déwan lan panyebaran nggunakake karya werf kanggo saiki mung ing server mbangun (karo gitlab-runner), lan pod karo tes diluncurake ing master, sampeyan kudu nggawe direktori /mnt/tests ing master lan menehi menyang runner, contone,, liwat NFS. Conto rinci kanthi panjelasan bisa ditemokake ing Dokumentasi K8.

Asil bakal:

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

Ora ana sing nglarang nggawe saham NFS langsung ing gitlab-runner, lan banjur dipasang ing pods.

komentar

Sampeyan bisa uga takon kenapa nggawe rumit kabeh kanthi nggawe Proyek yen sampeyan mung bisa mbukak skrip kanthi tes langsung ing pelari cangkang? Jawabane cukup sepele...

Sawetara tes mbutuhake akses menyang infrastruktur (MongoDB, RabbitMQ, PostgreSQL, lsp) kanggo verifikasi manawa bisa digunakake kanthi bener. Kita nggawe tes manunggal - kanthi pendekatan iki, dadi gampang kanggo nyakup entitas tambahan kasebut. Saliyane iki, kita entuk standar pendekatan penyebaran (sanajan nggunakake NFS, tambahan soyo tambah saka direktori).

asil

Apa sing bakal kita deleng nalika ngetrapake konfigurasi sing disiapake?

Panyuwunan gabungan bakal nuduhake statistik ringkesan kanggo tes sing ditindakake ing pipa paling anyar:

JUnit ing GitLab CI karo Kubernetes

Saben kesalahan bisa diklik ing kene kanggo rincian:

JUnit ing GitLab CI karo Kubernetes

NB: Pembaca sing ati-ati bakal sok dong mirsani yen kita lagi nyoba aplikasi NodeJS, lan ing gambar - .NET... Aja kaget: mung nalika nyiapake artikel, ora ana kesalahan nalika nyoba aplikasi pisanan, nanging padha ditemokake ing liyane.

kesimpulan

Nalika sampeyan bisa ndeleng, ora ana sing rumit!

Ing asas, yen sampeyan wis duwe cangkang kolektor lan bisa, nanging sampeyan ora perlu Kubernetes, masang testing kanggo iku bakal dadi tugas malah prasaja saka diterangake kene. Lan ing Dokumentasi GitLab CI sampeyan bakal nemokake conto kanggo Ruby, Go, Gradle, Maven lan sawetara liyane.

PS

Waca uga ing blog kita:

Source: www.habr.com

Add a comment