Cоздание и настройка глобального роутера через Terraform

Как автоматизировать создание и настройку глобального роутера в облаке через Terraform Provider

Как с помощью Terraform Provider автоматизировать настройку глобального роутера.

Итак, у вас есть две виртуальные машины в разных регионах, на которых крутится дев, тест, прод (нужное подчеркнуть). И вам нужно соединить их приватной сетью. В целом это можно сделать и ручками. Но когда инфраструктура разрастется, вы точно не захотите заниматься подобными вещами.

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

Исходные условия

Начнем с описания исходной инфраструктуры. Допустим, у нас есть две виртуальных машины в Москве и Санкт-Петербурге.

Санкт-Петербург, зона ru-1:

  • облачная сеть с подсетью 192.168.0.0/28,
  • ВМ в этой сети с IP 192.168.0.2,
  • облачный роутер, подключенный к сети, и плавающий IP: 95.213.230.121.
Скриншот из панели управления. Созданная виртуальная машина с IP 192.168.0.2.

Москва, зона ru-2:

  • облачная сеть с подсетью 172.16.0.0/28,
  • ВМ в этой сети с IP 172.16.0.2,
  • облачный роутер, подключенный к сети, и плавающий IP: 176.114.69.92.
Скриншот из панели управления. Созданная виртуальная машина с IP 172.16.0.2.

Плавающий, или Floating, IP на обеих ВМ нужны для удобства демонстрации сетевой связанности. В реальном примере они могут отсутствовать — доступ будет осуществляться через виртуальную консоль в панели управления.

Допустим, на ВМ1 в Санкт-Петербурге у меня запущен сервис с базой данных. Я решаю обеспечить катастрофоустойчивость и на ВМ2 в Москве поднимаю копию БД и настраиваю репликацию с ВМ1. Схематично это будет выглядеть так:

Схема с двумя ранее созданными ВМ.
Схема инфраструктуры с двумя облачными серверами в разных регионах. Плавающие IP-адреса здесь не показаны, но их можно добавить.

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

В описанном примере у обеих ВМ есть плавающие IP-адреса, но настраивать через них связь нельзя по ряду причин. Вот две наиболее популярные:

  • Трафик через плавающий IP часто проходит через NAT-шлюзы и внешние границы сети провайдера. Это увеличивает задержки (ping) по сравнению с прямой передачей пакетов внутри приватной сети.
  • Используя плавающий IP, вы выставляете сервисы виртуальных машин во внешнюю сеть. Даже если вы настроили файрвол, риск атаки все равно будет выше, чем при использовании изолированного внутреннего канала.

Отличная альтернатива — настройка сетевой связанности через Глобальный роутер Selectel. В этом случае ВМ2 будет доступна с ВМ1 по внутреннему IP-адресу в серой сети. Это приводит нас к тому, как провалидировать работоспособность созданной топологии:

Логинимся по SSH на ВМ2, ставим утилиту tcpdump и смотрим ICMP-пакеты.

Так выглядит установка утилиты в консоли.

Далее логинимся на ВМ1 и запускаем ping до ВМ2 по внутреннему адресу 172.16.0.2:

Так в консоли выглядит ping с одной ВМ до другой.

Глобальный роутер не настроен, поэтому связи между виртуальными машинами нет. Значит, нам нужно его добавить и настроить, чтобы в итоге получить вот такой вид:

Схема с двумя ранее созданными ВМ. Теперь в ней есть глобальный роутер.

Это можно сделать двумя способами:

  • через панель управлениями (без автоматизации),
  • автоматически через Terraform.

Способ 1. Настраиваем в панели управления

Не буду погружаться детально в этот подход, так как он довольно подробно описан в нашей документации. Достаточно напомнить, что потребуется:

  • создать ресурс Глобального роутера,
  • подключить к созданному роутеру сеть и подсеть в ru-1,
  • подключить к созданному роутеру сеть и подсеть в ru-2.

В панели управления результат будет выглядеть следующим образом:

В панели управления отображается сеть, которая связывает две виртуальные машины.

