Пайплайн gitlab для Spring REST приложения. Часть 1

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Непрерывная интеграция с помощью gitlab ci/cd - тема широко известная и часто встречающаяся в разных статьях в Интернет. Однако, большинство статьей построено как описание общих принципов - что это такое, какова общая структура файла gitlab-ci.yml, что такое стадии, скрипты и прочие элементы, которые используются для описания стадий. Но обычно в таких статьях мало конкретики и "живых" примеров реализации, выходящих за рамки декларации:

script:
    - echo $CI_BUILD_NAME

А между тем, именно написание скриптов и есть самый сложный элемент пайплайнов, а вовсе не понимание структуры и общих принципов построения. Во всяком случае, у меня сложилось именно такое впечатление, потому что разнообразие приложений фактически неисчислимо, среды и условия для развертывания также очень разнообразны, не говоря уже о конкретных языках программирования и фреймворках, и потому реализации конкретных пайплайнов могут различаться очень сильно, буквально, как небо и земля.
Также gitlab предоставляет обширную документацию, но разобраться в ней вовсе не просто в тех случаях, когда у вас приложение - не какой-то там "Hello world!", а что-то существенно посложнее и действительно предназначенное для продуктива. Как в документации gitlab, так и в большинстве статей примеры реализации обычно представляют собой краткое описание многочисленных, но разрозненных элементов пайплайна для данного конкретного узкого момента в одной отдельно взятой задаче, а не подробный разбор всего процесса в деталях, который мог бы дать общую картину. Не могу сказать за других, но вот лично мне всегда было легче что-то понять и освоить на конкретных примерах чужих проектов, читая и разбирая чужой код, а документация только помогала этому процессу. Поэтому данную статью я адресую по большей части тем коллегам java-разработчикам, которые страдают теми же самыми индивидуальными особенностями восприятия.

И тем не менее, поругав общую картину относительно gitlab ci/cd в Интернет, я рискую добавить к ней еще одно точно такое же описание, потому что вовсе не претендую на исчерпывающую полноту всех вариантов и в всех деталей. И ругать меня будут за то же самое, за что я ругал только что других. Ведь я также не собираюсь писать подробное руководство для совсем уж начинающих и объяснять базовые основы gitlab ci/cd, а намерен показать только его отдельные детали - но это будут именно самые интересные детали реализации скриптов для нескольких стадий, которых мне и, возможно, многим другим, как раз и не хватает. Надеюсь, что кому-то это может оказаться полезным.

Для описания я буду использовать REST API сервис, предназначенный для развертывания в kubernetes и написанный на Spring. Сервис не совсем "настоящий", но максимально приближенный к продуктовому. В нем есть:

  1. Обычная структура для REST API - репозитории, entity сервисы, контроллеры, сконфигурирован swagger через springfox, поскольку сервис учебный - безопасность Spring security не настраивалась.

  2. Настроен liquibase и миграции.

  3. Часть кода на уровне сервисов покрыта unit-тестами.

  4. Отлажены локально несколько модульных тестов с использованием testcontainers.

  5. В будущем предполагается один простой нагрузочный тест, но его мы будем настраивать сразу же в gitlab ci/cd, потому что он будет рассчитываться на использование контейнера k6.

  6. Отлажено развертывание сервиса в kubernetes при помощи helm.

Тем не менее, абсолютно все подробности и весь код самого проекта в статье приводиться не будет, это не очень интересно и только замусорит ваше внимание несущественными деталями - я сделаю основной упор на скрипты, а код приложения будет показан только там, где это нужно для понимания. Состав приложения я привел только для общего понимания - с чем мы имеем дело, и что мне потребовалось выполнить по ТЗ для создания и отладки пайплайна ci/cd. Как видим, это далеко не "Hello world!"

Простая стадия сборки для разработчиков отдельных новых функции

