Terraform: создание и управление инфраструктурой


В этой статье расскажем о преимуществах использования Terraform: что это такое, какие задачи решает и опишем подробнее процесс установки на Windows, Ubuntu, centOS.
Terraform - это программный инструмент для создания инфраструктуры в облаке при помощи кода, так называемый IaC (Infrastructure as code).
Terraform, как инструмент, несет преимущества для пользователей облачных сервисов, в том числе и в облаке mClouds. Terraform позволит быстро развернуть и настроить инфраструктуру с помощью кода, упростит администрирование облачными ресурсами. В этом и состоит главная задача Terraform — доступное и простое управление состоянием ИТ-инфраструктуры.
В работе с инструментом отметим следующие преимущества:
- Скорость развертывания пользовательских виртуальных стендов(теннантов - логических сущностей, использующих выделенные ресурсы в своих целях). Вся виртуальная среда может быть развернута одновременно с необходимыми параметрами с минимальным количеством кликов и без участия технической поддержки.
- Моментальная проверка плана активации нового теннанта. С помощью описанного кода можно проверить, что и в каком порядке будет создано или изменено.
- Удобное использование для создания демо-стендов под тестирование и отладку программного обеспечения. Вы можете создавать и передавать стенды для отдела тестирования, параллельно проверять ПО в разных средах, а также моментально изменять и удалять ресурсы, создав лишь один план построения ресурсов.
Из чего состоит Terraform
Кратко разберемся с составляющими Terraform:
Providers (провайдеры)
В Terraform всякий тип инфраструктуры описывается как ресурс. Связь между ресурсами и платформой API обеспечивается благодаря модулям-провайдерам. Они позволяют создавать ресурсы в рамках нужной платформы, например, VMware vCloud Director. В рамках одного проекта можно работать сразу с несколькими провайдерами одновременно.
Resources (описание ресурсов)
Описание ресурсов, фактически - это описание вашей инфраструктуры. Сеть, виртуальная машина, правило для межсетевого экрана или для проброса порта - все это есть ресурс.
Вы можете самостоятельно создавать описание ресурсов для провайдера VMware vCloud Director и применять описание для создания ресурсов у любого хостинг-провайдера, которой использует vCloud Director. Достаточно лишь изменить параметры аутентификации и параметры подключения к необходимому провайдеру.
Provisioners
Эта составляющая позволяет выполнять операции по первоначальной настройке и обслуживанию операционной системы после создания виртуальных машин. После того, как будет создан ресурс виртуальной машины, с помощью provisioners, вы можете настроить и подключиться к ней по SSH и, например, выполнить обновление ОС, а также загрузить и выполнить скрипт.
Input и Output переменные
Input переменные - входные переменные для любых типов блоков. Output переменные позволяют сохранить значения после создания ресурсов и могут быть использованы в качестве входных переменных в других модулях, например в блоке Provisioners.
States (состояния)
Хранят информацию о конфигурации ресурсов платформы провайдера.
Структура блоков
В Terraform все состоит из блоков разных видов. Общая структура блока выглядит следующим образом:
BLOCK_TYPE “BLOCK_LABEL” “BLOCK_LABEL”{
#block body
<Identifier> = expression# пример объявления составляющих блоков
}
Язык Terraform является декларативным, поэтому порядок следования блоков значения не имеет, кроме блоков provisioner, где описывается команды для выполнения при подготовке инфраструктуры. И нам важно, чтобы блоки шли в правильном порядке, иначе можно получить ошибку.
Terraform использует язык программирования HCL. Подробную информацию о синтаксисе можно почитать здесь.
Terraform можно загрузить с официального сайта разработчика. В Российской федерации он блокируется, поэтому для загрузки дистрибутива, доступа к документации и дальнейшего использования необходимо использовать proxy.
После загрузки исполняемого файла его необходимо будет положить в папку с проектом.
Создание инфраструктуры
С теорией разобрались. Настало время собственноручно создать инфраструктуру. В нашем примере мы будем создавать vAPP, три виртуальные машины:
- Windows Server,
- Debian с nginx в качестве web сервера,
- CentOS в качестве FTP-сервера.
Также мы создадим локальную сеть, подключим к ней виртуальные машины и настроим для них доступ в интернет. Плюс мы настроим правила для удаленного доступа к виртуальным машинам из сети Интернет.
Структура нашего проекта будет проста и состоять всего из двух файлов:
- tf - файл с описанием переменных.
- tf - файл с объявлениями параметров для нашей виртуальной инфраструктуры.
Вообще можно создавать отдельные файлы с описанием различных параметров, например, файл network.tf, где мы могли бы описать только сетевые параметры. Но мы ограничимся только двумя файлами для простоты примера.
Для работы мы будем использовать следующий набор:
- Ноутбук с Windows 11 и официальный дистрибутив версии 1.3.7.
- Для редактирования кода будем применять Visual Studio Code с установленным расширением Terraform для удобства.
Конфигурация виртуальных машин
Конфигурация виртуальных машин выглядит так:

- Итак, создадим нашу инфраструктуру и начнем с файла settings.tf, где опишем необходимые нам переменные.
Перво-наперво, опишем переменную провайдера, где укажем параметры подключения к виртуальному дата-центру:
variable "connect" {
type = map
default = {
"organization" = "organization-name"
"url_connect" = "organization-api url"
"data_center" = "data-center name"
"user" = "organization-administrator name"
"password" = "organization-administrator password"
}
}Что же мы тут написали? Мы указали переменную connect и присвоили ей тип map - словарь, то есть, он будет содержать в себе набор значений по принципу “ключ-значение”. И далее в блоке default мы указываем наши данные:
- organization - название нашей организации,
- url_connect - ссылка для отправки api запросов в наш дата центр,
- data_center - название дата центра,
- user - имя пользователя-администратора дата центра,
- password - пароль пользователя.
Параметры можно найти в vCloud Director: подменю Administration в разделе Settings -> General.

2. Далее опишем внешнюю сеть, к которой будет подключаться наша инфраструктура:
variable "main_net"{
type = map
default = {
name = "EXTENDED-NET-NAME"
type = "ext"
}
}Здесь мы также используем тип map.
3. После этого перейдем к ответственному шагу - переменной, описывающую нашу локальную сеть (саму сеть мы создадим далее):
variable "routed_net"{
type = map
default = {
"edge" = "sanya-test-EDGE" # название виртуального маршрутизатора
"name" = "test_net" # название сети
"gateway" = "10.10.10.254" # шлюз по умолчанию
"cidr" = "10.10.10.0/24" # идентификатор сети
"static_start" = "10.10.10.1" # начальный адрес пула
"static_end" = "10.10.10.200" # конечный адрес пула
"type" = "org" # тип сети(в нашем случае - сеть организации)
"netmask" = "255.255.255.0" # маска сети
"dns_1" = "1.1.1.1" # первый dns сервер
"dns_2" = "8.8.8.8" # второй dns сервер
}
}И здесь мы тоже использовали тип map и указали параметры нашей будущей сети.
4. И последняя переменная - это переменная “edge”, описывающая наш граничный маршрутизатор, его название и внешний IP-адрес:
variable "edge"{
type = map
default = {
"name" = "test-EDGE"
"ip" = "public ip"
}
}На этом мы закончили описывать переменные и теперь переходим к файлу main.tf. В нём мы будем описывать нашу будущую инфраструктуру.
В этом файле порядок блоков важен, так как в противном случае, мы не сможем, например, подключить сеть к виртуальной машине, если она не будет создана.
Итак, начнём.
- Первым делом, напишем блок провайдера:
terraform {
required_providers {
vcd = {
source = "vmware/vcd"
version = "3.7"
}
}
required_version = ">= 0.13"
}В этом блоке указываем каким провайдером мы будем пользоваться, уточняем необходимую версию. В нашем случае будем пользоваться провайдером vcd, так как наша инфраструктура построена на VMWare. Версию Terraform мы указываем 3.7. Такую мы используем в нашей компании.
2. Далее идёт блок подключения к vCloud Director:
provider "vcd" {
auth_type = "integrated"
max_retry_timeout = 10
user = var.connect["user"]
password = var.connect["password"]
org = var.connect["organization"]
url = var.connect["url_connect"]
}Тут мы указываем тип аутентификации - внутренний, максимальную задержку попытки и данные для подключения: пользователя, пароль, организацию и url-ссылку для обработки api запросов. Если вы уже заметили, мы используем данные из переменной connect, которую описывали в файле settings.tf.
Обратите внимание на синтаксис. В общем случае он выглядит вот так: var.variable_name[“parameter_name”].
Очень похоже на обращение к элементу словаря по его ключу в языках программирования. Этим мы еще не раз воспользуемся в дальнейшем.
3. Далее идёт блок создания vApp, в котором будут храниться наши виртуальные машины:
resource "vcd_vapp" "vapp" {
org = var.connect["organization"]
vdc = var.connect["data_center"]
name = "testVApp"
power_on = true
depends_on = [vcd_network_routed.net]
}В этом блоке, кода мы указываем организацию и виртуальный дата-центр (их надо указывать в начале каждого блока создания ресурсов в дата-центре, иначе может возникнуть ошибка).
4. Далее мы указываем имя нашего VApp - testVapp, говорим, что он будет сразу включен после создания.
5. Далее идет важная часть - зависимость от другого блока. Это делается для того, чтобы быть точно уверенным, что нужный ресурс будет создан, чтобы не получить ошибку на моменте создания. В нашем случае мы указываем, что обязательна должна быть создана сеть, чтобы её можно было добавить в VApp. Синтаксис обращения к ресурсу отличается от синтаксиса обращения к переменной: сначала указывается название ресурса в провайдере, затем через точку пишется произвольное название нашего ресурса. Первая часть обязательно должна быть ресурсом, входящим в состав провайдера, иначе мы не сможем создать и получим ошибку.
Более подробно ознакомиться с перечнем ресурсов провайдера vcd и списком параметров каждого ресурса можно здесь.
6. Далее мы создаем нашу локальную сеть, используя следующий код:
resource "vcd_network_routed" "net"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
name = var.routed_net["name"]
edge_gateway = var.routed_net["edge"]
gateway = var.routed_net["gateway"]
netmask = var.routed_net["netmask"]
dns1 = var.routed_net["dns_1"]
dns2 = var.routed_net["dns_2"]
static_ip_pool { #Пул статик IP-адресов
start_address = var.routed_net["static_start"] #первый адрес пула
end_address = var.routed_net["static_end"] #последний адрес пула
}
}В нём мы создаем ресурс vcd_network_routed, так как наша сеть будет маршрутизируемой и иметь доступ в Интернет, и называем его net. В его параметрах мы указываем данные из переменной routed_net, не забывая в начале описания ресурса указать организацию и дата-центр.
7. Далее мы подключаем нашу сеть к VApp через описание ресурса vcd_vapp_org_network:
resource "vcd_vapp_org_network" "direct_network" {
org = var.connect["organization"]
vdc = var.connect["data_center"]
vapp_name = vcd_vapp.vapp.name
org_network_name = vcd_network_routed.net.name
}Так как в блоке создания VApp мы указали зависимость от ресурса сети, то мы точно уверены, что добавляемая нами сеть создана с нужными нам параметрами, и остается лишь присвоить параметрам ресурса нужные значения.
8. Далее идёт самые большие по количество строк кода ресурсы - наши виртуальные машины:
resource "vcd_vapp_vm" "ubuntu23"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
vapp_name = vcd_vapp.vapp.name
name = "ubuntu23"
computer_name = "ubuntu23"
catalog_name = "Templates"
template_name = "GoldUbuntu23"
power_on = true
cpus = 1
cpu_cores = 1
memory = 4096
storage_profile = "Gold Storage Policy"
network {
type = "org"
name = vcd_vapp_org_network.direct_network.org_network_name
is_primary = true
adapter_type = "VMXNET3"
ip_allocation_mode = "MANUAL"
ip = "10.10.10.4"
}
override_template_disk {
bus_type = "paravirtual"
size_in_mb = "32768"
bus_number = 0
unit_number = 0
storage_profile = "Silver Storage Policy"
}
depends_on = [vcd_vapp_org_network.direct_network]
}*описание виртуальной машины с Ubuntu23.
Итак, как видим, мы создали ресурс виртуальной машины centos, указали имя каталога и имя темплейта, из которого виртуальная машина будет создана. Далее мы поставили параметр power_on в значение true, что говорит о том, что машина будет сразу включена после создания.
После мы выдали нашей машине 1 виртуальное ядро процессора и 4 ГБ оперативной памяти и указали политику жестких дисков.
После этого идёт блок с описанием сетевых параметров:
- мы обозначили тип сети как “сеть организации”(сеть именно такого типа мы создали чуть выше) и её имя. Наш сетевой интерфейс будет главным у виртуальной машины (параметр is_primary стоит в значении true).
- мы указали тип адаптера как VMXNET3 (такой тип надо указывать всегда), способ получения ip адреса как “ручной”, то есть мы вручную настроим его и выдали нашей машине ip address 10.10.10.4.
- далее мы изменяем объем дискового пространства машины (параметр override_template_disk). Здесь мы назначили тип шины как “паравиртуальная”, указали размер нашего диска - 32 ГБ (для Windows server мы будем выделять 40 ГБ дискового пространства). Следует отметить, что размер диска указывается в МБ.
Каждый блок ресурса виртуальной машины идентичен по наполнению, за исключением используемой ОС, имени компьютера, PI-адресу и пространству на диске. Поэтому мы не будем описывать ресурсы двух оставшихся виртуальных машин, отметим, что в них мы применим кастомизацию ОС.
resource "vcd_vapp_vm" "debian"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
vapp_name = vcd_vapp.vapp.name
name = "debian12"
computer_name = "debian-vm"
catalog_name = "Templates-name"
template_name = "debian-template-name"
power_on = true
cpus = 1
cpu_cores = 1
memory = 4096
storage_profile = "Gold Storage Policy"
network {
type = "org"
name = vcd_vapp_org_network.direct_network.org_network_name
is_primary = true
adapter_type = "VMXNET3"
ip_allocation_mode = "MANUAL"
ip = "10.10.10.2"
}
override_template_disk {
bus_type = "paravirtual"
size_in_mb = "32768"
bus_number = 0
unit_number = 0
storage_profile = "Gold Storage Policy"
}
customization {
enabled = true
force = true
allow_local_admin_password = true
auto_generate_password = false
admin_password = "password-example"
}
depends_on = [vcd_vapp_org_network.direct_network]
}
*Описание виртуальной машины с debian
resource "vcd_vapp_vm" "winsrv"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
vapp_name = vcd_vapp.vapp.name
name = "windowsServer2019"
computer_name = "winserver"
catalog_name = "templates-name"
template_name = "windows-server-2019-template-name"
power_on = true
cpus = 1
cpu_cores = 1
memory = 4096
storage_profile = "Gold Storage Policy"
network {
type = "org"
name = vcd_vapp_org_network.direct_network.org_network_name
is_primary = true
adapter_type = "VMXNET3"
ip_allocation_mode = "MANUAL"
ip = "10.10.10.3"
}
override_template_disk {
bus_type = "paravirtual"
size_in_mb = "61440"
bus_number = 0
unit_number = 0
storage_profile = "Gold Storage Policy"
}
customization {
enabled = true
force = true
allow_local_admin_password = true
auto_generate_password = false
admin_password = "password-example"
}
depends_on = [vcd_vapp_org_network.direct_network]
}*Описание виртуальной машины с Windows Server
Кастомизация ОС делается следующим образом:
- сначала мы включаем ее (enabled - true) - это обязательный параметр, без него сделать кастомизацию не выйдет,
- после мы ставим параметр force в true, что говорит о том, что виртуальная машина будет запущена с применением кастомизации.
- далее мы меняем пароль администраторской учетной записи (в Unix-системах - это пользователь root, в Windows - Администратор). Указываем, что мы будем менять пароль администратора (allow_local_admin_password = true), отключаем автогенерацию пароля (auto_generate_password = false) и указываем сам пароль (admin_password= “password-example”).
Создание правил межсетевого экрана и NAT
Теперь мы переходим к созданию правил межсетевого экрана и NAT.
resource "vcd_nsxv_snat" "internet_access"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
edge_gateway = var.edge["name"]
network_type = var.main_net["type"]
network_name = var.main_net["name"]
original_address = var.routed_net["cidr"]
translated_address = var.edge["ip"]
depends_on = [vcd_network_routed.net]
}Этим ресурсом мы создаем правило для доступа нашей локальной сети в Интернет. Здесь нам интересны следующие параметры:
- network-name - имя сети, к которой будет применимо правило (в нашем случае - это внешняя сеть, к которой подключен ЦОД),
- original_address - адрес источника до преобразования. В него мы передаем CIDR нашей внутренней сети организации, то есть под это правило будет попадать любой трафик, исходящий из локальной сети,
- далее идет адрес после преобразования - наш внешний IP-адрес.
Таким нехитрым образом мы даем всем нашим виртуальным машинам доступ в Интернет. Следующими тремя ресурсами мы создадим правила для проброса портов из Интернета во внутреннюю сеть для удаленного доступа к виртуальным машинам:
resource "vcd_nsxv_dnat" "ubuntu"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
edge_gateway = var.edge["name"]
network_type = var.main_net["type"]
network_name = var.main_net["name"]
original_address = var.edge["ip"]
original_port = "38004"
translated_address = "10.10.10.4"
translated_port = "22"
protocol = "tcp"
}*правило для доступа к ubuntu по SSH
resource "vcd_nsxv_dnat" "debian"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
edge_gateway = var.edge["name"]
network_type = var.main_net["type"]
network_name = var.main_net["name"]
original_address = var.edge["ip"]
original_port = "38002"
translated_address = "10.10.10.2"
translated_port = "22"
protocol = "tcp"
}*правило для доступа к debian по SSH
resource "vcd_nsxv_dnat" "windows"{
org = var.connect["organization"]
vdc = var.connect["data_center"]
edge_gateway = var.edge["name"]
network_type = var.main_net["type"]
network_name = var.main_net["name"]
original_address = var.edge["ip"]
original_port = "38003"
translated_address = "10.10.10.3"
translated_port = "3389"
protocol = "tcp"
}*правило для доступа к Windows server по RDP
Отметим, что в целях безопасности, удаленный доступ происходит по нестандартным портам (напомним, что для SSH стандартным является порт 22 tcp, для протокола RDP - 3389 tcp), и они подменяются на этапе прохождения трафика через маршрутизатор edge.
Запуск кода и создание инфраструктуры
Теперь, когда инфраструктура описана, ее можно создать.
Для этого перейдите в папку проекта, где уже находятся два файла с кодом и загруженный ранее дистрибутив, и выполните команду terraform.exe init. (если вы используете PowerShell, то команда выглядит следующим образом: ./terraform init):

Как мы видим, Terraform успешно проинициализирован и готов к последующей работе. Далее мы вводим команду terraform.exe plan, которой добавляем наш код в очередь, проверяем его на ошибки и проверяет дата центр на то, что описанная выше инфраструктура уже существует. Та, которой нет, будет добавлена в очередь на создание:
* Неполный вывод команды terraform.exe plan
После ввода команды мы получим следующий результат:
![]()
Такой план связан с тем, что до этого уже создавались ресурсы при помощи Terraform , 2 ресурса будут удалены, так как их параметры поменялись, и Terraform удалит их, чтобы пересоздать, и 6 ресурсов будут созданы с нуля. В случае, если конфигурация создается с нуля, то terraform будет только создавать и ничего не изменять и удалять.
Для создания ресурсов вводим команду terraform.exe apply:
* Неполный вывод команды terraform.exe plan
Далее вводим yes в терминал для подтверждения и ждем, пока Terraform создаст всю вышеописанную инфраструктуру.
Результат - успех. Вся инфраструктура создана!
* Часть вывода команды terraform.exe apply
Если мы зайдем в vCloud Director, то мы увидим, что инфраструктура создана.



Далее можно подключаться к виртуальным машинам и производить дополнительную настройку.
Итоги
Подведем итоги, что мы узнали:
- Terraform - это OpenSource гибкая система управления состоянием инфраструктуры, который использует декларативный стиль написания кода.
- Вся инфраструктура может быть развернута одновременно с необходимыми параметрами.
- Подключение к облачным провайдерам происходит через специальные модули - провайдеры. Для подключения к VMWare vCloud Director используется провайдер VCD
- Terraform использует собственный язык программирования HCL. Синтаксис языка напоминает JSON, но имеет блочную структуру.
- IaC код можно хранить, например, на GitHub, что дает единую точку входа для работы с инфраструктурой и повышает прозрачность кода - все внесенные в код правки должны пройти согласование.
Также мы создали свою инфраструктуру, состоящую из локальной сети, одного VApp, трех виртуальных машин, правил межсетевого экрана для удаленного доступа к машинам из сети Интернет по нестандартным портам и доступа внутренней сети в Интернет.
В заключение хочется сказать, что Terraform - очень удобный инструмент для развертывания инфраструктуры, использующий код для ее описания. Да, итоговый код может выглядеть громоздким и на его написание может уйти время, но потом введя всего три команды, мы получаем готовую инфраструктуру, которую можно использовать сразу либо дополнительно настроить, а после уже использовать.
Выбираем GPU для ИИ: Видеокарты NVIDIA RTX 4090 и 5090 vs L40S 48GBРазобрали как выбрать видеокарту для работы с нейросетями. Сравнили работу с разным объемом памяти, где идет выбор между популярными RTX 4090 24GB, RTX 5090 32Gb и серверной L40S 48GB для ИИ. Наше сравнение видеокарт поможет вам принять оптимальное решение с учетом специфики ваших задач и бюджетных ограничений.
16 октября, 2025
Как выбрать сервер для 1С-Битрикс: Управление сайтом, чтобы сайт быстро работал и не падалПравильный выбор сервера для 1С-Битрикс: Управление сайтом это ключ к стабильной и быстрой работе сайта. В статье разбираем основные критерии подбора конфигурации.
30 мая, 2025
Использование WebUI для Nginx: обзор веб-интерфейсовРассказываем как упростить управление веб-сервером Nginx с помощью веб-интерфейсов. Разбираем их возможности и особенности установки.
20 мая, 2025