
Привет, Хабр! Меня зовут Сергей, я разработчик облачной платформы в Selectel. В прошлой статье я рассказал об использовании Terraform для создания глобального роутера и настройки сетевой связности между разными регионами облака. Сегодня продолжим тему и объединим в сеть выделенный и облачный серверы.
Материал будет полезен DevOps-инженерам и специалистам, владеющим Terraform хотя бы на базовом уровне. Тем, кто только знакомится с инструментом, рекомендую сначала изучить основы.
Содержание
→ Исходные условия
→ Способ 1. Настраиваем в панели управления
→ Способ 2. Автоматическая настройка с помощью Terraform Provider
→ Шаг 1. Провайдер, роутер и сети облака
→ Шаг 2. Добавляем сеть до выделенного сервера
→ Шаг 3. Настройка подсети выделенного сервера
→ Проверяем итоговый результат
→ Как корректно указать зону в ресурсе сети
→ Ранее созданные ресурсы и import
→ Заключение
Исходные условия
Часть инфраструктуры осталась прежней — это сервер в петербургском облачном регионе 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.

Бесплатная миграция в Selectel
Начислим до 1 000 000 бонусов на два месяца. А наши инженеры подготовят план и поддержат на всех этапах миграции.
Способ 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.