JUnit di GitLab CI sareng Kubernetes

Sanaos kanyataan yén sadayana terang pisan yén nguji parangkat lunak anjeun penting sareng dipikabutuh, sareng seueur anu parantos ngalakukeunana sacara otomatis pikeun waktos anu lami, dina lega Habr teu aya resep tunggal pikeun nyetél kombinasi produk populér sapertos di Ecological ieu salaku (karesep urang) GitLab sareng JUnit. Hayu urang ngeusian jurang ieu!

JUnit di GitLab CI sareng Kubernetes

bubuka

Kahiji, hayu atuh masihan sababaraha konteks:

  • Kusabab sakabéh aplikasi urang ngajalankeun on Kubernetes, urang bakal mertimbangkeun ngajalankeun tés dina infrastruktur luyu.
  • Pikeun assembly sarta deployment kami nganggo werf (dina hal komponén infrastruktur, ieu ogé otomatis hartina Helm aub).
  • Kuring moal balik kana detil ngeunaan kreasi sabenerna tés: bisi urang, klien nu nyerat tés sorangan, sarta kami ngan mastikeun peluncuran maranéhanana (jeung ayana laporan pakait dina pamundut ngahiji).


Kumaha urutan umum lampah bakal kasampak kawas?

  1. Ngawangun aplikasi - urang bakal ngaleungitkeun pedaran tahap ieu.
  2. Nyebarkeun aplikasi ka spasi ngaran misah tina klaster Kubernetes tur mimitian nguji.
  3. Milarian artefak sareng nga-parsing laporan JUnit sareng GitLab.
  4. Ngahapus ngaranspasi saméméhna dijieun.

Ayeuna - pikeun palaksanaan!

carana ngatur

GitLab CI

Hayu urang mimitian ku sempalan .gitlab-ci.yaml, nu ngajelaskeun deploying aplikasi tur ngajalankeun tés. Daptar éta tétéla lumayan ageung, janten lengkep ditambah ku koméntar:

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

Ayeuna dina diréktori .helm/templates hayu urang ngadamel YAML sareng Ayub - tests-job.yaml - pikeun ngajalankeun tés sareng sumber daya Kubernetes anu diperyogikeun. Tingali katerangan saatos daptar:

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

Naon jenis sumberdaya dijelaskeun dina konfigurasi ieu? Nalika nyebarkeun, urang nyiptakeun ruang ngaran unik pikeun proyék éta (ieu dituduhkeun dina .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) sareng gulung kaluar:

  1. ConfigMap kalawan naskah tés;
  2. tugas kalayan katerangan ngeunaan pod sareng diréktif anu ditangtukeun command, nu ngan ngajalankeun tés;
  3. PV jeung PVC, nu ngidinan Anjeun pikeun nyimpen data tés.

Nengetan kaayaan bubuka kalawan if dina awal manifes - sasuai, file YAML séjén tina bagan Helm sareng aplikasina kedah dibungkus tibalik desain ambéh maranéhanana teu meunang deployed salila nguji. nyaeta:

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

Sanajan kitu, lamun tés merlukeun sababaraha infrastruktur (contona, Redis, RabbitMQ, Mongo, PostgreSQL ...) - YAMLs tiasa teu pareuman. Nyebarkeun aranjeunna kana lingkungan tés ogé ... nyaluyukeun aranjeunna sakumaha nu katingali pas, tangtosna.

touch ahir

Sabab assembly sarta deployment maké werf karya pikeun ayeuna ngan dina server ngawangun (kalayan gitlab-runner), sareng pod kalayan tés diluncurkeun dina master, anjeun kedah nyiptakeun diréktori /mnt/tests on master sarta masihan ka runner, contona, via NFS. Conto lengkep sareng katerangan tiasa dipendakan dina dokuméntasi K8s.

hasilna bakal kieu:

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

Teu aya anu ngalarang ngadamel saham NFS langsung dina gitlab-runner, teras dipasang dina pods.

nyarios

Anjeun tiasa naroskeun naha ngahesekeun sadayana ku nyiptakeun Proyék upami anjeun ngan saukur tiasa ngajalankeun naskah kalayan tés langsung dina pelari cangkang? Jawabanana rada sepele...

Sababaraha tés merlukeun aksés ka infrastruktur (MongoDB, RabbitMQ, PostgreSQL, jsb) pikeun pariksa yen aranjeunna jalan leres. Kami ngajantenkeun tés ngahijikeun - kalayan pendekatan ieu, janten gampang ngalebetkeun éntitas tambahan sapertos kitu. Salian ieu, urang meunang standar pendekatan deployment (sanajan ngagunakeun NFS, ningkatna tambahan tina directories).

hasil

Naon anu bakal urang tingali nalika urang nerapkeun konfigurasi anu disiapkeun?

Paménta gabungan bakal nunjukkeun statistik kasimpulan pikeun tés anu dijalankeun dina pipa anu pang anyarna:

JUnit di GitLab CI sareng Kubernetes

Unggal kasalahan tiasa diklik di dieu pikeun detil:

JUnit di GitLab CI sareng Kubernetes

NB: Nu maca attentive bakal aya bewara yen urang keur nguji aplikasi NodeJS, sarta dina Potret layar - .NET... Ulah heran: éta ngan bari Nyiapkeun artikel, euweuh kasalahan kapanggih dina nguji aplikasi munggaran, tapi aranjeunna kapanggih dina sejen.

kacindekan

Sakumaha anjeun tiasa tingali, euweuh pajeulit!

Sacara prinsip, upami anjeun parantos gaduh kolektor cangkang sareng tiasa dianggo, tapi anjeun henteu peryogi Kubernetes, ngalampirkeun tés éta bakal janten tugas anu langkung saderhana tibatan anu dijelaskeun di dieu. Jeung di Dokuméntasi GitLab CI anjeun bakal mendakan conto pikeun Ruby, Go, Gradle, Maven sareng sababaraha anu sanésna.

PS

Baca ogé dina blog urang:

sumber: www.habr.com

Tambahkeun komentar