A pesar de que todo o mundo sabe perfectamente que probar o teu software é importante e necesario, e moitos levan facendo de forma automática durante moito tempo, na inmensidade de Habr non había nin unha soa receita para configurar unha combinación de produtos tan populares. este nicho como (o noso favorito) GitLab e JUnit . Imos cubrir este oco!
Introdución
En primeiro lugar, permíteme dar un pouco de contexto:
Dado que todas as nosas aplicacións se executan en Kubernetes, consideraremos realizar probas na infraestrutura adecuada.
Para montaxe e despregamento utilizamos werf (en termos de compoñentes de infraestrutura, isto tamén significa automaticamente que Helm está implicado).
Non entrarei nos detalles da creación real de probas: no noso caso, o cliente escribe el mesmo as probas e só aseguramos o seu lanzamento (e a presenza do informe correspondente na solicitude de fusión).
Como será a secuencia xeral de accións?
Creación da aplicación: omitiremos a descrición desta fase.
Implementa a aplicación nun espazo de nomes separado do clúster de Kubernetes e comeza a probar.
Buscando artefactos e analizando informes JUnit con GitLab.
Eliminando un espazo de nomes creado previamente.
Agora - á implementación!
axuste
GitLab CI
Comecemos cun fragmento .gitlab-ci.yaml, que describe a implantación da aplicación e a execución de probas. A lista resultou ser bastante voluminosa, polo que se complementou completamente con comentarios:
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
Agora no directorio .helm/templates imos crear YAML con Job - tests-job.yaml — para executar probas e os recursos de Kubernetes que necesita. Vexa as explicacións despois da lista:
Que tipo de recursos descrito nesta configuración? Ao implementar, creamos un espazo de nomes único para o proxecto (isto indícase en .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) e desenrola:
ConfigMap con guión de proba;
Traballo cunha descrición do pod e a directiva especificada command, que só executa as probas;
PV e PVC, que che permiten almacenar datos de proba.
Preste atención á condición introdutoria con if ao comezo do manifesto; en consecuencia, outros ficheiros YAML do gráfico Helm coa aplicación deben estar envoltos en á inversa deseñar para que non se despreguen durante as probas. É dicir:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
Con todo, se as probas requiren algunha infraestrutura (por exemplo, Redis, RabbitMQ, Mongo, PostgreSQL...) - os seus YAML poden ser non apagar. Imprógaos tamén nun ambiente de proba... axustándoos como creas oportuno, por suposto.
Preme final
Porque montaxe e despregamento usando werf works por agora só no servidor de compilación (con gitlab-runner) e o pod con probas lánzase no mestre, terás que crear un directorio /mnt/tests sobre o mestre e dálle ao corredor, por exemplo, a través de NFS. Pódese atopar un exemplo detallado con explicacións en Documentación K8s.
Ninguén prohibe facer un recurso compartido NFS directamente en gitlab-runner, e despois montalo en pods.
Nota
Podes estar preguntando por que complica todo creando un traballo se pode simplemente executar un script con probas directamente no shell runner? A resposta é bastante trivial...
Algunhas probas requiren acceso á infraestrutura (MongoDB, RabbitMQ, PostgreSQL, etc.) para verificar que funcionan correctamente. Facemos as probas unificadas; con este enfoque, faise doado incluír esas entidades adicionais. Ademais disto, conseguimos estándar enfoque de implantación (aínda que use NFS, montaxe adicional de directorios).
Resultado
Que veremos cando apliquemos a configuración preparada?
A solicitude de combinación mostrará estatísticas de resumo para as probas realizadas na súa última canalización:
Cada erro pódese facer clic aquí para obter máis información:
NB: O lector atento notará que estamos a probar unha aplicación NodeJS, e nas capturas de pantalla - .NET... Non te estrañes: é que ao preparar o artigo non se atoparon erros ao probar a primeira aplicación, pero si atopáronse noutro.
Conclusión
Como vedes, nada complicado!
En principio, se xa tes un colector de shell e funciona, pero non necesitas Kubernetes, engadirlle probas será unha tarefa aínda máis sinxela que a descrita aquí. E en Documentación de GitLab CI atoparás exemplos para Ruby, Go, Gradle, Maven e algúns outros.