Проверим наш ping после настройки и увидим, что связанности все еще нет! Как так? Я же обещал, что будет все работать! А дело в том, что надо просто добавить статические маршруты:

  • На ВМ1: ip r add 172.16.0.0/28 via 192.168.0.1,
  • На ВМ2: ip r add 192.168.0.0/28 via  172.16.0.1.

Наконец, мы получаем работающий вариант:

Проверка ping в консоли после настройки.

Способ 2. Автоматическая настройка с помощью Terraform Provider

Теперь соберем аналогичную конструкцию с помощью Terraform-ресурсов. Как известно, хорошим тоном является организация шаблона по файлам:

  • versions.tf,
  • main.tf,
  • vars.tf,
  • outputs.tf.

Я предлагаю временно его нарушить для простоты демонстрации и описывать все в одном файле (main.tf). Это упростит определение параметров ресурсов. При росте размера шаблона или желании его параметризации рекомендую реорганизовать код и разделить на упомянутые файлы.

Инициализация провайдера

Ресурсы глобального роутера были добавлены недавно и доступны с версии 7.3.0 Terraform Provider. Указываем в шаблоне эту версию:


      terraform {
  required_providers {
    selectel = {
      source  = "selectel/selectel"
      version = "~> 7.3.0"
    }
  }
  required_version = ">= 1.9.8"
}

Далее требуется инициализировать Selectel provider согласно официальной инструкции:


      provider "selectel" {
  domain_name  = “123456”
  username     = “user”
  password     = “password”
  auth_region  = “ru-1”
  auth_url     = https://cloud.api.selcloud.ru/identity/v3/
}

Для проверки корректной настройки достаточно выполнить команду:

terraform init

Ожидаемый вывод при успешной настройке:

Отображение успеха в консоли.

Создание ресурсов Глобального роутера

Теперь осталось описать ресурсы Глобального роутера:

  • роутер,
  • зона ru-1,
  • зона ru-2,
  • vpc сеть в регион ru-1,
  • vpc подсеть в регионе ru-1,
  • vpc сеть в регион ru-2,
  • vpc подсеть в регионе ru-2.

Типы ресурсов и их параметры доступны в документации. Их можно найти по префиксу selectel_global_router_.

Шаг 1. Описываем глобальный роутер

Создание глобального роутера выполняется с использованием ресурса selectel_global_router_router_v1.


      resource "selectel_global_router_router_v1" "gr_router" {
  name = "terraform-router"
}

Выполним команду:

terraform plan

Ожидаемый ответ:

Ожидаемый ответ, если все сделано правильно. Вы увидите надпись "selectel_global_router_router_v1.gr_router will be created".

Шаг 2. Получаем UUID зон облака

Для подключения сетей к Глобальному роутеру в ресурсе сети необходимо указать параметр zone_id — UUID зон облака. Это можно сделать через датасорсы. В нашем облаке зоны имеют имена: ru-1, ru-2 и тип vpc.


      data "selectel_global_router_zone_v1" "vpc_zone1" {
  name    = “ru-1”
  service = "vpc"
}

data "selectel_global_router_zone_v1" "vpc_zone2" {
  name    = “ru-2”
  service = "vpc"
}

Шаг 3. Подключаем сети к созданному роутеру

Описываем ресурсы сетей для подключения к роутеру. Перечисляем параметры:

  • router_id – UUID ранее описанного роутера,
  • zone_id – в какой зоне находится Openstack сеть, на основе дата сорсов выше,
  • project_id – UUID проекта, в котором находятся искомые сети,
  • name – имя для сети в глобальном роутере,
  • os_network_id – UUID Openstack сети в соответствующей зоне.

UUID Openstack сети доступно как через CLI, так и через панель управления:

Отображение двух ВМ в панели управления.

      resource "selectel_global_router_vpc_network_v1" "gr_network_1" {
  router_id     = selectel_global_router_router_v1.gr_router.id
  zone_id       = data.selectel_global_router_zone_v1.vpc_zone1.id
  os_network_id = "dcbb82ab-9d5d-4438-ab14-0a86242bcf09"
  project_id    = "8178a2a9d6834238a608d9d339519e6b"
  name          = "gr_net_1"
}


