Управление Gitlab репозиториями с помощью Terraform
Рассмотрим управление Gitlab репозиториями через Terraform и какие это дает приемущества
Зачастую мы слышим о terraform в контексте управления облачной инфраструктурой. История классическая. Сначала кажется, что проще в UI накликать инфраструктуру, никакой код не нужен. Но выясняется, что по мере разрастания проекта ситуация меняется. Например, есть необходимость поднять дополнительные 20 виртуальных машин с определенной конфигурацией. В ui облака практически неизбежно придется прокликивать создание каждой, а через код достаточно написать 5-10 строчек. Все это хорошо известно, но зачем применять iac подход к репозиториям? Кажется, что git-репозитории - это совсем не инфраструктура.
Зачем управлять репозиториями через terraform?
1. Упрощенное дублирование
Представим ситуацию, команда разработка приступает к созданию нового микросервиса. Ей необходим репозиторий с такими же настройками, как в остальных их проектах. С iac подходом не придется ходить в старые репозитории и смотреть как там было настроено. Достаточно будет дописать пару строчек кода и применить их. Отмечу, что, например, в Gitlab есть возможность наследовать настройки от родительской группы. Но далеко не всегда репозитории создаются в одних группах из-за особенностей корпоративных процессов. Кроме того, не все настройки можно унаследовать.
2. Единый подход к управлению
Хотя и формально репозиторий - это не инфраструктура, было бы приятно иметь единый интерфейс для описания всех конфигураций. Возьмем упрощенный пример. Нужно развернуть вм c gitlab
graph TD
VPC[VPC] --> VM[Виртуальная машина c GitLab]
SG[Security groups] --> VM
VM --> P1[Проект 1]
VM --> P2[Проект 2]
VM --> P3[Проект 3]
VM --> Pn[...]
Через Terraform можно описать сеть и security группы. Через него же можно развернуть вм, описав в cloud-init установку Gitlab. И вот когда уже все подготовлено, можно через все тот же Terraform описать репозитории (кстати и не только их). На большом количестве различных конфигураций иметь единый интерфейс для их описания невероятно удобно.
Управляем репозиториями в коде на примере Gitlab
Пререквизиты
Давайте посмотрим на практике, как выглядит создание репозиториев в gitlab в коде. Для того, чтобы воспроизвести пример у себя, понадобится:
- Аккаунт в Gitlab с access токеном.
- Установленный Opentofu (форк Terraform). Используем форк, т.к. в его лицензии нет существенных ограничений.
Запуск уже готового манифеста
Если не хочется писать манифест самому, то можно просто скачать готовый и применить его
- Сохраните себе репозиторий с terraform модулями
- Перейдите в modules/gitlab-project/examples/multiple-projects
- Вставьте ваш gitlab access token на 11-ой строчке
1
token = "<YOUR_GITLAB_TOKEN>"
- Выполните
1 2
tofu init tofu apply -auto-approve
Создание манифеста с нуля
Весь код будем делать в файлике main.tf. Создайте его в пустой директории. Для начала добавим информацию о провайдере, с помощью которого будем вносить изменения. Не забудьте добавить ваш gitlab access token в 11-ую строчку.
1
2
3
4
5
6
7
8
9
10
11
12
13
terraform {
required_providers {
gitlab = {
source = "gitlabhq/gitlab"
version = "18.4.1"
}
}
}
provider "gitlab" {
token = "<YOUR_GITLAB_TOKEN>" # Подставьте сюда ваш gitlab access token
base_url = "https://gitlab.com/api/v4/"
}
Создадим репозитории. Для упрощения будет пример, когда настройки полностью совпадают за исключением имен проектов. В реальных задачах конечно же так просто не будет. Здесь надо понимать, что есть 2 пути.
- Конфигурация хранится в большом словаре и репозитории описываются в цикле по верхнеуровневым ключам этого словаря
- Описание по-просту дублируются, общая конфигурация выносится в переменные.
Пока что рассмотрим простой пример
1
2
3
4
5
6
7
8
9
10
module "riftonix_project_test" {
source = "git::https://github.com/riftonix/terraform-shared.git//modules/gitlab-project?ref=gitlab-project/1.0.1"
for_each = toset(["ms-1", "ms-2", "ms-3", "ms-4"])
project_name = each.value # Имя проекта
group_id = 0 # Проекты лежат в корневой группе, которая есть по умолчанию
only_allow_merge_if_pipeline_succeeds = true # Мерж в protected ветки разрешаем, если пайплайн успешен
protected_branches = ["main", "master", "release/*"] # Описываем, какие ветки protected
}
Здесь важно понимать, что как правило управлением репозиториями под новые микросервисы занимается сама разработка. И вполне возможна коллизия, когда мы пытаемся управлять gitlab проектом через terraform, а разработчик пытается внести изменения вручную.
Полностью забрать контроль за репозиторием неочень хорошая идея, получится, что все изменения завязаны на управляющую команду. Можно конечно дать доступ разработчикам вносить изменения в код конфигурации, но на практике разратчик вряд ли будет работать по такому флоу.
Корректнее будет сделать кастомные gitlab-роли. За часть настроек отвечают разработчики, которым выдается новая роль, а за часть devops-команда. В публичной версии Gitlab этот функционал к сожалению не доступен, не добавляйте код ниже в main.tf
1
2
3
4
5
6
7
8
9
resource "gitlab_member_role" "custom_maintainer" {
name = "Custom maintainer"
description = "This role gives the developers additonal access to manage CI/CD variables"
base_access_level = "DEVELOPER"
enabled_permissions = [
"ADMIN_CICD_VARIABLES",
"ARCHIVE_PROJECT"
]
}
В этом примере командам разработки передается управление переменными окружения и возможность делать проект архивным. Остальными настройками управляет devops-команда. Конкретный набор прав для команд зависит от сложившихся процессов внутри компании, здесь сложно сделать универсально. Документацию по gitlab_member_role можно посмотреть здесь.
Вернемся к нашему main.tf. Пришло время его инициализировать и применить настройки.
1
2
tofu init
tofu apply -auto-approve
На выходе получаем 4 одинаково настроенных gitlab-проекта.
Выводы
Terraform (и его форк OpenTofu) можно использовать не только для управления инфраструктурой, а более глобально, управляя всеми сущностями, у которых есть web api.
Здесь мы рассмотрели Gitlab проекты. При применении манифеста main.tf можно было заметить, что создалось 20 сущностей, хотя мы сделали всего лишь 4 репозитория. С помощью кастомных ролей (в Enterprise-версии GitLab) можно разграничить, какие настройки контролирует DevOps-команда, а какие — разработчики, сохраняя при этом централизованное управление через единый Terraform/Opentofu интерфейс.
Такой подход описания конфигураций в коде возможно распространить и на другие компоненты. Это и управление grafana дашбордами, и различные git хостинги, и произвольные k8s манифесты (примеры реализации можно посмотреть здесь). Ведь на самом деле devops практики — это не столько про инструменты, сколько про культуру воспроизводимости и автоматизации. И Terraform/OpenTofu — один из самых мощных способов воплотить эту культуру в жизнь, начиная от виртуальной машины и заканчивая последним репозиторием в вашей организации.
