Terraform

Разворачивать облачную инфраструктуру в Selectel и управлять ей можно с помощью утилиты Terraform от HashiCorp.

Через Terraform можно работать с продуктами:

Инфраструктура и ее компоненты описываются на языке HashiCorp Configuration Language (HCL) в конфигурационных файлах с расширением .tf — манифестах.

Для работы с услугами Selectel используется два Terraform-провайдера:

  • OpenStack-провайдер для управления ресурсами OpenStack, например облачными серверами, дисками, сетями;
  • Selectel-провайдер, который взаимодействует с API Selectel, для управления проектами и квотами, пользователями, их ролями и токенами, DNS, кластерами и группами нод Managed Kubernetes, облачными базами данных.

Чтобы развернуть инфраструктуру через Terraform:

  1. Установите Terraform.
  2. Создайте манифест.
  3. Инициализируйте Terraform-провайдеры OpenStack и Selectel.
  4. Опционально: настройте хранение Terraform State в объектном хранилище.
  5. Составьте план инфраструктуры.
  6. Проверьте конфигурацию и разверните инфраструктуру.

Установить Terraform

Перед началом работы установите Terraform на облачном сервере или локальном компьютере.

Используйте инструкцию на официальном сайте Terraform в зависимости от операционной системы.

Создать манифест

План инфраструктуры описывается в манифестах — файлах с расширением .tf.

При выполнении команды terraform apply, которая создает инфраструктуру, Terraform загружает все манифесты, лежащие в одной директории — создаются все описанные ресурсы (resources). Файлы с описанием одной инфраструктуры должны находиться в отдельной директории.

Создайте директорию и файл внутри нее, например main.tf. Файлы с описанием плана могут иметь любое название.

Настроить провайдеры

В манифесте нужно перечислить Terraform-провайдеры, необходимые для создания инфраструктуры. Обычно для работы используются два провайдера: Selectel и OpenStack. В некоторых случаях требуется только OpenStack, например, если проект облачной платформы уже создан.

Добавьте в файл блок с описанием провайдеров:

terraform {
required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 1.49.0"
    }
    selectel = {
      source  = "selectel/selectel"
      version = "~> 3.9.0"
    }
  }
}

Актуальные версии провайдеров (version) можно найти в их официальной документации (Selectel и OpenStack), нажав на кнопку USE PROVIDER.

Для авторизации OpenStack-провайдера добавьте в манифест:

provider "openstack" {
  auth_url    = "https://api.selvpc.ru/identity/v3"
  domain_name = "<selectel_account>"
  tenant_id   = "<project_id>"
  user_name   = "<user_name>"
  password    = "<user_password>"
  region      = "<pool>"
}

Укажите:

Для авторизации Selectel-провайдера:

provider "selectel" {
  token = "<selectel_token>"
}

Укажите <selectel_token> — токен аккаунта (ключ Selectel API), его можно получить по инструкции Ключи API.

Настроить хранение Terraform State

Terraform State (состояние Terraform) — это файл с расширением .tfstate, который хранит описание развернутой инфраструктуры. Файл создается вместе с инфраструктурой и обновляется при ее изменении.

Terraform State можно хранить в объектном хранилище Selectel.

  1. Создайте контейнер в объектном хранилище.

  2. Добавьте блок backend в манифест:

    terraform {
    required_version = ">= 0.14.0"
      required_providers {
        openstack = {
          source  = "terraform-provider-openstack/openstack"
          version = "~> 1.49.0"
        }
       selectel = {
         source  = "selectel/selectel"
         version = "~> 3.9.0"
       }
      }
    
      backend "s3" { 
        bucket                      = "/<container_name>"
        endpoint                    = "s3.storage.selcloud.ru"
        key                         = "<file_name>.tfstate"
        region                      = "ru-1"
        skip_region_validation      = true
        skip_credentials_validation = true
        access_key                  = "<access_key>"
        secret_key                  = "<secret_key>"
      }
    }
    

    Укажите:

    • <container_name> — имя контейнера в объектном хранилище, в котором будет храниться файл с состоянием Terraform. Имя можно посмотреть в панели управления в разделе Объектное хранилище ⟶ Хранилище ⟶ вкладка Контейнеры;
    • <file_name> — имя файла с состоянием Terraform;
    • <access_key> — логин пользователя объектного хранилища в формате НомерАккаунта_ИмяПользователя. Логин можно посмотреть в панели управления в разделе Объектное хранилище ⟶ Пользователи. Убедитесь, что у пользователя включен доступ по протоколу S3;
    • <secret_key> — пароль пользователя объектного хранилища. Пароль не хранится в панели управления – если вы его потеряли, установите новый пароль.

