Настройка CI/CD для Gitlab-репозитория: схемы и гайд по шагам

—

от автора

Рассказываем, как работать с CI/CD. Сравнение инструментов и подробный гайд по сборке и развертыванию через Docker на удаленный сервер с помощью Gitlab CI/CD на примере Spring Boot-приложения.

Привет! Меня зовут Николай, я Backend-разработчик в РЕЛЭКС. В статье ты найдешь полезный теоретический материал и сравнение инструментов CI/CD. Покажу, как настроить сервер и поделюсь полезными командами, которые помогут в работе.

О чём внутри
  1. Начнём с теории: коротко о CI/CD — это база.

  2. Инструменты работы с CI/CD: выбираем свой.

  3. Как устроен процесс CI/CD: схема работы.

  4. Переходим к практике: настройка виртуального сервера.

  5. Настройка конфига .gitlab-ci.yml.

Начнём с теории: коротко о CI/CD — это база

CI/CD (Continuous Integration / Continuous Deployment) — это непрерывная интеграция и развертывание, предназначенные для повышения удобства, частоты и надежности публикации изменений программного обеспечения или продукта, где:

CI — это практика разработки ПО, при которой изменения в коде автоматически собираются, тестируются и интегрируются в целевую ветку репозитория. Основная идея — минимизация разрыва между компонентами проекта и быстрая обратная связь о качестве кода, благодаря автоматической сборке и тестированию.

CD — это продолжение CI, которое позволяет автоматически разворачивать успешно собранный и протестированный код на сервере или другой среде реального применения. Цель — автоматизация процесса разработки и развертывания приложения или программного продукта после всех этапов проверки и тестирования. Развертывание в продакшн должно выполняться после ручного подтверждения деплоя, чтобы предоставить дополнительный уровень контроля и безопасности.

Инструментов работы с CI/CD огромное множество — самыми популярными считаются:

  1. Gitlab CI/CD — полностью интегрированная в GitLab система для автоматизации сборки, тестирования и развертывания программного кода. GitLab CI/CD использует файл конфигурации YAML в репозитории проекта для определения правил работы на каждом этапе в пайплайне. Поддерживает использование Docker-образов для определения окружения сборки — отсюда большая гибкость и повторное использование кода.

  2. Jenkins — система с открытым исходным кодом для внедрения CI/CD для автоматизации процесса разработки. Jenkins — самостоятельное приложение, которое требует настройки на сервере, зато предлагает обширный набор плагинов. Это расширяет его функциональность и интеграцию с другими системами и сервисами.

  3. Azure DevOps — отдельное комплексное решение от Microsoft с набором инструментов разработки. Оно позволяет командам планировать работу, совместно создавать код и доставлять приложения. Для автоматизации сборки, тестирования и развертывания приложений используется инструмент Azure Pipelines.

  4. TeamCity — сервер непрерывной интеграции от JetBrains. У TeamCity открытая архитектура, которая позволяет разработчикам создавать плагины для расширения функционала. Некоторые функции бесплатны, но для больших команд и проектов может потребоваться покупка коммерческой лицензии, с чем сейчас возникают сложности.

Сравнительный анализ по наиболее показательным характеристикам

Сравнительный анализ по наиболее показательным характеристикам

Выбор инструмента зависит от ваших целей, задач и сложности реализации.

Задача — развернуть Spring Boot-приложение, расположенное в Gitlab-репозитории на продакшн стенде. Сделать это надо с помощью удобного и простого инструмента, чтобы начать использовать его функционал сразу, «из коробки» — Gitlab CI/CD отлично подходит. Он полностью интегрирован со средой Gitlab. Не требует дополнительной установки, а также имеет поддержку и подробную документацию.

С выбором инструмента разобрались. Перейдем к главному: как устроен процесс CI/CD. Ниже — схема его работы.

Как устроен процесс CI/CD: схема работы

Схема работы CI/CD

Схема работы CI/CD

Алгоритм схемы следующий:

  1. Разработчик пишет код и заливает его в GitLab-репозиторий проекта. 

  2. GitLab ищет в корне репозитория конфиг .gitlab-ci.yml и, когда находит, запускает пайплайн согласно описанной в конфиге логике.

Пайплайн (pipeline) представляет собой целиковый процесс из этапов или стадий (stage), которые состоят из задач (job). Каждая задача выполняется в изолированном процессе (используется GitLab Runner). 

