Управление инфраструктурой с помощью terragrunt (terraform) и gitlab ci

Kate

Administrator
Команда форума
В этом посте:


  • Использование terraform модулей
  • Организуем структуру каталогов с terraform модулями для terragrunt согласно вашей инфраструктуре
  • Создание/Обновление/Удаление инфраструктуры одной terragrunt командой
  • Настройка в gitlab ci для запуска и сохранения terraform lock и state в gitlab
  • Бекап terraform state из gitlab

Terraform — это инструмент для управления инфраструктурой в облаке с использованием описания в виде кода.


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


Terragrunt — это обертка для Terraform, позволяющая решать проблемы, связанные с масштабированием и переиспользованием кода для настройки инфраструктуры.


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


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


Использование terraform модулей​


Terraform модули — это предварительно настроенные компоненты Terraform, которые можно использовать для создания и управления различными инфраструктурными компонентами.​


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


Посты про terraform модули:



Будут использоваться модули:



Организуем структуру каталогов с terraform модулями для terragrunt согласно вашей инфраструктуре​


Можно использовать terraform модули с чистым terraform, но c terragrunt это будет удобнее:


  • Код будет компактнее, а значит читабельнее
  • Структура каталогов отражает то, как организована ваша инфраструктура.
  • Можно создать/обновить/удалить инфраструктуру одной командой
  • Можно периодически запускать plan и проверять изменилось что-нибудь

Посты про terragrunt:



Будет рассматриваться репозиторий https://gitlab.com/anton_patsev/gitlab_ci_terragrunt
Структура каталогов этого репозитория минимальная в целях объяснения принципов работы terragrunt:


.
├── dev
│ ├── env.hcl
│ └── group1
│ ├── dns
│ │ └── terragrunt.hcl
│ ├── group.hcl
│ └── vpc-address
│ └── terragrunt.hcl
├── README.md
└── terragrunt.hcl

Обычно инфраструктуру разделяют на какие-нибудь группы:


  • dev/uat/prod
  • vpc1/vpc2
  • другие варианты

Пример структуры каталогов от самого terragrunt — https://github.com/gruntwork-io/terragrunt-infrastructure-live-example


Рассмотрим HCL конфиги​


Рассмотрим корневой terragrunt.hcl.
Корневой terragrunt.hcl нужен для задания общих переменных, параметров.


# корневой terragrunt.hcl

locals { # переменные общие для всего проекта
env_vars = read_terragrunt_config(find_in_parent_folders("env.hcl")) # Функция read_terragrunt_config() используется для чтения конфига env.hcl (group.hcl),
group_vars = read_terragrunt_config(find_in_parent_folders("group.hcl")) # найденного с помощью функции find_in_parent_folders() в этой директории или вышележащих директориях до корневой директории.
project_id = "43542597" # project_id в gitlab
env = "dev" # Переменная, которая описывает директорию dev как dev окружение в этом проекте.
username = "anton_patsev" # ваш login в gitlab
string_path_relative_to_include = join(".", [replace("${path_relative_to_include()}", "/", "-"), "tfstate"]) # получение из пути dev/group1/dns получить имя tfstate: dev-group1-dns.tfstate
}

inputs = merge({
# merge в terragrunt используется для объединения входных параметров из нескольких источников.
# Это позволяет использовать общие параметры для нескольких конфигураций Terraform,
# а также позволяет переопределять параметры для конкретной конфигурации.
cloud_id = local.env_vars.locals.cloud_id
folder_id = local.env_vars.locals.folder_id
network_id = local.group_vars.locals.network_id
})

remote_state {
# В backend.tf определяется где сохраняется terraform state. В данном случае сохраняется в http сервисе.
backend = "http"
# Параметры для сохранения terraform state
config = {
address = "https://gitlab.com/api/v4/projects/${local.project_id}/terraform/state/${local.string_path_relative_to_include}"
lock_address = "https://gitlab.com/api/v4/projects/${local.project_id}/terraform/state/${local.string_path_relative_to_include}/lock"
unlock_address = "https://gitlab.com/api/v4/projects/${local.project_id}/terraform/state/${local.string_path_relative_to_include}/lock"
username = local.username # Login доступа к http сервису (в данном случае gitlab)
# Пароль доступа берется из переменной окружения
lock_method = "POST"
unlock_method = "DELETE"
retry_wait_min = 5
}
generate = {
path = "backend.tf"
# Создается файл backend.tf в каждом скачанном terraform модуле
if_exists = "overwrite_terragrunt"
}
}