Составить план инфраструктуры

Составьте план инфраструктуры в файле с расширением .tf. Вы можете:

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

Пример плана инфраструктуры

Применение этого плана создаст инфраструктуру в пуле ru-3, которая будет содержать:

  • облачный сервер с загрузочным сетевым диском из образа Ubuntu 20.04 LTS 64-bit, с произвольной конфигурацией с 1 vCPU и 1 ГБ RAM. Все доступные типы конфигураций — в документации;
  • приватную сеть с подсетью;
  • облачный роутер, подключенный к внешней сети;
  • публичный IP-адрес, привязанный к облачному серверу.

В примере используется проект Облачной платформы My First Project, который создается автоматически при регистрации аккаунта, также проект можно создать через Terraform.

План описан в двух файлах — main.tf и vars.tf. В первом хранится описание создаваемых ресурсов, во втором — объявлены переменные, которые могут переиспользоваться в main.tf.

Файл vars.tf

# Пул Облачной платформы
variable "region" {
  default = "ru-3"
}

# Значение SSH-ключа для доступа к облачному серверу
variable "public_key" {
  default = "key_value"
}

# Сегмент пула
variable "az_zone" {
  default = "ru-3b"
}

# Тип сетевого диска, из которого создается сервер
variable "volume_type" {
  default = "fast.ru-3b"
}

# CIDR подсети
variable "subnet_cidr" {
  default = "10.10.0.0/24"
}

Здесь:

  • ru-3пул облачной платформы, в котором будет развернута инфраструктура;
  • key_value — значение SSH-ключа. Его можно создать в панели управления или с помощью OpenStack CLI командами ssh-keygen -t rsa и openstack keypair create --public-key ~/.ssh/id_rsa.pub <ssh_name>
  • ru-3b — сегмент пула;
  • fast.ru-3b — тип сетевого диска, из которого создается сервер. Доступные для создания типы можно посмотреть с помощью команды openstack volume type list
  • 10.10.0.0/24 — CIDR подсети.

Файл main.tf

# Инициализация Terraform и хранения Terraform State
terraform {
  required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 1.49.0"
    }
    selectel = {
      source  = "selectel/selectel"
      version = "~> 3.9.0"
    }
  }

  backend "s3" { 
    bucket                      = "/container"
    endpoint                    = "s3.storage.selcloud.ru"
    key                         = "terraform.tfstate"
    region                      = "ru-1"
    skip_region_validation      = true
    skip_credentials_validation = true
    access_key                  = "access_key"
    secret_key                  = "secret_key"
  }
}

# Инициализация провайдера OpenStack
provider "openstack" {
  auth_url    = "https://api.selvpc.ru/identity/v3"
  domain_name = "selectel_account"
  tenant_id   = "project_id"
  user_name   = "user_name"
  password    = "user_password"
  region      = var.region
}

# Инициализация провайдера Selectel
provider "selectel" {
  token = "selectel_token"
}

# Создание SSH-ключа
resource "openstack_compute_keypair_v2" "key_tf" {
  name       = "key_tf"
  region     = var.region
  public_key = var.public_key
}

# Запрос ID внешней сети по имени
data "openstack_networking_network_v2" "external_net" {
  name = "external-network"
}

# Создание роутера
resource "openstack_networking_router_v2" "router_tf" {
  name                = "router_tf"
  external_network_id = data.openstack_networking_network_v2.external_net.id
}

# Создание сети
resource "openstack_networking_network_v2" "network_tf" {
  name = "network_tf"
}

# Создание подсети 
resource "openstack_networking_subnet_v2" "subnet_tf" {
  network_id = openstack_networking_network_v2.network_tf.id
  name       = "subnet_tf"
  cidr       = var.subnet_cidr
}

