- PVSM.RU - https://www.pvsm.ru -
Если в качестве инфраструктуры, где разворачивается приложение, выступает Kubernetes, можно сказать, что существует два способа запуска тестов (и других утилит для анализа кода) в CI/CD:
Первый подход мы достаточно подробно описывали на интересном примере с базами данных в статье «Как мы выносили СУБД (и не только) из review-окружений в статическое [1]». В этой статье рассмотрен более простой путь — запуск вне K8s-кластера. Делать мы это будем на примере SonarQube-тестов в рамках CI/CD, построенного на базе GitLab с использованием werf.
Стоит помнить, что такой метод подходит только для тех тестов, которые не требуют подключения к другим объектам в инфраструктуре. С другой стороны, этот вариант хорош тем, что позволяет экономить кластерные ресурсы: нам не нужно выделять дополнительные ресурсы в K8s, поскольку вместо этого используются внешние мощности (локальных машин или сервера сборки/деплоя).
Для запуска тестов будет использоваться CI/CD-утилита werf [2], которая позволяет работать с полным жизненным циклом доставки приложений, а в частности — удобно собирать Docker-образы, а потом запускать их локально. Если вы уже используете werf, встраивание дополнительных команд будет совсем тривиальным, а если нет — на данном примере можно увидеть, как удобно контролировать все процессы CI/CD в одном месте.
Теперь — к непосредственной практике.
Основная особенность использования тестов и других анализаторов кода в CI/CD — необходимость устанавливать дополнительные пакеты/конфигурационные файлы в Docker-образ приложения. Установка все в один образ увеличивает размер итогового образа и добавляет неиспользуемые файлы во время запуска самого приложения.
В качестве альтернативного варианта* можно использовать отдельную сборку Docker-образа со всеми необходимыми зависимостями для тестов. Такая сборка будет выполняться параллельно сборке основного образа и использоваться только там, где требуется.
* Известная многим лучшая практика гласит, что для всех целей применения (от тестов и отладки до запуска в production) должен собираться единственный образ. Поэтому вариант со сборкой другого образа может быть допустим разве что для случаев, когда требуется тестировать только исходный код приложения. В таком варианте можно основной образ приложения использовать в виде артефакта [3] в образе для тестов.
Также обращаю внимание, что хотя последующие примеры основаны на использовании тестов с SonarQube [4], это не мешает выполнять аналогичные действия и с другими инструментами.
В werf реализация задуманного осуществляется с помощью переменных окружения, устанавливаемых в определенной Job в CI/CD-пайплайне.
Для конфигурации на стороне GitLab CI/CD потребуется определить Job с тестами (в .gitlab-ci.yml
) примерно так:
Build sonar-tests:
stage: build
script:
- werf build-and-publish
variables:
SONAR_TESTS: "yes"
tags:
- werf
only:
- schedules
Как видно, в variables
определяется переменная SONAR_TESTS
, которая и будет задействована в сборке через werf.
Не будем подробно останавливаться на том, как в целом реализуется сборка с помощью werf: эту информацию можно найти в документации утилиты [5], а полный конфиг для нашего случая будет приведен ниже.
В рамках подготовительных работ важно заметить, что в конфигурации сборки (werf.yaml
) появится следующий блок:
{{ if eq (env "SONAR_TESTS") "yes" }}
---
image: sonar-tests
from: node:10.16.0
# остальные этапы сборки
# ...
{{ end }}
Т.е. теперь мы можем обратиться к той переменной SONAR_TESTS
, что задали в GitLab CI/CD. Так легко контролировать этапы сборки с помощью переменных.
Перейдем к непосредственному созданию инструкций для сборки Docker-образа с помощью werf. В этом образе требуются следующие элементы:
Получается следующий набор инструкций для werf:
{{ $sonar_version := "4.4.0.2170"}}
{{ if eq (env "SONAR_TESTS") "yes" }}
---
image: sonar-tests
from: node:10.16.0
git:
- add: /
to: /app
ansible:
install:
- name: "npm install sonar"
shell: |
npm install --no-save -D sonarqube-scanner
args:
chdir: /app
- name: "Install default-jdk"
apt:
update_cache: yes
state: present
name:
- default-jdk
- name: "install sonarqube scanner"
args:
chdir: /app
shell: |
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-{{ $sonar_version }}.zip
mkdir -p /root/.sonar/native-sonar-scanner/
unzip -qq sonar-scanner-cli-{{ $sonar_version }}.zip -d /root/.sonar/native-sonar-scanner/
mv /root/.sonar/native-sonar-scanner/sonar-scanner-{{ $sonar_version }}/ /root/.sonar/native-sonar-scanner/sonar-scanner-{{ $sonar_version }}-linux/
- name: "Setup /app/sonar.js"
copy:
content: |
{{ tpl (.Files.Get ".werf/sonar.js") . | indent 8 }}
dest: /app/sonar.js
{{ end }}
{{ end }}
Опять же, полную информацию по структуре и содержанию werf.yaml можно найти в документации [6]. Здесь мы рассмотрим только основные инструкции. Итак, установка необходимых компонентов в образ состоит из следующих операций:
sonar
и sonarqube-scanner
. Эти пакеты требуются для поддержки SonarQube в Node.js-приложении.sonar-scanner
, для которого мы и устанавливаем JDK.sonar.js
с помощью функции .Files.Get
. Подробнее см. далее.
Что за файл, находящийся по адресу .werf/sonar.js
? Это конфиг, в котором хранится вся необходимая информация для запуска Sonar-тестов. Посмотрим на его содержимое:
{{ $_ := env "SONAR_TOKEN" | set . "Token" }}
{{ $_ := env "SONAR_PROJECT" | set . "Project" }}
{{ $_ := env "SONAR_URL" | set . "Url" }}
const sonarqubeScanner = require('sonarqube-scanner');
sonarqubeScanner( {
serverUrl : "{{ .Url }}",
token : "{{ .Token }}",
options: {
'sonar.projectName': "{{ .Project }}",
'sonar.projectDescription': 'Description for "{{ .Project }}" project...',
'sonar.sources': '.',
'sonar.projectKey': "{{ .Project }}",
'sonar.projectBaseDir': '/app'
}
},
() => process.exit()
)
В трёх первых строчках перечисляются переменные окружения, которые определяются, например, в GitLab CI/CD Variables. В дальнейшем, т.е. во время сборки/деплоя, эти переменные могут использоваться аналогично тому, как мы уже показывали в werf.yaml
(через встроенную конструкцию werf).
Подробнее об определяемых переменных:
SONAR_TOKEN
— токен, который вы создаете в самом SonarQube; именно через него производится авторизация в SonarQube;SONAR_PROJECT
— название созданного проекта в SonarQube;SONAR_URL
— URL к SonarQube (может быть как внешним URL, так и адресом до сервиса).
В результате сборки (werf build
) по таким конфигам (werf.yaml
и sonar.js
) получается Docker-образ (под названием sonar-tests
), который можно использовать для запуска Sonar-тестов, чем мы и займемся в следующей главе.
NB: Аналогичным образом можно собирать и запускать linting-тесты (речь не про что-то компилируемое), интеграционные тесты и т.д., причем даже в Kubernetes-окружении, а не только локально (в любом случае как минимум экономится место в основном образе).
Последний этап — запуск тестов локально на GitLab Runner.
Для этого в GitLab CI/CD определяется отдельная Job, в которой будут запускаться тесты. Например:
Deploy sonar-tests:
script:
- werf run sonar-tests -- bash -c "node /app/sonar.js"
tags:
- werf
stage: deploy
environment:
name: sonar-tests
only:
- schedules
variables:
SONAR_TESTS: "yes"
after_script:
- echo "Scan results are here https://sonar/dashboard?id=${SONAR_PROJECT}"
when: always
dependencies:
- Build sonar-tests
Здесь используется единственная команда:
werf run sonar-tests -- bash -c "node /app/sonar.js"
В её первой части указывается название образа для запуска (sonar-tests
, берётся из werf.yaml
), во второй — команда для выполнения внутри контейнера.
Теперь пайплайн будет запускать Sonar-тесты на GitLab Runner, а их результаты — публиковать в SonarQube Dashboard.
Описанный вариант запуска тестов в первую очередь будет полезен тем, кто уже использует werf или собирается его внедрить в своем проекте. С werf run
можно выполнять тесты непосредственно на самом Runner'е и вместо отдельных Docker-инструкций описывать всё непосредственно в werf, аккумулируя подобные элементы в одном месте.
Этот подход, конечно, позволяет запускать не только SonarQube-тесты: подойдут и любые другие решения, не требующие создания отдельного окружения для них (в виде отдельного сервера БД, очередей сообщений и т.д.).
Также он подойдет, если вы хотите запускать тесты не в кластере, а в локальном окружении или на самом Runner'е, не используя ресурсы кластера.
Кстати, для разработчиков, только начинающих знакомиться с werf, мы подготовили увлекательный онлайн-самоучитель по этой утилите — попробуйте [7]!
Читайте также в нашем блоге:
Автор: Ilya Andreev
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/gitlab/358672
Ссылки в тексте:
[1] Как мы выносили СУБД (и не только) из review-окружений в статическое: https://habr.com/ru/company/flant/blog/501424/
[2] werf: https://ru.werf.io/
[3] артефакта: https://ru.werf.io/documentation/advanced/building_images_with_stapel/artifacts.html
[4] SonarQube: https://www.sonarqube.org/
[5] документации утилиты: https://ru.werf.io/documentation/index.html
[6] документации: https://ru.werf.io/documentation/configuration/introduction.html
[7] попробуйте: https://ru.werf.io/applications_guide_ru/?utm_campaign=habr_sonarqube
[8] Организация распределенного CI/CD с помощью werf: https://habr.com/ru/company/flant/blog/504390/
[9] Динамическая сборка и деплой Docker-образов с werf на примере сайта версионированной документации: https://habr.com/ru/company/flant/blog/478690/
[10] Источник: https://habr.com/ru/post/526702/?utm_source=habrahabr&utm_medium=rss&utm_campaign=526702
Нажмите здесь для печати.