Terraform#
Terraform представляет собой систему автоматизации развертывания и обновления информационной инфраструктуры с использованием доступного для организации оборудования и программного обеспечения. Для описания требуемой инфраструктуры Terraform предлагает декларативный язык на базе HCL.
Развертываемая инфраструктура может содержать самые разнообразные аппаратные и программные компоненты, включая серверы, балансировщики нагрузки, сетевое оборудование, системы хранения, компоненты безопасности и другие. Она может быть реализована как в приватном центре обработки данных, так и в одном из облачных сервисов.
Terraform предоставляет средства разработки собственных модулей в составе корпоративных систем автоматизации. Astra Automation включает в себя модули Terraform для управления информационными инфраструктурами, развертываемыми в различных облачных средах.
Принципы управления#
Принцип работы Terraform показан на схеме:
Terraform для управления ресурсами использует провайдеры – особые расширения, содержащие сведениях об API нужных сервисов. Как правило, файлы провайдеров размещаются в реестре провайдеров Terraform, однако, могут быть загружены и со сторонних ресурсов.
Используя данные, предоставленные провайдером, Terraform обращается к API нужного сервиса для получения сведений о состоянии ресурсов. Если описание ресурсов в конфигурационных файлах не совпадает с фактическим, Terraform изменяет состояние ресурсов сервиса, приводя их в соответствие описанию в конфигурационных файлах.
Управление инфраструктурой с помощью Terraform состоит из следующих шагов:
Описание ресурсов в конфигурационных файлах.
Инициализация модулей и провайдеров.
terraform init
На этом этапе Terraform загружает все необходимые файлы и сохраняет в каталоге проекта в следующие подкаталоги:
.terraform/modules/
– модули;.terraform/providers/
– провайдеры.
Проверка плана инфраструктуры.
Для проверки плана инфраструктуры используется следующая команда:
terraform validate
На этом этапе Terraform выполняет сверку описания инфраструктуры с формальными правилами, содержащимися в описаниях провайдера, модулей и переменных. Если в конфигурации инфраструктуры есть ошибки, Terraform на них укажет.
Планирование изменений.
Для получения списка изменений инфраструктуры, которые будут выполнены Terraform, чтобы привести инфраструктуру в соответствие с ее описанием в файлах проекта, используется следующая команда:
terraform plan
На этом этапе никаких фактических изменений инфраструктуры не происходит.
Применение изменений.
Для применения изменений используется следующая команда:
terraform apply
Типовая структура проекта Terraform#
В самом простом случае описание инфраструктуры с помощью Terraform хранится в одном или нескольких файлах с расширением .tf
, содержащих описания следующих сущностей:
общие настройки;
описание ресурсов.
Общие настройки#
К общим настройкам относятся:
сведения о провайдерах;
учетные данные для управления ресурсами выбранного сервиса.
Провайдер#
Провайдер определяет возможности Terraform по работе с сервисом:
параметры доступа к сервису;
перечень доступных для управления типов ресурсов;
перечень доступных для использования источников данных;
правила работы с ресурсами и источниками данных.
Перечень используемых провайдеров задается в блоке terraform.required_providers
, например:
terraform {
required_providers {
sbercloud = {
source = "sbercloud-terraform/sbercloud"
}
}
}
Здесь:
sbercloud
– название провайдера;sbercloud-terraform/sbercloud
– ссылка на источник для загрузки файлов провайдера.
Учетные данные для работы с ресурсами задаются в блоке provider
:
provider "sbercloud" {
# Настройки доступа к сервису
}
Здесь sbercloud
– название провайдера, указанное ранее.
Подробности об использовании провайдеров см. в документации Terraform.
Ресурс#
Ресурсы (виртуальные машины, сети, подсети, кластеры СУБД и т. п.) описываются в блоках resource
:
resource "openstack_db_user_v1" "user-1" {
# Описание ресурса
}
Здесь:
openstack_db_user_v1
– тип ресурса;user-1
– название ресурса, используемое в Terraform.
По умолчанию Terraform использует следующий подход при применении изменений конфигурации:
создает ресурсы, которые есть в описании инфраструктуры но отсутствуют в файле состояния;
удаляет ресурсы, которые есть в файле состояния, но отсутствуют в описании инфраструктуры;
обновляет ресурсы, параметры которых изменились;
удаляет и создает заново ресурсы, параметры которых изменились таким образом, что иначе применить их невозможно.
Подробности о ресурсах см. в документации Terraform.
Источник данных#
Источники данных (data sources) позволяют получать сведения о существующих ресурсах.
Источники данных описываются в блоках data
, например:
data "yandex_mdb_mysql_cluster" "data-source" {
name = "mysql-cluster-name"
}
где
yandex_mdb_mysql_cluster
– тип источника данных (кластер Yandex Managed Service for MySQL);data-source
– название источника данных;mysql-cluster-name
– название кластера.
Подробности об источниках данных см. в документации Terraform.
Состояние#
Состояние (state) – это информация о фактических существующих в сервисе ресурсах и связи их идентификаторов с описаниями в конфигурационных файлах Terraform.
По умолчанию состояние хранится локально в файле terraform.tfstate
.
Terraform использует его для расчета изменений, которые нужно выполнить, чтобы привести фактическое состояние ресурсов к желаемому.
Подробности о состояниях см. в документации Terraform.
Переменные и значения#
Terraform позволяет модулям хранить данные и обмениваться ими друг с другом следующими способами:
с помощью локальных значений (Local Values);
с помощью переменных, также называемых входными переменными (Input Variables);
с помощью выходных значений (Output Values).
Локальные значения#
Локальные значения позволяют многократно ссылаться на одно и то же значение без необходимости вводить его заново. Аналогом локальных значений в обычных языках программирования являются константы.
Локальные значения описываются в блоке locals
, например:
locals {
image_id = "fd87qct47l4isk56gucq",
storage_size = 40
}
где image_id
и storage_size
– названия, а fd87qct47l4isk56gucq
и 40
– значения.
Область видимости локальных значений ограничена модулем, в котором они описаны.
Для обращения к локальному значению используется следующий синтаксис:
resource "vm" "vm-1" {
image = local.image_id
disk_size = local.storage_size
# ...
}
Подробности о локальных значениях см. в документации Terraform.
Входные переменные#
Входные переменные (input variables), часто для краткости называемые просто «переменными», позволяют использовать одни и те же значения в разных модулях и .tf
-файлах.
Каждая входная переменная описывается в отдельном блоке variable
, например:
variable "image_id" {
type = string
}
Здесь image_id
– название переменной, string
– ее тип.
Для входной переменной может быть указано значение по умолчанию:
variable "image_id" {
type = string
default = "fd87qct47l4isk56gucq"
}
Для обращения к входной переменной используется следующий синтаксис:
resource "vm" "vm-1" {
image = var.image_id
# ...
}
Значения входных переменных, объявленных в корневом модуле, могут быть заданы следующими способами:
Значение параметра
-var
в аргументах командной строки.Объявления в файле с расширением
.tfvars
.Примечание
Terraform автоматически загружает значения входных переменных из файлов
terraform.tfvars
иterraform.tfvars.json
, а также из файлов, имена которых оканчиваются на.auto.tfvars
и.auto.tfvars.json
.Переменные среды.
Подробности о входных переменных см. в документации Terraform.
Выходные значения#
Выходные значения (output values) используются для передачи данных за пределы модуля.
Каждое выходное значение описывается в отдельном блоке output
, например:
output "bastion_ip" {
value = vsphere_virtual_machine.virtual_machine.default_ip_address
}
Для обращения к выходной переменной модуля из другого модуля используется следующий синтаксис:
module "vm" {
# ...
public_ip = module.bastion.bastion_ip
}
где:
bastion
– название модуля;bastion_ip
– название выходного значения.
Подробности о выходных значениях см. в документации Terraform.
Мета-аргументы#
Мета-аргументы (meta-arguments) используются для добавления в конфигурационные файлы дополнительной функциональности.
depends_on#
Мета-аргумент depends_on
используется для создания между ресурсами или модулями связей, которые не могут быть вычислены Terraform автоматически.
Пусть имеется следующее описание ресурсов, необходимых для запуска на ВМ приложения, работающего с базой данных PostgreSQL:
# Кластер Yandex Managed Service for PostgreSQL
resource "yandex_mdb_postgresql_cluster" "pg-cluster" {
# ...
}
# Пользователь кластера "pg-cluster"
resource "yandex_mdb_postgresql_user" "db-owner" {
cluster_id = yandex_mdb_postgresql_cluster.pg-cluster.id
# ...
}
# База данных в кластере "pg-cluster"
resource "yandex_mdb_postgresql_database" "db1" {
cluster_id = yandex_mdb_postgresql_cluster.pg-cluster.id
name = "db1"
owner = yandex_mdb_postgresql_user.db-owner.name
}
# Виртуальная машина
resource "yandex_compute_instance" "app-vm" {
name = "app-vm"
depends_on = [
yandex_mdb_postgresql_cluster.pg-cluster,
yandex_mdb_postgresql_user.db-owner,
yandex_mdb_postgresql_database.db1
]
# Прочие настройки ВМ
}
Между кластером СУБД, базой данных и пользователем есть прямая зависимость – поле cluster_id
у базы данных и пользователя обязательно для заполнения.
Порядок создания ресурсов в этом случае определяется логикой на стороне провайдера:
Кластер СУБД.
Пользователь СУБД.
База данных.
В то же время, ВМ не зависит от кластера СУБД, базы данных или ее пользователя. Однако, приложение, запущенное на ВМ, не сможет работать до тех пор, пока кластер СУБД, база данных и используемый для доступа к базе данных пользователь не будут созданы.
Блок depends_on
в описании ВМ указывает, что она зависит от перечисленных ресурсов и должна быть создана после них.
Подробности об использовании мета-аргумента depends_on
см. в документации Terraform.
count#
Мета-аргумент count
используется для создания однотипных ресурсов.
Пусть необходимо создать 4 одинаковых ВМ.
Соответствующую конфигурацию можно описать без использования мета-аргумента count
следующим образом:
resource "sbercloud_compute_instance" "vm-1" {
name = "vm-1"
# ...
}
resource "sbercloud_compute_instance" "vm-2" {
name = "vm-2"
# ...
}
resource "sbercloud_compute_instance" "vm-3" {
name = "vm-3"
# ...
}
resource "sbercloud_compute_instance" "vm-4" {
name = "vm-4"
# ...
}
При использовании мета-аргумента count
эту запись можно сократить:
resource "sbercloud_compute_instance" "vms" {
count = 4
name = "vm-${count.index + 1}"
# ...
}
Подробности об использовании мета-аргумента count
см. в документации Terraform.
for_each#
Мета-аргумент for_each
позволяет обрабатывать списки путем последовательного перебора их значений.
Это позволяет сократить описание однотипных ресурсов, имеющих различия в конфигурации.
Пусть необходимо создать в одной сети несколько подсетей. Описание инфраструктуры в этом случае может иметь следующий вид:
resource "sbercloud_vpc" "vpc-1" {
name = "vpc-1"
cidr = "10.33.0.0/24"
}
resource "sbercloud_vpc_subnet" "subnet-1" {
vpc_id = sbercloud_vpc.vpc-1.id
name = "subnet-1"
cidr = "10.33.10.0/24"
primary_dns = "100.125.13.59"
secondary_dns = "8.8.8.8"
}
resource "sbercloud_vpc_subnet" "subnet-2" {
vpc_id = sbercloud_vpc.vpc-1.id
name = "subnet-2"
cidr = "10.33.20.0/24"
primary_dns = "100.125.13.59"
secondary_dns = "8.8.8.8"
}
resource "sbercloud_vpc_subnet" "subnet-3" {
vpc_id = sbercloud_vpc.vpc-1.id
name = "subnet-3"
cidr = "10.33.30.0/24"
primary_dns = "100.125.13.59"
secondary_dns = "8.8.8.8"
}
Из этой записи видно, что значения полей vpc_id
, primary_dns
и secondary_dns
повторяются.
С помощью for_each
описание ресурсов можно значительно сократить:
resource "sbercloud_vpc" "vpc-1" {
name = "vpc-1"
cidr = "10.33.0.0/24"
}
locals {
subnets = {
"subnet-1" = { cidr = "10.33.10.0/24" },
"subnet-2" = { cidr = "10.33.20.0/24" },
"subnet-3" = { cidr = "10.33.30.0/24" }
}
}
resource "sbercloud_vpc_subnet" "subnets" {
for_each = local.subnets
name = each.key
cidr = each.value.cidr
vpc_id = sbercloud_vpc.vpc-1.id
primary_dns = "100.125.13.59"
secondary_dns = "8.8.8.8"
}
Подробности об использовании мета-аргумента for_each
см. в документации Terraform.
provider#
По умолчанию Terraform определяет нужный тип провайдера по типу ресурса.
Мета-аргумент provider
позволяет переопределить это поведение, явно указав провайдер, который должен использоваться для управления ресурсами.
Для использования мета-аргумента provider
выполните следующие действия:
Добавьте блок
provider
без поляalias
. В этом блоке опишите настройки провайдера, используемого по умолчанию, например:provider "yandex" { # ... zone = "ru-central1-a" }
Добавьте блок
provider
, содержащий полеalias
. Опишите специфичные настройки провайдера, а в полеalias
укажите псевдоним, который будет использоваться для обращения к нему, например:provider "yandex" { alias = "zone-b" # ... zone = "ru-central1-b" }
Добавьте поле
provider
к описанию ресурса. В значении укажите нужный провайдер в формате<name>.<alias>
, где:<name> – название провайдера;
<alias> – псевдоним.
resource "yandex_compute_instance" "vm-1" { provider = yandex.zone-b # ... }
Подробности об использовании мета-аргумента provider
см. в документации Terraform.
lifecycle#
В секции Ресурс описано стандартное поведение Terraform при применении конфигурации.
Мета-аргумент lifecycle
позволяет тонко настроить этот процесс.
В значении мета-аргумента lifecycle
можно указать значения следующих полей:
create_before_destroy
Тип:
bool
По умолчанию, если Terraform не может обновить ресурс «на лету», происходит следующее:
Существующий ресурс нужного типа удаляется.
Создается новый ресурс, который используется вместо удаленного.
Мета-аргумент
create_before_destroy
позволяет изменить этот порядок. При значенииtrue
новый ресурс будет создан до того, как удален существующий.prevent_destroy
Тип:
bool
При значении
true
этот мета-аргумент блокирует изменения ресурса, для применения которых его необходимо удалить и создать заново. Он особенно полезен, например, для таких ресурсов, как кластеры СУБД, хранилища данных и т. д.ignore_changes
Тип: список атрибутов
Когда Terraform обнаруживает различия между описанием ресурса и его фактическим состоянием в сервисе, он пытается изменить состояние ресурса таким образом, чтобы оно соответствовало описанию. Чтобы Terraform игнорировал изменение отдельных атрибутов ресурса, сделанное в сервисе, следует указать названия атрибутов в значении параметра
ignore_changes
.Специальное значение
all
позволяет Terraform игнорировать любые изменения ресурса.replace_triggered_by
Тип: список ресурсов или ссылок на атрибуты
В значении этого мета-атрибута следует указать список ресурсов или атрибутов, при изменении которых ресурс должен быть пересоздан.
Подробнее об управлении жизненным циклом ресурсов см. в документации Terraform.
Подключение модулей#
Terraform позволяет группировать в модули (modules) ресурсы, используемые вместе. Это позволяет переиспользовать существующий код при описании инфраструктуры в новом проекте.
По умолчанию описание всех ресурсов размещается в одном модуле, называемом корневым (root).
Модуль может принимать входящие параметры и возвращать какие-либо значения. Таким образом, модуль может быть настроен для использования в проекте в соответствии с необходимыми требованиями.