Прежде всего, мне потребовалось подстроиться под существующий процесс разработки, а не принудительно разворачивать собственный. Поэтому местами мой пайплайн будет выглядеть несколько странновато. Первым этапом стала разработка отдельных функций. Требование к процессу очень простое - создать стадию, на которой доработанный код приложения проверяется только лишь на сборку без ошибок, более ничего. Затем, если сборка прошла успешно, выполняется стадия развертывания кода приложения в kubernetes через helm на отдельном стенде, который представляет собой просто отдельный namespace кубера. Этот стенд будет использоваться тестировщиками для проверки правильной работы новой фичи. (Другие стенды также будут разворачиваться на том же самом физическом сервере в других namespace)

Пишем наши стадии, их будет четыре. Да-да, именно четыре, это связано с необходимостью работы с helm и особенностями его поведения в данной конкретной конфигурации пайплайна. Прежде всего, установим на сервере локально gitlab-runner и зарегистрируем его с экзекьютором shell. Не docker, не kubernetes экзекьютор, а именно shell - потому что в скрипте потребуется передавать обычные консольные команды helm. При регистрации обязательно добавим нужные тэги, когда консольный интерфейс регистрации попросит нас это сделать. Они понадобятся в пайплайне, чтобы стадии могли обратиться именно к "своему" gitlab-runner - потому что на сервере у вас их может быть зарегистрировано несколько. Первая стадия будет просто проверять возможность сборки приложения без ошибок, больше ничего она делать не будет, нет необходимости кэширования и сохранения артефактов - прошли стадию успешно - перешли в следующую. Никаких сложностей здесь нет, скрипт очень простой, выглядит это примерно вот так:

stages:
  - feature
feature development:
  tags:
    - feature
  stage: feature
  image: gradle:7.5.0-jdk11
  script:
    - cd rest-service
    - ./gradlew assemble

Здесь мы видим stage, который будет указывать на нужную стадию в секции stages, которая, в свою очередь, управляет порядком выполнения стадий - строго друг за другом. Здесь пока что мы видим одну стадию, другие мы добавим позже. Если вы привяжете к одной стадии несколько задач, они будут выполняться в рамках этой стадии параллельно в произвольном случайном порядке. Поэтому нужно внимательно следить, чтобы задачи в одной стадии не зависели друг от друга, иначе возможны накладки. Я эту проблему решаю самым простым способом - всегда связываю с одной стадией только одну задачу. image - это указание на docker образ, который будет использоваться в пайплайне gitlab для выполнения стадии. Приложение будет собираться внутри контейнера, создаваемого из этого образа. Тэг указывает на нужный gitlab-runner. Скрипт тоже очень простой, первая команда перемещает нас в отдельный каталог от корня приложения, это сразу же дает нам подсказку о том, файл build.gradle расположен не в корне приложения, и следовательно, это модульное приложение, и мы собираем и тестируем только один не зависимый от других модуль. Если бы модулей не было, эта строка кода не понадобилась бы, при запуске runner мы бы просто попали в корень приложения. Затем мы запускаем команду на сборку. Если сборка прошла успешно, больше ничего не проверяется и автоматически начинается следующая стадия.

Следующие стадии будут несколько посложнее, о них я расскажу в продолжении к данной статье.

А сейчас хочу пригласить всех на бесплатный урок от моих коллег из OTUS по теме: "Scope бинов в Spring".

  • Зарегистрироваться на бесплатный урок

Источник: https://habr.com/ru/company/otus/blog/695044/


Интересные статьи

Интересные статьи

В нашем мире, мире развития инновационных технологий, также неустанно развиваются и различные болезни, вирусы. В связи с этим людям рано или поздно придется переходить на время на дистанционный фо...
Здравствуйте! Сегодня мы напишем Slack Scrum покер бота на языке Go. Писать будем по возможности без фреймворков и внешних библиотек, так как наша цель – разобраться с яз...
Часть 1: Nuxt as fullstack server: frontend + backend API Server Часть 2: Additional SSR performance with Nuxt fullstack server Разработчики Nuxt предлагают 3 метода доступа к API: ...
Часть 2 Часть 3 Часть фотографий была взята с сайта Hack The Moon. Статья была представлена на 27-й ежегодной конференции по навигации и управлению Американского Общества Астронавтики (AAS...
В апреле этого года мы опубликовали перевод первого материала из цикла, посвящённого ответственному подходу к JavaScript-разработке. Там автор размышлял о современных веб-технологиях и об их раци...