resource "selectel_global_router_vpc_network_v1" "gr_network_2" {
  router_id = selectel_global_router_router_v1.gr_router.id
  zone_id       = data.selectel_global_router_zone_v1.vpc_zone2.id
  os_network_id = "c83d4fb4-2036-41c5-b8c3-6faf1444b071"
  project_id    = "8178a2a9d6834238a608d9d339519e6b"
  name          = "gr_net_2"
}

Валидируем итог через команду:

terraform plan

В выводе должны добавиться два новых ресурса с указанными параметрами:

Отображение новых ресурсов в консоли.

Шаг 4. Подключаем подсети к созданному роутеру

В заключительном блоке с ресурсами подсетей указываем следующие параметры:

  • network_id — UUID одной из ранее созданных сетей, в которой находится подсеть;
  • os_subnet_id — UUID Openstack подсети в соответствующей сети;
  • name – имя для подсети в глобальном роутере;
  • cidr — CIDR подсети, он должен совпадать с CIDR подсети в Openstack;
  • service_addresses — два IP-адреса, которые будут использованы сервисом для внутренних целей. По аналогии с созданием в панели управления выберем два свободных адреса из указанного CIDR подсети, заканчивающихся на .13, .14;
  • gateway — сервисный IP-адрес шлюза. По аналогии с созданием в панели управления выберем первый адрес из указанного CIDR подсети, заканчивающийся на .1.

UUID и CIDR Openstack подсети доступно как через CLI, так и через панель управления:

Отображение сети в панели управления.

      resource "selectel_global_router_vpc_subnet_v1" "gr_subnet_1" {
  network_id        = selectel_global_router_vpc_network_v1.gr_network_1.id
  os_subnet_id      = "b44dba75-bb76-4fc1-85e6-da07066fdc7f"
  cidr              = "192.168.0.0/28"
  gateway           = "192.168.0.1"
  service_addresses = ["192.168.0.13", "192.168.0.14"]
  name              = "gr_subnet_1"
}

resource "selectel_global_router_vpc_subnet_v1" "gr_subnet_2" {
  network_id        = selectel_global_router_vpc_network_v1.gr_network_2.id
  os_subnet_id      = "310dc6da-1d97-4ab3-9268-ab56d70beb86"
  cidr              = "172.16.0.0/28"
  gateway           = "172.16.0.1"
  service_addresses = ["172.16.0.13", "172.16.0.14"]
  name              = "gr_subnet_2"
}

Вывод terraform plan должен быть вида:

Вывод terraform plan.

Создание и проверка

Финально убеждаемся, что все ресурсы описаны корректно и создаем их:


      terraform plan
terraform apply

Лог успешного создания всех ресурсов:

Оторажение логов в случае успеха.

Проверяем, что у нас было создано через панель управления:

Отображение сетей в панели управления.

И запускаем тест проверки работоспособности, который использовали ранее:

  • логинимся по SSH на ВМ2, ставим утилиту tcpdump и смотрим ICMP-пакеты;
  • логинимся на ВМ1 и запускаем ping до ВМ2 по внутреннему адресу 172.16.0.2.
Логинимся на ВМ2.
Логинимся на ВМ1 и запускаем пинг до ВМ2.

Как видно, сеть была настроена аналогичным образом и виртуальные машины могут получить доступ друг к другу по IP-адресам внутри приватных сетей.

Заключение

Если вы только осваиваете Terraform и хотите создать схожую инфраструктуру, вам может пригодиться наш репозиторий с примерами Terraform-шаблонов. По ссылке вы найдете шаблоны для создания двух ВМ в разных зонах, соединенных в одну сеть с помощью Глобального роутера. Всю эту топологию можно создать за пару команд в Terraform и сразу зайти на одну из виртуальных машин, чтобы отправить ping на другую.

Буду рад обратной связи по использованию новых ресурсов в Terraform. Найденные проблемы можно оформлять в виде issue проекта на GitHub.

В следующей статье планирую рассказать о еще одном популярном сценарии использования Глобального роутера: как соединить виртуальную машину в облаке с выделенным сервером. Рассмотрю как использовать Terraform для автоматизации такой топологии.