Как автоматически связать выделенный и облачный серверы

Автоматизируем создание глобального роутера для связи выделенного и облачного серверов

Продолжаем говорить об использовании Terraform. Посмотрим, как объединить выделенный и облачный серверы в единую сеть.

Привет! Меня зовут Сергей Крайнев, я разработчик облачной платформы. В прошлой статье рассказал об использовании Terraform для создания глобального роутера и настройки сетевой связности между разными регионами облака. Сегодня продолжим тему и объединим в сеть выделенный и облачный серверы.

Материал будет полезен DevOps-инженерам и специалистам, владеющим Terraform хотя бы на базовом уровне. Тем, кто только знакомится с инструментом, рекомендую сначала изучить основы.

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

Часть инфраструктуры осталась прежней — это сервер в петербургском облачном регионе ru‑1. Для демонстрации нового сценария дополнительно зарезервирован «железный» сервер в московской локации MSK-2.

Облачный сервер в зоне ru-1:

  • облачная сеть с подсетью 192.168.0.0/28,
  • виртуальная машина (ВМ) в этой сети с IP‑адресом 192.168.0.2,
  • облачный роутер, подключенный к сети с плавающим IP 95.213.180.201.
Панель управления: показан статус виртуальной машины в зоне ru-1.

Выделенный сервер в зоне MSK-2:

  • облачная сеть с подсетью 172.16.0.0/28,
  • IP‑адрес хоста в этой сети — 172.16.0.2,
Панель управления: показан статус выделенного сервера в зоне MSK‑2.

Такая инфраструктура позволяет решать различные задачи — в том числе те, что описаны в документации.

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

Как и ранее, решим задачу с помощью глобального роутера Selectel. В результате московский выделенный сервер станет доступен с ВМ1 по внутреннему IP-адресу в серой сети. Проверка связности полностью аналогична и выполняется с помощью ping-запросов.

Целевая схема будет выглядеть так:

Схема настройки инфраструктуры: глобальный роутер соединяет подсеть выделенного сервера в зоне MSK-2 и подсеть облачного сервера в зоне ru-1.

Далее рассмотрим два способа реализации такой схемы:

  • вручную через панель управлениями,
  • автоматически с помощью Terraform.

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

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

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

Результат будет выглядеть так:

Интерфейс панели управления: раздел сетей с параметрами CIDR и шлюзов для выделенного сервера в локации MSK-2 и облачной платформы в зоне ru-1.

Укажем статические маршруты на обоих хостах:

  • на виртуальной машине: ip r add 172.16.0.0/28 via 192.168.0.1,
  • на выделенном сервере: ip r add 192.168.0.0/28 via 172.16.0.1.

В завершение проверим работоспособность схемы, запустив tcpdump на выделенном сервере:

Терминал: результат работы утилиты ping.
Терминал: результат работы утилиты tcpdump.

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

В статье «Автоматическое создание и настройка глобального роутера в облаке через Terraform Provider» мы подробно разобрали подключение сети с виртуальной машиной. Вспомним общие шаги.

  1. Инициализируем Terraform-провайдер.
  2. Создаем глобальный роутер.
  3. Получаем UUID облачной зоны из datasource.
  4. Подключаем сеть и подсеть в облаке к созданному глобальному роутеру.

Чтобы не усложнять пример, возьмем инфраструктуру из прошлой статьи, поэтому параметры ресурсов в манифестах останутся без изменений.

Шаг 1. Провайдер, роутер и сети облака


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

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

# Global Router resources

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

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

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_zone.id
  os_network_id = "dcbb82ab-9d5d-4438-ab14-0a86242bcf09"
  project_id    = "8178a2a9d6834238a608d9d339519e6b"
  name          = "gr_vpc_net"
}

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              = "vpc_subnet"
}

Скопируем код в шаблон main.tf и убедимся, что все работает, выполнив команды:


      terraform plan
terraform apply

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

Терминал: экранный журнал применения команды terraform applay.
Вывод результата в консоли.
Панель управления: свойства сети.
Ожидаемый результат в панели управления Selectel.

Шаг 2. Добавляем сеть до выделенного сервера

Теперь поговорим о ресурсах, которые еще не рассматривали. Начнем с подключения сети до выделенного сервера. Обязательные параметры для описания этой сущности в манифесте:

  • router_id — UUID созданного ранее глобального роутера;
  • zone_id — в какой зоне находится выделенный сервер;
  • vlan — тег VLAN серой сети, к которой подключен выделенный сервер;
  • name — имя сети внутри глобального роутера.

Часть атрибутов совпадает с настройками облачной сети, но есть и отличия. Важно: zone_id в данном случае берется также из datasource, но с другими параметрами. Это логично, потому что адреса для выделенных серверов находятся в другой зоне с иным именем и типом сервиса.


      data "selectel_global_router_zone_v1" "dedicated_zone" {
  name    = "MSK-2"
  service = "dedicated"
}

Тег VLAN можно найти на вкладке Сеть в настройках выделенного сервера. В нашем примере его значение — 1962.

Панель управления: отображены публичные и приватные IP-адреса.

Итоговое описание ресурса выглядит так:


      resource "selectel_global_router_dedicated_network_v1" "gr_network_2" {
  router_id     = selectel_global_router_router_v1.gr_router.id
  zone_id       = data.selectel_global_router_zone_v1.dedicated_zone.id
  vlan          = 1962
  name          = "gr_dedicated_net"
}

Шаг 3. Настройка подсети выделенного сервера

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

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

В манифесте код для нашей подсети выглядит так:


      resource "selectel_global_router_dedicated_subnet_v1" "gr_subnet_2" {
  network_id        = selectel_global_router_dedicated_network_v1.gr_network_2.id
  cidr              = "172.16.0.0/28"
  gateway           = "172.16.0.1"
  service_addresses = ["172.16.0.13", "172.16.0.14"]
  name              = "dedicated_subnet"
}

Проверяем итоговый результат

Добавим блоки datasource, сети и подсети в шаблон, после чего применим новую конфигурацию:


      terraform plan
terraform apply

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

Терминал: экранный журнал работы команды terraform applay.

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

Результат настройки через Terraform Provider в панели управления: успешно созданные сети gr_dedicated_net для оборудования и gr_vpc_net для облака.

Выполним итоговую проверку:

  • на выделенном сервере запускаем tcpdump и отслеживаем ICMP-пакеты;
  • на виртуальной машине с помощью утилиты ping отправляем эхо‑пакеты до выделенного сервера по внутреннему адресу 172.16.0.2.
Терминал: результат работы утилиты ping.
Терминал: результат работы утилиты tcpdump.

Итак, мы воспроизвели настройку в панели управления и организовали сетевую связность между серверами с помощью глобального роутера.

Как корректно указать зону в ресурсе сети

Отдельно хотелось подсветить вопрос использования параметра зоны при создании сетей. Выше показан рекомендуемый способ — получение zone_id через datasource. Есть и альтернативный вариант:узнать zone_id через API глобального роутера и явно указать UUID:


      resource "selectel_global_router_dedicated_network_v1" "gr_network_2" {
  router_id     = selectel_global_router_router_v1.gr_router.id
  zone_id       = 85d96ea3-b853-4cb9-a761-b79d202a2f90
  vlan          = 1962
  name          = "gr_dedicated_net"
}

Однако стоит избегать указания имени зоны вместо UUID в этом параметре. Приведенный ниже пример некорректен и работать не будет:


      resource "selectel_global_router_dedicated_network_v1" "gr_network_2" {
  router_id     = selectel_global_router_router_v1.gr_router.id
  zone_id       = "MSK-2"
  vlan          = 1962
  name          = "gr_dedicated_net"
}

Ранее созданные ресурсы и import 

В заключение хочется уделить несколько слов импорту ресурсов в Terraform. Многие о нем слышали, но не все применяли на практике.

Представим ситуацию: ресурсы созданы через API, а инструмент IaC внедряется позже. 

Что делать в таком случае?

Пересоздание ресурсов «с чистого листа» — не вариант, а хочется добавить автоматизацию и расширять инфраструктуру с помощью Terraform.

Здесь выручит команда terraform import. Чаще всего используется два подхода:

  • точечный импорт отдельного ресурса через Terraform CLI.
  • массовый перенос группы сущностей через шаблон и блок import.

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

Для первого подхода (работа в CLI) выполняется команда:


      terraform import <resource_type>.<resource_name> <resource_id>

# реальный пример
terraform import selectel_global_router_router_v1.gr_router 7474f486-b55a-4374-895d-b54cde2a1182

Ресурс будет импортирован и в дальнейшем им можно будет управлять через описание в шаблоне. 

Однако переносить таким образом множество объектов довольно затруднительно. Конечно, можно написать скрипт со множеством команд import и добавить все ресурсы по очереди.

Но зачем страдать, если есть более изящное решение — описать секцию импортов прямо в манифесте. Предположим, сетевая топология из статьи собрана вручную в панели управления, и мы хотим перенести ее в Terraform. Для этого создаем шаблон с описанием всех элементов, как в примерах выше, а в конце добавляем конструкции import:


      import {
  to = selectel_global_router_router_v1.gr_router
  id = "7474f486-b55a-4374-895d-b54cde2a1182"
}
import {
  to = selectel_global_router_vpc_network_v1.gr_network_1
  id = "3258698b-ba95-43a1-81ad-0865cc66ab1b"
}
import {
  to = selectel_global_router_dedicated_network_v1.gr_network_2
  id = "ea184aca-b882-4f6a-a2f2-2fbd20902e22"
}
import {
  to = selectel_global_router_vpc_subnet_v1.gr_subnet_1
  id = "49f9f443-76a9-4e14-9bcc-73d6ee14df89"
}
import {
  to = selectel_global_router_dedicated_subnet_v1.gr_subnet_2
  id = "03d6b9e1-3614-4ee2-a10e-c01f2606e9de"
}

Затем выполняем уже известные команды:


      terraform plan
terraform apply

Terraform импортирует ресурсы — не создает!

Терминал: результат работы команды terraform applay.

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

Заключение

Terraform, очевидно, упрощает развертывание инфраструктуры. Рассмотренный в статье пример, можно полностью автоматизировать — «с чистого листа» создать и связать через глобальный роутер выделенный и облачный серверы. Готовый манифест есть в нашем репозитории. Пара команд в консоли, настройка статических маршрутов — и можно повторить описанную топологию у себя в аккаунте Selectel.

Надеюсь, эта статья поможет упростить переход на автоматизацию работы с инфраструктурой с помощью Terraform. 

Также рекомендую к ознакомлению статью о том, «Как в Selectel с помощью Terraform заказать выделенный сервер» под любые нужды: от сервера для хостинга любимой игры — до PET проекта с LLM.