77

使用GitLab CI运行Kubernetes里的应用程序的JUnit测试

 3 years ago
source link: https://www.tuicool.com/articles/euEFzmJ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

每个人都知道软件测试的重要性和必要性-我相信许多人都坚持这样做。但出乎意料的是,我很难找到一个很好的例子来用GitLab和JUnit配置CI / CD。让我来填补这个空白。

背景

首先,让我定义完整的上下文:

  • 由于我们所有的应用程序都在Kubernetes中运行,因此我仅介绍相关架构中的测试
  • 我会使用 werf 来构建和部署映像(这意味着Helm也会参与到流水线中)
  • 我不会详细介绍测试本身:在我们的案例中,测试是在使用者实施的,我们仅确保测试正常运行(并在合并请求中显示相应的报告)

以下是我们的示例中常见的操作顺序:

  1. 构建应用程序-我们将省略此步骤的描述
  2. 将应用程序部署到Kubernetes集群的独立命名空间并运行测试
  3. 通过GitLab检索artifacts并解析JUnit报告
  4. 删除之前创建的命名空间

让我们开始实践吧!

GitLab CI (Continuous Integration, 持续集成)

我们将从 .gitlab-ci.yaml 的代码开始,以下部分描述了应用程序的部署和运行测试。代码有点长,我在其中插入了详细的注释:

variables:

声明我们将使用的werf的版本

WERF_VERSION: "1.0 beta"

.base_deploy: &base_deploy

script:

如果K8S不存在该命名空间则创建命名空间

- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}

加载werf并部署 - 详情请查看文档

( https://werf.io/how_to/gitlab_ ... -stag e)

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

设置超时(某些测试耗时很长)

并将其传递给发布

--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需要artifacts在其构建目录中

- mkdir ./tests || true

- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}

after_script:

在完成测试后用作业删除发布(以及其基础设施)

- 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 context, 文档请查看以下连接

( https://werf.io/how_to/gitlab_ ... uctur e)

WERF_KUBE_CONTEXT: '[email protected]'

tags:

使用带有 werf-runner 标签的runner

- werf-runner

artifacts:

首先必须创建一个artifact才能在流水线中查看

并下载它(例如,用于进行更深入的研究)

paths:

- ./tests/${CI_COMMIT_REF_SLUG}/*

超过一周的artifact将被删除

expire_in: 7 day

注意:以下这几行用于GitLab解析报告

reports:

junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml

为了简单起见,这里仅显示两个阶段

在现实中,你可能有更多阶段

stages:

- build

- tests

build:

stage: build

script:

build stage - 请查看werf相关文档:

( https://werf.io/how_to/gitlab_ ... -stag e)

- 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:

给命名空间命名

( https://docs.gitlab.com/ce/ci/ ... s.htm l)

name: tests-${CI_COMMIT_REF_SLUG}

stage: tests

except:

- schedules

Kubernetes

现在是时候创建一个YAML文件( tests-job.yaml )了,这个文件用来做两件事

.helm / templates

请参阅以下说明:

{{- 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描述和运行测试的 指令Job
  3. PV和PVC 将存储测试数据

注意清单开头的初始 if 语句。 为了防止使用应用程序部署Helm图表的其他YAML文件,您必须插入以下相反条件:

{{- if ne .Values.global.run_tests "yes" }}

Hey, I'm another YAML

{{- end }}

但是,如果一些测试需要 其他的基础设施 (如redis,rabbitmq, Mongo, PostgreSQL等等),那么你可以在相应的YAML文件中启动并部署这些组件到测试环境中。

最后一点

当前,仅通过构建服务器(使用gitlab-runner)支持使用werf进行构建和部署。 但是,测试容器在主节点上运行。 在这种情况下,您必须在主节点上创建 /mnt/tests 文件夹并将其安装到运行器(runner), 例如 通过NFS 。 K8s文档中提供了 详细示例

我们将会得到以下结果

[email protected]:~$ cat /etc/exports | grep tests

/mnt/tests    IP_gitlab-builder/32(rw,nohide,insecure,no_subtree_check,sync,all_squash,anonuid=999,anongid=998)



[email protected]:~$ cat /etc/fstab | grep tests

IP_kube-master:/mnt/tests    /mnt/tests   nfs4    _netdev,auto  0       0

另一种可能性是直接在gitlab-runner上创建一个共享的NFS目录,然后将其安装到pod上。

注释

您可能会问,如果可以轻松地在shell中运行测试脚本,那么创建Job的意义何在?答案很明显:

有些测试需要基础架构(例如MongoDB,RabbitMQ,PostgreSQL等)来检查功能。我的方法是一个统一的解决方案,可以轻松集成其他实例。另外,我们获得了 标准 的部署方法(即使用NFS和额外的目录)。

结果

如果应用提前准备好的配置会是什么结果?

合并请求中将显示在其先前流水线中执行的测试的摘要:

eEbm6ze.png!web

单击错误获取更多信息:

NNFviyB.png!web

*注意:细心的读者会注意到我们正在测试Node.js应用程序,但是屏幕截图上有一个.NET。不必感到惊讶:虽然我们在原始的应用程序中没有发现任何问题,但在另一个应用程序中暴露出了一些小问题。

结论

如您所见,它是如此简单!

如果您已经有可以使用的Shell脚本并且不需要Kubernetes,则可以通过更简单的方法实现以上例子。 请查看 GitLab CI 文档 。CI文档中提供了Ruby,Go,Gradle,Maven和其他一些产品的示例。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK