> 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/>

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-beec8a96a8589679077174c8556be692cad7c157%2F06645b4aa11a0ee0b337785705dd5d7f.jpeg?alt=media)

У нас в профсоюзе недавно появился сервис, который используется для создания публикаций в социальных сетях. Проект находится в 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 может занимать всего несколько минут. Поэтому после недолгих раздумий был придуман финт ~~ушами~~ функциями.

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-a29381c54cc942e5d2b230893dfd23831067a44c%2F840f7071412ea4bd9ee553596695343f.png?alt=media)

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

Необходим [аккаунт в 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-образ и опубликовать его в реестре проекта.

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-608454b58c80b0b623d9aa067ea6a75aef1eff32%2F611d9e857fc15a5f031aa65e69d764f0.png?alt=media)

Заострять внимание на самом проекте нет смысла, так как приложение роли не играет. Если у вас другой стек, то изменения будут в 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 / Виртуальные машины и нажимаем **«Создать ВМ»**.

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-757db6c2e47dfc31453dc01852c65e245ff038d7%2Fefb7cedb49e14634cfdbab8837e139b2.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-a9a46463a56f9b37eec111f98f2836c5a68ab0be%2F6925c73636817aa6d0536e3e8a09279a.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-cdee9809a0e55eadad7b316983754c5cd3f0806e%2Fa40d1b0a123bba4455f05075c6d63785.png?alt=media)

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

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-26f367158b3cec4d5b8cf34cbce8aebb95d3363e%2F5d40a4cd6069b92bd0341d3b0ac73b05.png?alt=media)

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

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

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-8afb492b9202d7f010edab9408115650c6157d61%2Feb7ab62671c428dfda188b07eba14773.png?alt=media)

Есть несколько способов [установить 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 / Функции и нажимаем **«Создать функцию»**.

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-37480e0e12a20046081b4e8c8f3be2b60b65adb1%2F46e2edfa1bf9c83e0b9236cec702edc1.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-4389e81a634686956f2792dcaa5e3002bea1a7f3%2Fb1e532b7a7169b81d6219930c15ec764.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-9b81c3e262297a61a50add83c933d5aab0665cb0%2F115a29e3bd460e65b98d15b819b20add.png?alt=media)

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

Нажимаем **«Создать файл»**, присваиваем файлу имя, например, **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.

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-ca91d9a9a21f75b2f8459b7820e46f7e6a8cb870%2F4b57857962cc7772b4a6e45f3a2afa12.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-bf46a9b5e018954d3f9ab562706b4f3d2c9772c0%2F55287125432273e7733c73747e3058ad.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-c5f580c353e6d782c871f309fd8c3d7bba7386a7%2Feb1cf4d34c2b6bfe40df1a08e95d379a.png?alt=media)

Прежде чем идти дальше, разберём, что происходит в 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
```

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-f818037b8025d09c5eeac3795f950b78efd46c73%2F48534f991a42eef64b64500b35942bdd.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-5dae24e18309856b99794828b69086c40b5bb390%2Fa71a4bcdadcf7b61b4dacc0b2f24a460.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-e05e2e09adddb35b60a5c79071b972f343670d68%2Ff1e14db140134847e7d2e13aceddf2e1.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-9823320534a91e7c23aeb481c30d209407c3c825%2F0bcf865034abdf96e80da59053b284b3.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-23ac5c53ae87637cf115540ac9a642839263a7ee%2F0e298de681537e3e66f947404cb77e42.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-a7165412b5fd6849e87b85ac0a64dbd90df088df%2F44bb67ceed770ddf643749352e4ce060.png?alt=media)

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

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-86f85257e53c1942af6c765637207e6139ce0a23%2F17116e20e3234f2e525d5408dbb9d7af.png?alt=media)

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

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

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-5f2f29a9de9bcb06e788cf250c7afd400053bb21%2F74be5cc1edd24e6a174240a450b40340.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-ab8f36fd4db30394b9f13db99419b6a975d61239%2Fe2bbe87dcb8bf8c0d4f6fdd813f3187e.png?alt=media)

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-ed13930b49818e98c120ccd5df928b137d26134e%2Fe6f38f8a1a5a78cd73ed445d975802a8.png?alt=media)

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

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

![](https://296194292-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLoAqAoOfr7XVUQw7Gff8%2Fuploads%2Fgit-blob-4019c4609795e847db7d65d71f7569a28e97af44%2F62f27a16fbfced39a40bfcdd3a21ee21.png?alt=media)

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

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

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

**Минусы:**

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