Автоматизируем создание глобального роутера для связи выделенного и облачного серверов
Продолжаем говорить об использовании 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.

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

Такая инфраструктура позволяет решать различные задачи — в том числе те, что описаны в документации.
Допустим, на ВМ1 в Санкт-Петербурге поднята база данных. Однако сам сервис и его окружение хочу развернуть на выделенном железном сервере в Москве, чтобы полностью контролировать вычислительные ресурсы.
Как и ранее, решим задачу с помощью глобального роутера Selectel. В результате московский выделенный сервер станет доступен с ВМ1 по внутреннему IP-адресу в серой сети. Проверка связности полностью аналогична и выполняется с помощью ping-запросов.
Целевая схема будет выглядеть так:

Далее рассмотрим два способа реализации такой схемы:
- вручную через панель управлениями,
- автоматически с помощью Terraform.
Способ 1. Настраиваем в панели управления
Воспользуемся документацией по настройке сети в облаке и подразделом по маршрутизации до выделенного сервера. Выполним следующие шаги:
- создадим ресурс глобального роутера,
- подключить к созданному роутеру изолированную сеть региона ru-1 и нужную подсеть,
- выполнить ту же процедуру для сети и подсети локации MSK-2.
Результат будет выглядеть так:

Укажем статические маршруты на обоих хостах:
- на виртуальной машине:
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 на выделенном сервере:


Способ 2. Автоматическая настройка с помощью Terraform Provider
В статье «Автоматическое создание и настройка глобального роутера в облаке через Terraform Provider» мы подробно разобрали подключение сети с виртуальной машиной. Вспомним общие шаги.
- Инициализируем Terraform-провайдер.
- Создаем глобальный роутер.
- Получаем UUID облачной зоны из datasource.
- Подключаем сеть и подсеть в облаке к созданному глобальному роутеру.
Чтобы не усложнять пример, возьмем инфраструктуру из прошлой статьи, поэтому параметры ресурсов в манифестах останутся без изменений.
Шаг 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
Ожидаемый вывод в консоли и интерфейсе панели управления показан ниже. Если результаты отличаются, рекомендуем сверить манифесты с примерами из прошлой статьи.


Шаг 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.

Итоговое описание ресурса выглядит так:
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
В облаке появятся два дополнительных ресурса:

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

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


Итак, мы воспроизвели настройку в панели управления и организовали сетевую связность между серверами с помощью глобального роутера.
Как корректно указать зону в ресурсе сети
Отдельно хотелось подсветить вопрос использования параметра зоны при создании сетей. Выше показан рекомендуемый способ — получение 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.
Заключение
Terraform, очевидно, упрощает развертывание инфраструктуры. Рассмотренный в статье пример, можно полностью автоматизировать — «с чистого листа» создать и связать через глобальный роутер выделенный и облачный серверы. Готовый манифест есть в нашем репозитории. Пара команд в консоли, настройка статических маршрутов — и можно повторить описанную топологию у себя в аккаунте Selectel.
Надеюсь, эта статья поможет упростить переход на автоматизацию работы с инфраструктурой с помощью Terraform.
Также рекомендую к ознакомлению статью о том, «Как в Selectel с помощью Terraform заказать выделенный сервер» под любые нужды: от сервера для хостинга любимой игры — до PET проекта с LLM.