Рассмотрим env.hcl.
В директории dev в конфиге env.hcl задаются параметры для dev окружения, например id folder или другие.


locals {
cloud_id = "b1gvct0b630bbm7i7v90" # cloud-patsevanton
folder_id = "b1g972v94kscfi3qmfmh" # default
}

Рассмотрим group.hcl.
В директории group1 в конфиге group.hcl задаются параметры для обособленной группы (group1), например network_id или другие.


locals {
network_id = "enprkje8ae9b74e0himb" # default
}

Рассмотрим terragrunt.hcl для вызова определенного terraform модуля. В качестве примера возьмем terragrunt.hcl из директории dns.
В директории group1 присутствуют 2 директории: dns и vpc-address. В каждой директории присутствует terragrunt.hcl.


terraform {
# Ссылка на terraform модуль и его тег или ветку
source = "github.com/patsevanton/terraform-yandex-dns.git//.?ref=main"
}

include {
# Этот блок кода используется для поиска и загрузки конфигурационных параметров из родительских папок.
# Это позволяет использовать один и тот же код для конфигурации нескольких подсистем.
path = find_in_parent_folders()
}

# Указывается зависимость текущего кода от vpc-address
dependency "vpc-address" {
config_path = "../vpc-address" # Указываем где искать vpc-address
# Mock_outputs_allowed_terraform_commands используется для того,
# чтобы позволить Terragrunt выполнять имитацию команд Terraform для проверки ваших конфигураций без изменения любого реального состояния.
# Это позволяет проверять и отлаживать ваши конфигурации до того, как вы будете применять их на самом деле.
mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"]
# При выполнении terragrunt init/validate/plan в переменную external_ipv4_address будет подставлено фейковое значение
mock_outputs = {
external_ipv4_address = "fake_external_ipv4_address"
}
}

# Параметры, которые могут быть переданы в terraform модуль.
inputs = {
description = "grafana"
zone = "apatsev.org.ru."
name = "apatsev-org-ru"
public = true
recordset = [
{
name = "grafana1.apatsev.org.ru."
type = "A"
ttl = 600
data = [dependency.vpc-address.outputs.external_ipv4_address]
},
]
}

Запуск terragrunt в каждой директории


cd dev/group1/dns
terragrunt apply
cd ..
cd vpc-address
terragrunt apply

Создание/Обновление/Удаление инфраструктуры одной terragrunt командой​


Можно создать/удалить инфраструктуру одной командой terragrunt run-all:


cd dev
terragrunt run-all apply -auto-approve --terragrunt-non-interactive

Если вы хотите отладить и создать инфраструктуру вручную, необходимо закомментировать remote_state в корневом terragrunt.hcl


Настройка в gitlab ci для запуска и сохранения terraform lock и state в gitlab​


Создайте Project access token с именем GITLAB_ACCESS_TOKEN согласно инструкции: Project access tokens


Чтобы передать Personal Access Token в переменную окружения GitLab откройте ваш проект, затем откройте Settings —> CI/CD и разверните Variables.


Создайте новую переменную окружения GITLAB_ACCESS_TOKEN и в качестве ее значения укажите содержимое Personal Access Token.


Для безопасности отметьте созданную переменную как protected.


Так же создайте новую переменную окружения YC_TOKEN и в качестве ее значения укажите содержимое OAuth-токена согласно инструкции: OAuth-токен


Для безопасности лучше использовать IAM-токен сервисного аккаунта.



Бекап terraform state из gitlab​


curl --header "Content-Type: application/vnd.api+json" --header "Authorization: Bearer glpat-xxxx" \

Где 43542597 — id проекта, dev-group1-dns.tfstate — название terraform state

 
Сверху