> For the complete documentation index, see [llms.txt](https://book.konstantinsecurity.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.konstantinsecurity.com/readme/architect/ci-cd/gitlab-runner-in-yandex-cloud.md).

# GitLab Runner in Yandex Cloud

<https://habr.com/ru/articles/696366/>

![](/files/wrfCrCKlRqmFKtOUsAMO)

У нас в профсоюзе недавно появился сервис, который используется для создания публикаций в социальных сетях. Проект находится в GitLab, но с недавних пор использовать Shared Runners в GitLab не представляется возможным, поскольку для этого требуется подключить банковскую карту, а российские карты не принимаются. Открыть счёт в банке другой страны непросто, поэтому было решено развернуть GitLab Runner в Yandex Cloud, поскольку сервис уже развёрнут в Yandex Serverless Containers.

Развернуть GitLab Runner в Yandex Cloud можно в Managed Service for GitLab или на виртуальных машинах (далее ВМ). Сравнение этих сервисов в схожих конфигурациях:

\| Сервис | Конфигурация | Особенности | Стоимость, ₽ / месяц | | --- | --- | --- | --- | | Managed Service for GitLab | vCPU: 2 RAM: 8 Гб Disk: SSD 30 Гб | SaaS, предустановленный GitLab | 5 401,50 | | ВМ с образом GitLab | vCPU: 4 Intel Ice Lake, 100% RAM: 8 Гб Disk: SSD 30 Гб | Предустановленный GitLab | 5 166,90 | | Чистая ВМ | vCPU: 2 Intel Ice Lake, 100% RAM: 8 Гб Disk: SSD 30 Гб | Чистая ОС | 3 654,90 |

Чистая ВМ — наиболее подходящий вариант, поскольку Managed Service for GitLab и ВМ с образом GitLab обходятся относительно дороже и имеют излишнюю функциональность для текущей задачи. Кроме того, чистая ВМ более гибкая в выборе вычислительных ресурсов, так что стоимость использования может быть ниже. Например, следующая конфигурация обойдётся в 754,65 ₽ / месяц:

* vCPU: 2, Intel Ice Lake, 20%
* RAM: 4 Гб
* Disk: SSD 15 Гб
* Прерываемая ВМ

Но было бы слишком расточительно оставлять ВМ запущенной круглые сутки, ведь работа GitLab Runner может занимать всего несколько минут. Поэтому после недолгих раздумий был придуман финт ~~ушами~~ функциями.

Суть финта: запускать ВМ только при создании нового пайплайна в проекте, а в остальное время держать в выключенном состоянии. В таком случае стоимость использования ВМ сократится до пары сотен рублей. Диаграмма последовательности для такой функциональности представлена ниже.

![](/files/psrIOZm4VpwVgh2pqIZF)

## Пререквизиты

Необходим [аккаунт в Yandex Cloud](https://cloud.yandex.ru/docs/getting-started/quickstart-individuals) и [репозиторий в GitLab](https://docs.gitlab.com/ee/user/project/repository/). В этом примере [репозиторий](https://gitlab.com/ruitunion/gitlab-runners-in-yandex-cloud) уже содержит приложение и Dockerfile к нему. Требуется собрать и протестировать приложение, затем собрать Docker-образ и опубликовать его в реестре проекта.

![](/files/N2UET0uH9Rb0RzmPponr)

Заострять внимание на самом проекте нет смысла, так как приложение роли не играет. Если у вас другой стек, то изменения будут в Dockerfile и .gitlab-ci.yml. В данном случае приложение — это Web API на [ASP.NET](http://asp.net/) Core, сгенерированное командой:

```
dotnet new webapi –use-minimal-apis –no-openapi
```

## Создание и настройка ВМ в Compute Cloud

### Создание ВМ в Compute Cloud

Переходим в раздел Compute Cloud / Виртуальные машины и нажимаем **«Создать ВМ»**.

![](/files/ejDA6pcIjQGtoKRM1D5s)

Присваиваем имя, выбираем зону доступности и ОС, которая больше нравится. Например, Ubuntu:

![](/files/Yu88GjpZmvwZqcuIPFBH)

Настраиваем диск и вычислительные ресурсы, исходя из потребностей. Для простых приложений, в том числе и для нашего примера, подойдёт 20% гарантированной доли двух vCPU и 4 Гб RAM.

![](/files/fLn4Fwu2RcjkqFo15QWM)

Выбираем сервисный аккаунт с ролью compute.operator. Этой роли достаточно [для запуска и остановки ВМ](https://cloud.yandex.ru/docs/compute/security/). Если такого сервисного аккаунта нет, то создаём. Этот аккаунт необходим для управления ВМ из функции, которая будет создана далее.

Вводим логин для пользователя ОС, SSH-ключ для [подключения по SSH](https://cloud.yandex.ru/docs/compute/operations/vm-connect/ssh) и нажимаем **«Создать ВМ»**.

![](/files/sUZc2vMHZ2R4rx252kIF)

Дожидаемся создания ВМ и переходим к следующему шагу.

### Установка GitLab Runner

Сперва подключимся к ВМ. Для этого копируем публичный IP-адрес ВМ и [подключаемся по SSH](https://cloud.yandex.ru/docs/compute/operations/vm-connect/ssh).

![](/files/ubMfJ0GNTWjoabB9Utjt)

Есть несколько способов [установить GitLab Runner](https://docs.gitlab.com/runner/install/). В нашем примере будет использоваться Docker, так как это наиболее универсальный вариант. Инструкция по установке Docker Engine для разных ОС лежит [тут](https://docs.docker.com/engine/install/).

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

```
sudo systemctl enable docker
```

Осталось [загрузить и запустить образ с GitLab Runner](https://docs.gitlab.com/runner/install/docker.html). Сделаем это с подключением локальных томов.

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

Отключаться от ВМ не нужно, так как ещё необходимо зарегистрировать раннер. Как это сделать, будет показано позже, при настройке GitLab.

## Создание и настройка функции в Cloud Functions

### Создание функции

Переходим в раздел Cloud Functions / Функции и нажимаем **«Создать функцию»**.

![](/files/qmo1BGdiQuZ01Un4GRtV)

Присваиваем имя функции и нажимаем **«Создать»**:

![](/files/dWom0TeY8Otajd6o2ft4)

Выбираем среду выполнения. В этом примере используется Node.js. Затем снимаем галочку с **«Добавить файлы с примерами кода»** и нажимаем **«Продолжить»**.

![](/files/wuODnoY97I49AAdzWJuK)

### Настройка функции

Нажимаем **«Создать файл»**, присваиваем файлу имя, например, **index.js** и вставляем [код функции](https://gitlab.com/ruitunion/gitlab-runners-in-yandex-cloud/-/blob/main/yandex-cloud/index.js). Затем определяем точку входа. Формат должен быть такой:

<имя файла без расширения>.<имя функции>

Аналогичным образом создаём [package.json](https://gitlab.com/ruitunion/gitlab-runners-in-yandex-cloud/-/blob/main/yandex-cloud/package.json). Этот файл необходим, чтобы указать зависимость на Node.js SDK от Yandex.

Результат выглядит примерно так:

![](/files/GwlUYPbWCyEeJmkjtu55)

В параметрах функции указываем сервисный аккаунт с ролью compute.operator, который был выбран при создании ВМ. Через этот аккаунт функция будет запускать и останавливать ВМ. Остальные значения оставляем по умолчанию:

![](/files/v6PnXnZyPYtHbuUDGh56)

Осталось нажать **«Создать версию»**, дождаться обновления функции и сделать её публичной:

![](/files/1X8NNxBi4TFKhoY5Yke4)

Прежде чем идти дальше, разберём, что происходит в index.js.

Функция **handler**:

1. Сравнивает значение заголовка X-Gitlab-Token со значением в константе gitlabToken для того, чтобы функция обрабатывала запросы только от нашего репозитория. Значение токена можно сгенерировать любым удобным способом: GUID-генератор, генератор паролей и т.д.
2. Парсит тело запроса и проверяет значение object\_kind. Обрабатываться должны только события от pipeline. Остальные игнорируются.
3. Проверяет значение detailed\_status. Если в проекте создан новый pipeline, то статус у него будет pending. В таком случае запускаем ВМ. Если статус passed, значит, работа pipeline завершена успешно, можно останавливать ВМ.

Функции **startInstance** и **stopInstance**:

1. Создают новую сессию с токеном сервисного аккаунта, который мы указали при создании функции. Данные этого аккаунта будут доступны в параметре **context**.
2. Создают запрос на запуск и остановку ВМ соответственно.
3. Отправляют запрос в инстанс, который указан в константе **virtualMachineInstanceId**.

## Настройка проекта GitLab

### Регистрация и настройка раннера

Возвращаемся к ВМ. Для регистрации необходимо выполнить одну из команд из этой [инструкции](https://docs.gitlab.com/runner/register/index.html#docker). Для нашего примера:

```
docker run --rm -it -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register
```

После чего будет предложено определить значения для параметров конфигурации.

![](/files/9K5LUESIRudeNlZkirhx)

URL и токен находим на странице Settings / CI/CD:

![](/files/3IDTNwVHLtYbMppKR4UP)

Указываем при регистрации теги, которые описаны в файле .gitlab-ci.yml, иначе раннер не будет брать джобы.

![](/files/YYNwDHOpwMyEWVwGFmm2)

Если теги не используются, то после завершения регистрации указываем раннеру брать джобы без тегов:

![](/files/SmiEGrjPWO2fcoZHzc5w)

В результате в проекте появится доступный раннер.

![](/files/2tlLhCio4YGiMq59diBY)

Поскольку в этом примере будет собираться Docker-образ, включаем privileged mode в настройках раннера. Для этого флагу privileged присваивается значение true в файле /srv/gitlab-runner/config/config.toml

![](/files/Hr4BXT9OeYn5a9HsGdfs)

### Создание webhook

Переходим в раздел Settings / Webhook. Тут вводим URL функции, затем токен, который указали в константе gitlabToken, после чего выбираем триггер **pipeline** и нажимаем **Add webhook**:

![](/files/whDFLpqhbPw45fV4e44c)

## Проверяем работу CI/CD

Сперва остановим ВМ. После этого создадим новую ветку в репозитории, изменим какой-нибудь файл и сделаем merge request.

Все три стейджа отработали без ошибок:

![](/files/b84gNnK56lphSvOq0spe)

В реестре контейнеров создан Docker-образ:

![](/files/8x4iPrvuvPtIzrhJ2max)

В логах функции видно, что с момента запуска ВМ до завершения работы CI/CD прошло примерно 5 минут 20 секунд.

![](/files/Ik3jYq8sm5jRpQ1xaRAx)

## Анализ решения

Ниже приведена стоимость использования одной виртуальной машины с GitLab Runner в Compute Cloud за неделю. Если экстраполировать такое потребление на месяц, то выйдет примерно 200-250 рублей, что дешевле использования полноценной ВМ.

![](/files/9GBZPlz2vnqOqChA3PQ2)

Основной ресурс, на который уходит бюджет — хранилище. Если сумма в 200-250 рублей — всё ещё много, то нужно сменить тип хранилища с SSD на HDD.Также в качестве платформы можно выбрать Intel Cascade Lake, так как она позволяет снизить гарантированную долю vCPU до 5%. Стоимость такой ВМ будет на 30-40% ниже, но и производительность её также будет ниже.

**Плюсы такого решения:**

1. Относительно простая конфигурация, которая легко настраивается.
2. Невысокая стоимость ресурсов облака, подходит для небольших pet-проектов.

**Минусы:**

1. Если на одной ВМ развёрнуты раннеры от нескольких проектов, то нужно усложнять логику включения / отключения ВМ, так как ВМ может внезапно отключиться при завершении работы одного из раннеров.
