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 - очень удобный инструмент для развертывания инфраструктуры, использующий код для ее описания. Да, итоговый код может выглядеть громоздким и на его написание может уйти время, но потом введя всего три команды, мы получаем готовую инфраструктуру, которую можно использовать сразу либо дополнительно настроить, а после уже использовать.
Виртуализация — неизбежная и незаменимая часть современной ИТ-инфраструктуры любого бизнеса. Что это такое и как она работает, рассмотрим в этой статье.
01 октября, 2024Как мы используем продукты VMware для виртуальных серверовМы строим облачную инфраструктуру на основе архитектуры этого бренда: используем VMware vSphere для создания виртуальных серверов и управления ими, панель VMware vCloud Director для управления облаком. В статье рассказываем, почему выбираем именно эти решения.
28 сентября, 2024Частные, публичные и гибридные облака: разные виды облачных сервисовРассказываем, что представляет собой гибридное облако, как оно работает, какие особенности имеет и кому подойдет
20 августа, 2024