Что за термины мы описали выше? 

  • Раннер (gitlab runner) — приложение, в рамках которого выполняются задачи и которое можно развернуть на разных типах систем: Linux, macOS, Windows, Docker, Kubernetes и так далее.

  • Задачи (jobs) — «кирпичики», из которых строится процесс CI/CD. Это может быть сборка проекта (компиляция, подтягивание зависимостей) или прогон автотестов, или публикация собранного кода в Docker-репозиторий. По умолчанию задачи выполняются изолированно, но их можно связать между собой при помощи артефактов. 

  • Артефакты (artifacts) — исполняемые файлы или пакеты для передачи результатов выполнения одной задачи на вход другой. Это позволяет управлять жизненным циклом программного продукта. Пример артефактов — скомпилированные бинарные файлы, архивы, образы контейнеров.

  • Этапы (stages) — служат для группировки задач и определения порядка их выполнения. Задачи, принадлежащие одному этапу, выполняются параллельно, если доступно достаточное количество раннеров. Этапы будут выполняться в порядке, указанном в конфиге.

  • Пайплайн (pipeline) — верхнеуровневый элемент процесса CI/CD, включающий в себя этапы и задачи.

Переходим от теории к практике. Теперь только пайплайны! Только хардкор!

Переходим к практике: настройка виртуального сервера

Переходим к настройке сервера. Процесс займет не одно действие, поэтому пойдем последовательно, шаг за шагом:

Шаг 1: Установка Docker

Официальный сайт руководства по Docker предоставляет удобный скрипт для неинтерактивной установки Docker. Такой вариант, скорее, подходит для рабочего окружения, а не для продакшена. 

С помощью curl-команды скачаем sh-файл для запуска и настройки докера.

curl -fsSL https://get.docker.com -o get-docker.sh

Затем запустим его для установки необходимых зависимостей.

sudo sh ./get-docker.sh

Шаг 2: Скачивание и запуск контейнера GitLab Runner в Docker

В официальном руководстве Gitlab есть описание нескольких вариантов GitLab Runner. В этой статье рассмотрим установку через Docker — более простую для развертывания и версионирования. Также меньше нагружает сервер скачиванием дополнительных пакетов. Для наших целей будем использовать облегченный образ GitLab Runner последней версии:

docker run -d --name gitlab-runner --restart always \   -v /srv/gitlab-runner/config:/etc/gitlab-runner \   -v /var/run/docker.sock:/var/run/docker.sock \   gitlab/gitlab-runner:alpine

После установки можно выполнить команду docker-ps и посмотреть, что появился контейнер с GitLab Runner. 

Помимо создания собственных раннеров, которые привязаны к конкретному проекту или группе, в GitLab есть так называемые “Shared runners”, которые доступны для всех проектов в пределах организации или всего инстанса GitLab. Такие раннеры обычно настраиваются администраторами и имеют общую конфигурацию, которую нельзя изменить на уровне отдельного проекта.

Облачная версия gitlab.com предоставляет несколько таких раннеров, которые можно использовать для ваших проектов. Они располагаются в блоке “Shared runners”. Проверьте, чтобы был активен чекбокс “Enable shared runners for this project”.

Шаг 3: Регистрация нового GitLab Runner 

Команда с официального руководства Gitlab, где:

— <Runner registration URL> — URL GitLab-сервера, с которым должен связаться Runner.

— <Registration token> — токен для установления связи между Runner и сервером.

Если вы используете свою установку GitLab, то в качестве параметра Runner registration URL, указываете ее URL-адрес. Если используется облачная версия, то https://gitlab.com/.

Чтобы узнать параметр Registration token перейдите в репозиторий проекта, в левой панели откройте меню Settings > CI/CD и разверните секцию Runners. В этой секции, в разделе Project runners, нажмите на троеточие справа от кнопки New project runner, где находится токен.

docker run --rm -it -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner:alpine register \   --non-interactive \   --url <Runner registration URL> \   --registration-token <Registration token> \   --executor docker \   --description "Brief description for the project" \   --tag-list "docker" \   --docker-image alpine:latest \   --docker-privileged \   --docker-volumes "/certs/client"

Выполнили команду — переходим во вкладку Runners в настройках CI/CD проекта. Там появится зарегистрированный раннер проекта, готовый к работе.

Шаг 4: Использование Container Registry для сохранения образа приложения

У gitlab есть интегрированный реестр докер-контейнеров (Container Registry). Так, у проекта появляется собственное пространство для хранения докер-образов, которые получили на этапе сборки. Перед использованием реестра контейнеров проверьте, что эта функция включена для вашего проекта. Для это откройте вкладку Visibility, project features, permissions в общих настройках проекта и сделаете чекбокс активным.

Чтобы сохранять и отправлять изображения, нужно пройти аутентификацию в реестре контейнеров. Для аутентификации нужно использовать один из представленных типов:

