JUnit في GitLab CI مع Kubernetes

على الرغم من حقيقة أن الجميع يعلمون أنه من الضروري والضروري اختبار البرنامج الخاص بك ، وأن الكثير منهم يقومون بذلك تلقائيًا لفترة طويلة ، لا توجد وصفة واحدة في الأماكن المفتوحة في Habr لإعداد مجموعة من هذه المنتجات الشائعة في هذه الفئة مثل GitLab و JUnit (المفضلة لدينا) . ملء هذه الفجوة!



استهلالي


أولاً ، سأوضح السياق:

  • نظرًا لأن جميع تطبيقاتنا تعمل في Kubernetes ، فسننظر في إجراء الاختبارات في البنية التحتية المناسبة.
  • للتجميع والنشر ، نستخدم werf (بمعنى مكونات البنية التحتية ، وهذا يعني أيضًا أن Helm متورط تلقائيًا).
  • لن أخوض في تفاصيل إنشاء الاختبارات مباشرةً: في حالتنا ، يكتب العميل الاختبارات بنفسه ، ونضمن فقط تشغيلها (ويتوفر التقرير المقابل في طلب الدمج).

كيف سيبدو التسلسل الكلي للأعمال؟

  1. تجميع التطبيق - سنحذف وصف هذه المرحلة.
  2. نشر التطبيق إلى مساحة اسم كتلة Kubernetes منفصلة وإطلاق الاختبار.
  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 

Kubernetes


الآن ، في دليل .helm/templates ، أنشئ YAML مع Job - 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} ) 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 الخاصة بهم. نشرها في بيئة اختبار ... بالطبع ، التغيير والتبديل كما تريد.

اللمسة النهائية


لأن التجميع والنشر باستخدام werf حتى الآن يعمل فقط على خادم الإنشاء (مع برنامج gitlab-runner) ، وسيتم تشغيل pod مع الاختبارات على المعالج ، وستحتاج إلى إنشاء دليل /mnt/tests على المعالج ومنحه إلى runner ، على سبيل المثال ، عبر 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 ، ثم تركيبها في القرون.

تعليق


قد تسأل ، لماذا تعقد كل شيء مع إنشاء Job ، إذا كان يمكنك فقط تشغيل البرنامج النصي للاختبار مباشرةً على برنامج shell؟ الجواب تافهة جدا ...

تتطلب بعض الاختبارات الوصول إلى البنية التحتية (MongoDB ، RabbitMQ ، PostgreSQL ، إلخ) للتحقق من صحة العمل معهم. نجعل الاختبار موحدًا - مع هذا النهج ، يصبح من السهل تضمين مثل هذه الكيانات الإضافية. بالإضافة إلى ذلك ، نحصل على نهج قياسي في النشر (حتى لو كان استخدام NFS ، دليل إضافي متصاعد).

يؤدي


ماذا سوف نرى عندما نطبق التكوين المعدة؟

سيُظهر طلب الدمج إحصائيات موجزة عن الاختبارات التي تم إطلاقها في خط الأنابيب الأخير:



يمكنك النقر على كل خطأ هنا للحصول على التفاصيل:



ملحوظة : سوف يلاحظ القارئ اليقظ أننا نقوم باختبار تطبيق NodeJS ، وفي لقطات الشاشة - .NET ... لا تفاجأ: فقط كجزء من إعداد المقال ، لم تكن هناك أخطاء في اختبار التطبيق الأول ، ولكن تم العثور عليها في تطبيق آخر.

استنتاج


على ما يبدو ، لا شيء معقد!

من حيث المبدأ ، إذا كان لديك بالفعل أداة إنشاء صدفة وكانت تعمل ، ولم تكن بحاجة إلى Kubernetes ، فستكون مهمة اختبار اللولب مهمة أكثر بساطة من الموصوفة هنا. وفي وثائق GitLab CI ، ستجد أمثلة على Ruby و Go و Gradle و Maven وبعض الآخرين.

PS


اقرأ أيضًا في مدونتنا:

Source: https://habr.com/ru/post/ar460897/


All Articles