# Подключение роутера к подсети
resource "openstack_networking_router_interface_v2" "router_interface_tf" {
  router_id = openstack_networking_router_v2.router_tf.id
  subnet_id = openstack_networking_subnet_v2.subnet_tf.id
}

# Поиск ID образа (из которого будет создан сервер) по его имени
data "openstack_images_image_v2" "ubuntu_image" {
  most_recent = true
  visibility  = "public"
  name        = "Ubuntu 20.04 LTS 64-bit"
}

# Создание уникального имени флейвора
resource "random_string" "random_name_server" {
  length  = 16
  special = false
}

# Создание конфигурации сервера с 1 ГБ RAM и 1 vCPU
# Параметр disk = 0  делает сетевой диск загрузочным
resource "openstack_compute_flavor_v2" "flavor_server" {
  name      = "server-${random_string.random_name_server.result}"
  ram       = "1024"
  vcpus     = "1"
  disk      = "0"
  is_public = "false"
}

# Создание сетевого загрузочного диска размером 5 ГБ из образа
resource "openstack_blockstorage_volume_v3" "volume_server" {
  name                 = "volume-for-server1"
  size                 = "5"
  image_id             = data.openstack_images_image_v2.ubuntu_image.id
  volume_type          = var.volume_type
  availability_zone    = var.az_zone
  enable_online_resize = true
  lifecycle {
    ignore_changes = [image_id]
  }
}

# Создание сервера
resource "openstack_compute_instance_v2" "server_tf" {
  name              = "server_tf"
  flavor_id         = openstack_compute_flavor_v2.flavor_server.id
  key_pair          = openstack_compute_keypair_v2.key_tf.id
  availability_zone = var.az_zone
  network {
    uuid = openstack_networking_network_v2.network_tf.id
  }
  block_device {
    uuid             = openstack_blockstorage_volume_v3.volume_server.id
    source_type      = "volume"
    destination_type = "volume"
    boot_index       = 0
  }
  vendor_options {
    ignore_resize_confirmation = true
  }
  lifecycle {
    ignore_changes = [image_id]
  }
}

# Создание публичного IP-адреса
resource "openstack_networking_floatingip_v2" "fip_tf" {
  pool = "external-network"
}

# Привязка публичного IP-адреса к серверу
resource "openstack_compute_floatingip_associate_v2" "fip_tf" {
  floating_ip = openstack_networking_floatingip_v2.fip_tf.address
  instance_id = openstack_compute_instance_v2.server_tf.id
}

Создать инфраструктуру

Выполните следующие команды в директории, в которой находятся созданные манифесты.

  1. Инициализируйте Terraform-окружение:

    terraform init
    
  2. Проверьте, что план составлен без ошибок:

    terraform plan
    

    Если ошибок в описании нет, будет выведен список ресурсов, готовых к созданию. Если ошибки есть — их нужно устранить.

  3. Разверните инфраструктуру и создайте ресурсы:

    terraform apply
    
  4. Подтвердите создание — введите yes и нажмите Enter. Созданные ресурсы автоматически отобразятся в панели управления.

Редактировать ресурсы

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

Если вы внесли изменения в инфраструктуру через панель управления, в манифестах они не отобразятся.

Для изменения инфраструктуры отредактируйте манифест и затем примените изменения:

terraform apply

Ограничения произвольных конфигураций

Если вы измените значение vCPU, RAM или локального диска в описании ресурса произвольной конфигурации (флейвора) облачного сервера на недопустимое, то возникнет ошибка — Terraform удалит флейвор и не сможет создать новый.

Чтобы сначала создавался новый флейвор, а затем удалялся старый, добавьте в описание флейвора (пример):

lifecycle {
    create_before_destroy = true
  }

Удалить ресурсы

Если вы удалили ресурсы через панель управления, это не отобразится в манифестах.

  1. Чтобы удалить ресурсы, в директории с манифестами выполните:

    terraform destroy
    
  2. Будет выведен список удаляемых ресурсов. Подтвердите удаление — введите yes и нажмите Enter.