— Личный токен доступа (Personal access token).

— Токен доступа для деплоя (Deploy tokens).

В примере использовали личный токен доступа. Перейдём в настройки профиля, во вкладку Access token, где нужно выбрать Add new token.

Для всех типов токенов требуется минимальные правила:

  1. read_registry — доступ на чтение (pull).

  2. write_registry — доступ на запись (push).

Сохраните в буфер обмена получившийся токен и вставьте его в Docker команду для аутентификации в реестре контейнеров, где:

— <username> — ваше реальное имя пользователя.

— <token> — токен доступа.

Команда выполняется на сервере, где ранее установили Docker, чтобы там взаимодействовать с реестром контейнера

docker login registry.example.com -u <username> -p <token>

Шаг 5: Настройка SSH-ключа

SSH-ключ используется GitLab CI/CD для входа на сервер и выполнения процедуры развертывания. Сгенерируем 4096-разрядный SSH-ключ алгоритмом RSA (пара из открытого и закрытого ключей).

Флаг -C добавляет комментарий для идентификации ключа. В качестве комментария можно указать, например, имя пользователя. подтвердите оба вопроса с помощью Enter.

ssh-keygen -t rsa -b 4096 -C <username>

Чтобы авторизовать публичную часть SSH-ключа, осуществляющего развертывание, добавим её к authorized_keys файлу.

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

Затем сохраним приватный ключ в GitLab как CI/CD переменную, чтобы сделать его доступным в процессе работы раннера. Для этого выведем содержимое приватного ключа.

cat ~/.ssh/id_rsa

Копируем содержимое ключа в буфер обмена, переходим в настройки CI/CD проекта во вкладку Variable и нажимаем Add variable.

Шаг 6: Определяем оставшиеся переменные окружения CI/CD

Добавим оставшиеся переменные для развертывания приложения на сервере:

SERVER_USER — имя пользователя для подключения к удаленному серверу через SSH. Можете использовать действующего пользователя или создать отдельного в системе.

SERVER_HOST — IP-адрес удаленного сервера для подключения через SSH. Для переменной сделать активной опцию Mask variable 

ENV_FILE — путь к файлу с переменными окружения, который будет использован при выполнении команд Docker Compose. Для этого поля поменяете тип с variable на file. В поле для ввода переменные указываются через знак равенства с новой строки.

Таким образом в списке должны отображаться четыре переменные окружения.

На этом все подготовка закончилась. Переходим к настройке конфига .gitlab-ci.yml.

Настройка конфига .gitlab-ci.yml

Файл .gitlab-ci.yml располагается в корне репозитория и определяет структуру пайплайна и логику его работы. Gitlab при каждом поддерживаемом событии (например, push-изменений или создание merge request разработчиком) ищет его и проверяет, есть ли в нем описание для обработки наступившего события.

Ниже — файл .gitlab-ci.yml для сборки и развертывания Spring Boot-приложения в docker-контейнере. 

 stages:  - build  - deploy   build-only-MR:  stage: build  tags:    - docker  image:    name: gcr.io/kaniko-project/executor:v1.9.2-debug    entrypoint: [ "" ]  script:    - /kaniko/executor      --context "${CI_PROJECT_DIR}"      --dockerfile "${CI_PROJECT_DIR}/Dockerfile"      --no-push  only:    - merge_requests   build:  stage: build  tags:    - docker  image:    name: gcr.io/kaniko-project/executor:v1.9.2-debug    entrypoint: [ "" ]  script:    - /kaniko/executor      --context "${CI_PROJECT_DIR}"      --dockerfile "${CI_PROJECT_DIR}/Dockerfile"      --destination "${CI_REGISTRY_IMAGE}:latest"  only:    - main   deploy:  stage: deploy  image: docker:20.10-git  tags:    - gitlab-org-docker  variables:    DOCKER_HOST: "ssh://${SERVER_USER}@${SERVER_HOST}"  before_script:    - mkdir -p ~/.ssh    - chmod 700 ~/.ssh    - eval $(ssh-agent -s)    - echo "${SSH_PRIVATE_KEY}" | tr -d '\r' | ssh-add -    - '[[ -f /.dockerenv || -d /run/secrets/kubernetes.io/serviceaccount ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY  script:    - docker compose --env-file $ENV_FILE pull    - docker compose --env-file $ENV_FILE down --timeout=60 --remove-orphans    - docker compose --env-file $ENV_FILE up --build --detach    - docker image prune -f || true  only:    - main  when: manual

Пайплайн состоит из двух этапов: сборка и развертывание.

Для этапа сборки написаны две задачи: build-only-MR и build. Обе выполняются на gitlab-runner с тегом Docker, который ранее мы зарегистрировали.

