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

d240416ce8b878202d5835d458e83c9e

В этом посте:


  • Использование 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 модули:

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


  • github.com/patsevanton/terraform-yandex-dns.git
  • github.com/patsevanton/terraform-yandex-vpc-address.git


Организуем структуру каталогов с 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 согласно инструкции https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html

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

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

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

Так же создайте новую переменную окружения YC_TOKEN и в качестве ее значения укажите содержимое OAuth-токена согласно инструкции https://cloud.yandex.ru/docs/iam/concepts/authorization/oauth-token

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

Бекап terraform state из gitlab

curl --header "Content-Type: application/vnd.api+json" --header "Authorization: Bearer glpat-xxxx" \
https://gitlab.com/api/v4/projects/43542597/terraform/state/dev-group1-dns.tfstate

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


Планы


  • Рассмотреть альтернативу terragrunt — Terramate
  • Рассмотреть использование Runatlantis

© Habrahabr.ru