Terraform — это средство для создания и управления инфраструктурой в коде, которое дает возможность развертывать, модифицировать и удалять разнообразные ресурсы в облачных сервисах, такие как виртуальные сервера, сетевые элементы, хранилища данных и т.д. Он применяет язык настроек HCL (HashiCorp Configuration Language), который имеет декларативный и понятный человеку синтаксис. HCL позволяет задавать требуемое состояние инфраструктуры с помощью секций, параметров и формул.
Преимущества использования:
- Вы можете запустить одинаковый код Terraform на различных платформах и получать одинаковые результаты.
- Вы можете разделять свою инфраструктуру на отдельные модули и использовать их в разных задачах.
- Вы можете работать с разными облачными провайдерами и услугами с помощью единого интерфейса.
- Вы можете сохранять свой код настроек в системе управления версиями и отслеживать изменения по времени.
- Вы можете работать над своей инфраструктурой в команде и согласовывать свои действия с помощью удаленного хранилища состояний.
Remote State
По умолчанию Terraform сохраняет своё состояние в локальном файле .tfstate. Однако при работе в команде использование локального файла усложняет работу с этим инструментом — каждый пользователь должен убедиться, что у него наиболее свежая версия файла с состоянием и что никто другой в данный момент времени не запускает создание ресурсов с аналогичным провайдером.
Механизм Remote State позволяет хранить файлы состояния в удалённом хранилище, что позволяет пользователям работать с самой свежей версией состояния и не думать о синхронизации. Terraform поддерживает следующие хранилища:
- Terraform Cloud
- HashiCorp Consul
- Amason S3 (или другое S3-совместимое хранилище)
- Google Cloud Storage
- Azure Blob Storage
- многие другие
Хранение состояния настраивается в конфигурации в блоке backend, например:
backend "s3" { endpoint = "" bucket = "" … }
Подробнее о конфигурации бэкэнда можно прочитать на сайте Terraform: Backend Configuration.
На данный момент Timeweb Cloud не поддерживает загрузку состояний в S3 для версий Terraform 1.6.0 и выше из-за изменений в структуре конфигурации.
Подготовка
Предварительные шаги для создания инфраструктуры.
Необходимые платные ресурсы
В этой статье будут созданы:
Создаём бакет
Чтобы использовать S3 в качестве хранилища состояния, нам необходимо создать бакет. Для этого перейдём в панель управления, в раздел «Хранилище S3».
Нажмём на кнопку «Заказать». Для примера возьмём минимальную конфигурацию:

На вкладке «Дашборд» бакета, который мы только что создали, отображаются настройки, которые позже укажем в файле .tf:

