Featured image of post Заметки о Terraform

Заметки о Terraform

Рекомендации чистописания из личного опыта

Введение

Terraform - это прекрасный инструмент для автоматизации создания ресурсов в облаках AWS, Azure, GCP, Hetzner и ещё много где. Штука классная. С помощью tfenv можно просто и удобно обновлять сам Terraform локально и выбирать нужную версию. Можно создать файлик в корне проекта и прописать нужную версию, чтобы tfenv автоматически нужную версию Terraform подставлял под проект.
Есть ряд практических рекомендаций которые я вывел для себя читая официальную документацию, которая прям очень хороша, а так же модули и код написанный AWS-ом.

Рекомендации

Проштудируйте официальные рекомендации. От себя я написал далее.

1. Не дублировать тип ресурса в имени

Не правильно

1
2
3
4
5
6
7
resource "aws_vpc" "production_vpc" {
  cidr_block = "172.16.0.0/16"

  tags = {
    Name = "Production VPC"
  }
}

Правильно

1
2
3
4
5
6
7
resource "aws_vpc" "production" {
  cidr_block = "172.16.0.0/16"

  tags = {
    Name = "Production"
  }
}

Пояснения

  1. В коде всё равно обращение к ресурсу будет ${aws_vpc.production.id} - тут и так понятно, что это VPC, нет смысла тратить символы на то, что уже написано
  2. В имени ресурса тоже самое, ведь Вы в любом случае будете смотреть на VPC в списке на странице VPC в AWS Console, там другого-то и не будет. Опять же, зачем тогда дублировать.

2. Использовать this как имя, но только в модулях

Допустим у Вас есть модуль, который создаём виртуалку и минимальный обвес к ней. В пределах модуля виртуалка одна.

1
2
3
4
5
resource "aws_instance" "this" {
  ami           = data.aws_ami.this.id
  instance_type = var.instance_type
...
}

Зачем же придумывать имена для ресурсов, если он в пределах модуля единственный? Незачем. Опять же, нужно понимать, что это имя объекта в пределах кода Terraform. Удобно, когда любой тип ресурса это просто this, но делать так, нужно только в пределах одного модуля, который создаёт логическую единицу, ведь виртуальная машина без своей Security Group, которая открывает к ней порты не имеет смысла, значит логически - это один кусок.

3. Создавать стандартные файлы для модулей

ФайлСодержание
vars.tfВсе переменные
outputs.tfВыходные параметры
versions.tfСекция с требованиями к провайдерам
main.tfФайл с корневым содержимым

4. Не объявлять провайдеры в модулях

Пропишите version constraints, но оставьте инициализацию на усмотрение того, кто будет использовать Ваш модуль.

5. Переменная tags

Добавьте переменную, через которые будут навешиваться теги на абсолютно все ресурсы в модуле.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
variable "tags" {
  type        = map(string)
  description = "Extra tags."
  default     = {}
}

locals {
  default_tags = {
    Custom    = "Some default tags"
    Terraform = "Path to module folder in your Git repo - helps to find code in repo fast"
  } 
  tags = merge(
    local.default_tags,
    var.tags
  )
}

resource "aws_vpc" "production" {
  cidr_block = "172.16.0.0/16"

  tags = merge(
    local.tags,
    {
      Name = "Production"
    }
  )
}

Вот тут в переменную local.tags мы вначале собираем итоговый словарь, а потом его используем где нужно в пределах модуля.

6. Именование ресурсов с name_prefix

Всегда, обязательно используйте префикс имени для создания ресурсов. Поменяв одну эту переменную код должен создать абсолютно такую же инфраструктуру, в том же аккаунте и ничего не должно конфликтовать - это хороший модуль, который может быть использован вновь.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
variable "name_prefix" {
  type        = string
  description = "Name prefix for all resources (required)."
  validation {
    condition = can(regex("^[a-z][a-z0-9-]+[a-z]$", var.name_prefix))
  }
}

resource "tls_private_key" "this" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

resource "aws_key_pair" "this" {
  key_name   = var.name_prefix
  public_key = tls_private_key.this.public_key_openssh
}

И нет смысла дописывать что-то к имени если ресурс один. Допустим этот код того же часть модуля для создания виртуалки, значит он будет использоваться примерно так.

1
2
3
4
5
6
module "ec2_backend" {
  source = "./ec2"

  name_prefix = "production-backend"
  instance_type = "t3a.small"
}

То есть, всё для того же EC2 Key Pair в списке будет понятно, к какой он виртуалке относиться просто по префиксу. Другое дело будь их два, тогда имя в коде было бы "${var.name_prefix}-some-suffix".

7. Никаких дефисов в именах ресурсов

Забудьте напрочь про дефис в имени ресурса. Ломает анализатор кода в IDE и это капец как мешает ещё в некоторых моментах.

Неправильно

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
module "ec2-backend" {
  source = "./ec2"

  name_prefix = "production-backend"
  instance_type = "t3a.small"
}

output "backend-ip" {
  value module.ec2-backend.private-ipv4
}

Правильно

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
module "ec2_backend" {
  source = "./ec2"

  name_prefix = "production-backend"
  instance_type = "t3a.small"
}

output "backend_ip" {
  value module.ec2_backend.private_ipv4
}

Обращу внимание, что для имени самого ресурса в облаке, рекомендую по максимуму использовать именно дефис - красивее, но в Terraform - никогда.

Licensed under Apache License, Version 2.0
Обновлено Mar 21, 2022 14:43 +0200
All rights reserved
Создано при помощи Hugo
Тема Stack, дизайн Jimmy