
В предыдущей статье мы рассмотрели основы языка HCL, используемого Terraform для описания требуемых конфигураций. Также мы подготовили небольшое описание для создания экземпляра EC2 в AWS. Однако, в представленном описании у на присутствуют только основные параметры, необходимые для создания узла, но отсутствуют, к примеру параметры для настройки сети.
Для полноценной автоматизации нам было бы неплохо прописать все необходимые для работы сетевые интерфейсы. Для этого объявим две переменные net_primary и net_ad для двух сетевых интерфейсов. Если вам не требуется второй интерфейс, net_ad можно не указывать, однако в большинстве случаев для серверов требуется скорее большее количество сетевых портов.
variable "net_primary" {
type = string
default = "subnet-3155417b"
}
variable "net_ad" {
type = string
default = "subnet-3155417a"
}В строковых значениях этих переменных мы указали, к каким сетям будут подключаться сетевые интерфейсы, которым будут присвоены net_primary и net_add. В данном примере указаны дефолтные подсети облака Amazon.
Далее добавим в наш конфигурационный файл ресурсы, описывающие сетевые интерфейсы:
resource "aws_network_interface" "primary" {
subnet_id = var.net_primary
source_dest_check = false
}
resource "aws_network_interface" "ad" {
subnet_id = var.net_ad
source_dest_check = false
} Указанный в примере параметр source-dest-check отвечает за проверку каждого пакета, проходящего через интерфейс. Когда source-dest-check включен, каждый IP-пакет, проходящий через этот интерфейс, должен быть отправлен, либо предназначаться IP-адресу этого интерфейса.
Но в случае, если вам необходимо настроить маршрутизацию либо NAT на экземпляре, нужно отключить source-dest-check для интерфейса данного экземпляра. Также, в случае, если нам необходимо автоматически назначить IP адрес с помощью DHCP, нужно добавить следующую строку:
associate_public_ip_address = true Давайте добавим эти параметры в наш конфигурационный файл:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
provider "aws" {
region = var.region
}
variable "region" {
default = "us-west-1"
description = "AWS Region"
}
variable "ami" {
default = "ami-00831fc7c1e3ddc60"
description = "Amazon Machine Image ID for Ubuntu Server 20.04"
}
variable "type" {
default = "t2.micro"
description = "Size of VM"
}
variable "net_primary" {
type = string
default = "subnet-3155417b"
}
variable "net_ad" {
type = string
default = "subnet-3155417a"
}
resource "aws_instance" "demo" {
ami = var.ami
instance_type = var.type
resource "aws_network_interface" "primary" {
subnet_id = var.net_primary
source_dest_check = false
}
resource "aws_network_interface" "ad" {
subnet_id = var.net_ad
source_dest_check = false
}
tags = {
name = "Demo System"
}
}
output "instance_id" {
instance = aws_instance.demo.id
}Таким образом, мы дополнили настройки нашего экземпляра сетевыми параметрами. Теперь давайте рассмотрим различные функции Terraform, позволяющие обрабатывать числовые и строковые значения. Собственно, наименования этих функций аналогичны используемым в других языках программирования, поэтому тем, кто знаком с любым языком высокого уровня разобраться в этих функциях будет несложно.
Функции Terraform
Основными числовыми функциями, которые могут потребоваться в работе являются min и max, вычисляющие минимальное и максимальное значения из предложенного списка.
max(12, 54, 3)
54При этом, если список значений вложен в другой список, функция также найдет нужное значение
min([12, 54, 3]...)
3Строковые функции более востребованы, так как с их помощью можно генерировать различные наименования, тэги и другие строковые значения, необходимые в дальнейшей работе.
Если мы получаем строковые значения из файла , там могут присутствовать символы окончания строки (\n, \r). Для того, чтобы их корректно удалить, можно воспользоваться функцией chomp
chomp("hello\n")
hello
chomp("hello\r\n")
hello
chomp("hello\n\n")
hello Еще одна функция, предназначенная для удаления лишних символов по краям строк, это trim. Здесь мы сами передаем функции те символы, которые необходимо удалить. Вот несколько примеров
trim("?!hello?!", "!?")
"hello"
trim("foobar", "far")
"oob"
trim(" hello! world.! ", "! ")
"hello! world." У этой функции есть несколько вариаций, так trimprefix и trimsuffix удаляют символы с начала и с конца строки соответственно, а trimspace удаляет все пробелы в терминах Юникода, то есть помимо самих пробелов также табуляцию, перенос строк и другие значения.
Для поиска строк в конфигурациях мы можем воспользоваться регулярными выражениями с помощью функции regex. На просторах Хабра можно найти массу статей, посвященных работе с регулярными выражениями, поэтому здесь мы не будем на этом останавливаться.
Еще несколько практически полезных функций позволяют работать со списками, состоящими из наборов различных значений. Начнем с функции element, которая извлекает отдельный элемент из списка:
element(["a", "b", "c"], 1)
b В этом примере мы получили первый элемент из списка. Напомним, что нумерация в списках Terraform начинается с 0. Но, если мы попросим у этой функции извлечь элемент с индексом, который больше длины списка, функция выполнит “оборот”, то есть присвоит индексу в качестве результата остаток от целочисленного деления (mod).
element(["a", "b", "c"], 3)
aТак что будьте готовы к такому “странному” но абсолютно корректному поведению данной функции.
Еще одна интересная функция Terraform это merge. Эта функция получает на вход произвольное количество объектов в формате ключ-значение, у которых ключи могут быть не уникальны. Например:
{a="b", c="d"}, {e="f", c="z"}Здесь c имеет значения d и z. Функция merge присвоит с значение z, потому-что приоритет имеет тот ключ, который находится позже в последовательности аргументов. Если типы аргументов не совпадают, результирующий тип будет объектом, соответствующим структуре типов атрибутов после применения правил объединения.
Чтобы стало понятнее посмотрим примеры:
merge({a="b", c="d"}, {e="f", c="z"})
{
"a" = "b"
"c" = "z"
"e" = "f"
}Здесь ключу с соответствует значение z, первое присвоение a=”b” в итоге потеряно. Другой пример:
merge({a="b"}, {a=[1,2], c="z"}, {d=3})
{
"a" = [
1,
2,
]
"c" = "z"
"d" = 3
}Здесь мы сначала объединили объекты, в результате чего a был присвоен массив [1,2].
Данная функция может быть полезна в случае, если у нас имеется разнородный набор данных и необходимо привести его к единой структуре.
Рассмотрим пример практического применения данных функций. Ниже приведен блок кода HCL, в котором мы берем номер нашего экземпляра (у нас же развернуто несколько экземпляров EC2, иначе какой смысл во всей автоматизации и IaC