Пишем конфигурацию
Теперь приступим к написанию конфигурации.
- Добавляем папку
terraform_s3, в которой будет наш проект. - Создаём там файл
main.tf. - По инструкции заполняем информацию о провайдере.
Должна получиться следующая структура файлов:
├── terraform_s3 │ ├── main.tf
И следующее содержимое файла main.tf:
terraform { required_providers { twc = { source = "tf.timeweb.cloud/timeweb-cloud/timeweb-cloud" } } required_version = ">= 1.5.3" } provider "twc" { token = "<your token>" }
Теперь добавим настройки бэкенда в блок terraform.
backend "s3" { endpoint = "https://s3.twcstorage.ru" region = "ru-1" bucket = "<bucket name>" key = "states/terraform.tfstate" access_key = "<your access key>" secret_key = "<your secret key>" skip_region_validation = true skip_credentials_validation = true skip_metadata_api_check = true skip_requesting_account_id = true skip_s3_checksum = true }
Параметры:
endpoint— адрес S3-хранилища из панели управления.region— регион из панели управления.bucket— название бакета, где буду храниться наши конфигурации.key— путь к файлу в бакете вместе с названием файла. Например,states/<название файла>.tfstate.access_keyиsecret_key— ключи для доступа к бакету. Их можно получить в панели управления, на странице созданного ранее бакетаskip_region_validationиskip_credentials_validation— флаги, с помощью которых мы пропускаем валидацию региона и ключей доступа на стороне AWS. Они нужны, так как мы используем не оригинальный AWS S3, а другое облако.
Вот пример, как должен выглядеть полный код файла main.tf:
terraform { required_providers { twc = { source = "tf.timeweb.cloud/timeweb-cloud/timeweb-cloud" } } required_version = ">= 1.5.3" backend "s3" { endpoint = "s3.twcstorage.ru" region = "ru-1" bucket = "<bucket name>" key = "states/terraform.tfstate" access_key = "<your access key>" secret_key = "<your secret key>" skip_region_validation = true skip_credentials_validation = true } } provider "twc" { token = "<your token>" }
После всех настроек выполним команду terraform init:
Защита данных
В конфигурации бэкэнда параметры access_key и secret_key содержат чувствительные данные, которые не должны быть доступны посторонним лицам. Их не рекомендуется хранить в явном виде в файле конфигурации.
- Можно установить переменные окружения
AWS_ACCESS_KEY_IDиAWS_SECRET_ACCESS_KEYс соответствующими значениями ключей доступа к бакету. Тогда Terraform будет автоматически читать эти переменные при работе с бэкэндом. - Использование параметров командной строки. Можно использовать параметр
-backend-configпри выполнении командыinit:
terraform init -backend-config="access_key=1234" -backend-config="secret_key=1234"
Создаём инфраструктуру
В файле main.tf опишем создание виртуальной машины и локальной сети:
- Укажем ОС.
data "twc_os" "example-os" { name = "ubuntu" version = "22.04" }
- Укажем пресет.
data "twc_presets" "example-preset" { price_filter { from = 300 to = 400 } }
- Добавим VPC.
resource "twc_vpc" "example-vpc" { name = "Example VPC" description = "Some example VPC" subnet_v4 = "192.168.0.0/24" location = "ru-1" }
- Опишем конфигурацию сервера.
resource "twc_server" "example-server-with-local-network" { name = "Example server with local network" os_id = data.twc_os.example-os.id preset_id = data.twc_presets.example-preset.id local_network { id = twc_vpc.example-vpc.id } }
- Добавим идентификатор приватной сети в выходные параметры, чтобы мы могли использовать его в других конфигурациях
output "tw-vpc" { value = twc_vpc.example-vpc.id }
Содержимое конфигурации main.tf будет выглядеть так:
terraform { required_providers { twc = { source = "tf.timeweb.cloud/timeweb-cloud/timeweb-cloud" } } required_version = ">= 1.5.3" backend "s3" { endpoint = "s3.twcstorage.ru" region = "ru-1" bucket = "<bucket name>" key = "states/terraform.tfstate" access_key = "<your access key>" secret_key = "<your secret key>" skip_region_validation = true skip_credentials_validation = true } } provider "twc" { token = "<your token>" } data "twc_os" "example-os" { name = "ubuntu" version = "22.04" } data "twc_presets" "example-preset" { price_filter { from = 300 to = 400 } } resource "twc_vpc" "example-vpc" { name = "Example VPC" description = "Some example VPC" subnet_v4 = "192.168.0.0/24" location = "ru-1" } resource "twc_server" "example-server-with-local-network" { name = "Example server with local network" os_id = data.twc_os.example-os.id preset_id = data.twc_presets.example-preset.id local_network { id = twc_vpc.example-vpc.id } } output "tw-vpc" { value = twc_vpc.example-vpc.id }
Выполним команду terraform validate:
Затем terraform plan:
И terraform apply:
После применения конфигурации в бакете автоматически будет создан файл состояния.
Проверка и использование состояния
В панели управления можно проверить наличие файла состояния в бакете:
Теперь попробуем использовать сохранённое состояние в другой конфигурации.
Добавим новую папку remote-state:
mkdir remote-state cd remote-state
Добавим файл remote-state.tf и заполним его следующим образом:
terraform { required_providers { twc = { source = "tf.timeweb.cloud/timeweb-cloud/timeweb-cloud" } } required_version = ">= 1.5.3" } provider "twc" { token = "<your token>" } data "terraform_remote_state" "vpc" { backend = "s3" config = { endpoint = "s3.twcstorage.ru" region = "ru-1" bucket = "<bucket name>" key = "states/terraform.tfstate" skip_region_validation = true skip_credentials_validation = true access_key = "<your access key>" secret_key = "<your secret key>" } } data "twc_os" "example-os" { name = "ubuntu" version = "22.04" } data "twc_presets" "example-preset" { price_filter { from = 300 to = 400 } } resource "twc_server" "example-server-with-local-network" { name = "Example server with local network" os_id = data.twc_os.example-os.id preset_id = data.twc_presets.example-preset.id local_network { id = data.terraform_remote_state.vpc.outputs.tw-vpc } }
В этом примере мы используем outputs из предыдущего файла main.tf для получения идентификатора локальной сети, и добавляем в эту сеть новый VPS.
Выполним команды:
terraform initterraform validateterraform planterraform apply
Будет создан второй сервер в нужной локальной сети:
Чтобы удалить созданные ресурсы, выполните команду terraform destroy сначала во второй конфигурации, а затем в первой.