带有Kubernetes的GitLab CI中的JUnit

尽管每个人都知道测试软件非常重要和必要,并且许多人已经很长时间自动进行了测试,但是在Habr的开放空间中没有一个配方可以在此细分市场中设置一堆(我们最喜欢的)GitLab和JUnit这样受欢迎的产品。 。 填补这一空白!



介绍性


首先,我将概述背景:

  • 由于我们所有的应用程序都在Kubernetes中工作,因此我们将考虑在适当的基础架构中运行测试。
  • 对于组装和部署,我们使用werf (就基础架构组件而言,这也自动意味着涉及Helm)。
  • 我将不介绍直接创建测试的详细信息:在我们的案例中,客户端是自己编写测试的,我们仅确保测试能够运行(并且合并请求中提供了相应的报告)。

整个动作序列将是什么样的?

  1. 应用程序组装-我们将省略此阶段的描述。
  2. 将应用程序部署到单独的Kubernetes集群名称空间并启动测试。
  3. 通过GitLab搜索工件并解析JUnit报告。
  4. 删除以前创建的名称空间。

现在-实施!

客制化


吉它实验室


让我们从.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目录中,使用Job- tests-job.yaml创建一个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目录并将其提供给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 

没有人禁止直接在gitlab-runner上制作NFS球,然后将其安装在吊舱中。

注意事项


您可能会问,如果您可以直接在shell运行器上运行测试脚本,为什么要使Job的创建复杂化? 答案很简单...

一些测试需要访问基础架构(MongoDB,RabbitMQ,PostgreSQL等),以检查使用它们的正确性。 我们将测试统一化-通过这种方法,可以轻松地包含这样的其他实体。 除此之外,我们在部署中获得了一种标准方法(即使使用NFS,也需要进行附加目录安装)。

结果


应用准备好的配置后会看到什么?

合并请求将显示有关在其最后一个管道中启动的测试的摘要统计信息:



您可以单击每个错误以获取详细信息:



注意 :细心的读者会注意到我们正在测试NodeJS应用程序,并且在屏幕截图-.NET中...不要惊讶:在本文准备过程中,测试第一个应用程序没有错误,但在另一个应用程序中发现了错误。

结论


显然,没有什么复杂的!

原则上,如果您已经有一个shell生成器并且可以运行,并且不需要Kubernetes,那么将其拧紧测试将是比这里描述的还要简单的任务。 在GitLab CI文档中,您将找到Ruby,Go,Gradle,Maven等示例。

聚苯乙烯


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN460897/


All Articles