Первая — для сборки проекта только при создании merge request-а. При этом получившийся Docker-образ не сохраняется в реестре контейнеров GitLab. 

Вторая задача для сборки проекта при вливании кода в ветку main. Получившийся Docker-образ пушится в реестр контейнеров GitLab с тегом latest. 

Для сборки Docker-образов из Dockerfile в директории проекта используется образ Kaniko. Это мощный инструмент для сборки образов Docker, который не требует наличия Docker-демона. Например, внутри своего контейнера или кластера Kubernetes. Использование Kaniko считается более быстрым и безопасным подходом, чем Docker-in-Docker.

Этап развертывания включает в себя одну задачу, которая выполняется на общем раннере с тэгом gitlab-org-docker. Это один из Shared runner, которые предоставляет облачная версия gitlab.com. 

Задача использует стандартный Docker-образ версии 20.10-git. В переменных задан путь для подключения к Docker на удаленном сервере через SSH. Переменные окружения SERVER_USER и SERVER_HOST определили ранее, как переменные CI/CD.

В блоке before_script выполняется настройка SSH для безопасного взаимодействия со стендом: создание директории, установка прав доступа для хранения SSH-ключа, инициализация SSH-агента, к которому добавляется приватный ключ из переменной окружения. После чего производится настройка параметров SSH. Затем авторизация в реестре контейнеров с использованием логина и пароля, хранящихся в переменных CI_REGISTRY_USER и CI_REGISTRY_PASSWORD — для получения доступа к собранным Docker-образам.

В блоке scripts подтягиваются обновления для образов с реестра. Затем останавливаются и удаляются текущие контейнеры — начинается запуск контейнеров в фоновом режиме с новыми скачанными образами из реестра. Крайняя команда удаляет все неиспользуемые образы.

Эта задача также выполняется только при вливании кода в ветку main и требует ручного подтверждения для запуска (опция when: manual).

Разворачивать будем REST-приложение на Java. Напишем контроллер, в котором будет один GET-запрос для теста, что приложение развернуто на удаленном сервере, и мы можем к нему обратиться.

Ниже — ключевые файлы, которые мы написали. 

Тестовый GET-запрос:

@CrossOrigin @RequestMapping("/test") @RestController public class TestController {      @GetMapping("/hello")    public ResponseEntity<String> getTest() {        return ResponseEntity.ok("Hello world");    } }

Dockerfile

FROM maven:3.8-openjdk-17-slim   RUN mkdir -p /home/app WORKDIR /home/app   ADD pom.xml /home/app ADD src /home/app/src   RUN mvn clean package CMD ["java", "-jar", "/home/app/target/test-0.0.1-SNAPSHOT.jar"]

docker-compose.yml

version: '3.9'   services:  core:    container_name: spring-application    image: registry.gitlab.com/my-test-project6/test-cicd-project:latest    environment:      TEST_SERVICE_PORT: ${TEST_SERVICE_PORT}      OPEN_API_TITLE: ${OPEN_API_TITLE}    ports:      - "8081:${TEST_SERVICE_PORT}"    logging:      driver: 'json-file'      options:        max-size: '100m'        max-file: '3'

Такой момент: мы используем переменные TEST_SERVICE_PORT — порт, на котором будет запущено приложение в Docker-контейнере и OPEN_API_TITLE — заголовок swagger-а. Прописав переменные в docker-compose-файле, мы указали нашему Java-приложению, что ее можно использовать как значение переменной в конфигурационном файле application.yml.

application.yml

server:  port: ${TEST_SERVICE_PORT}  servlet:    context-path: /api   api:  title: ${OPEN_API_TITLE}   springdoc:  api-docs:    path: /doc/api-docs  swagger-ui:    path: /doc/swagger-ui.html

Когда изменения кода зальются в main-ветку, начнется выполнение задачи build. Как только сборка успешно завершилась, можно деплоить на прод, нажав на значок запуска.

Через пару минут увидим, что приложение успешно прошло сборку и развертывание в Docker-контейнере на удаленном сервере.

Приложение доступно на порту 8081. Мы можем обратиться по API /api/test/hello и увидеть заветную надпись «Hello world». Готово!

Краткие выводы

CI/CD — важная практика разработки программного обеспечения для автоматизации процесса интеграции, тестирования и развертывания кода. Благодаря CI/CD команды разработчиков могут улучшать качество ПО и доставлять новые функции эффективнее и в более короткие сроки.

Приятных «‎разворачиваний»! Не бойтесь сложностей — это только начало!


ссылка на оригинал статьи https://habr.com/ru/articles/764568/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *