⚖️ Старый vs Новый: эволюция Terraform

⚡ Ключевые различия

  • Провайдеры: раньше объявлялись отдельно → теперь внутри terraform { required_providers {} }
  • Ручные клики в консоли AWS → Terraform-код в git
  • .terraform.tfvars (нестандартное имя из лекции) → стандартное terraform.tfvars
  • Секреты в .tf файлах → переменные + .gitignore + AWS Secrets Manager
  • Bash-скрипты для создания инфраструктуры → декларативный Terraform

Ручное управление vs Infrastructure as Code

Аспект Ручное управление (устарело) Infrastructure as Code (Terraform)
Создание ресурсов Клики в AWS Console, заполнение форм terraform apply — автоматически
Воспроизводимость Тяжело — нужно помнить каждый шаг Идеальная — terraform apply создаёт идентичное окружение
История изменений Нет или только AWS CloudTrail Git history — кто, когда, что изменил
Code Review Невозможен Pull Request перед изменением prod
Управление несколькими окружениями Каждое окружение — новые клики Одна конфигурация + разные tfvars

Terraform 0.x vs HCL2 (современный Terraform)

Старый способ — объявление провайдера (до Terraform 0.13)

Устаревший паттерн из лекции (не использовать в новых проектах):
# main.tf — СТАРЫЙ СПОСОБ (Terraform < 0.13)
# Провайдер объявляется отдельно без required_providers

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "name-group-bucket"
}
# Нет: required_version, required_providers, source, version

Современный способ — HCL2 (Terraform 0.13+)

Рекомендуемый паттерн (использовать в новых проектах):
# providers.tf — СОВРЕМЕННЫЙ СПОСОБ (Terraform >= 0.13)
terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"     # зафиксировать мажорную версию
    }
  }
}

provider "aws" {
  region = "eu-central-1"
}

Почему важно:

  • required_version — гарантирует, что все члены команды используют совместимую версию Terraform
  • source = "hashicorp/aws" — явно указывает, откуда скачивать провайдер (предотвращает использование сторонних провайдеров с тем же именем)
  • version = "~> 5.0" — защищает от breaking changes при обновлении провайдера
  • .terraform.lock.hcl — фиксирует точные хеши провайдеров

Нестандартное имя файла переменных в лекции

Из лекции: .terraform.tfvars (с точкой)

Нестандартное имя из лекции:
# Как в лекции — нестандартное имя с точкой в начале
# Terraform НЕ загружает этот файл автоматически!
terraform plan -var-file=".terraform.tfvars"
terraform apply -var-file=".terraform.tfvars"

В лекции объяснение: «Файл .terraform.tfvars — не публичный и передаётся дискретно. Не содержит конфиденциальных данных, поэтому помещён в git-репозиторий».

Современный best practice: стандартные имена

Рекомендуется:
# Стандартные имена — Terraform загружает АВТОМАТИЧЕСКИ без -var-file:
terraform.tfvars
*.auto.tfvars   # любой файл с суффиксом .auto.tfvars

# Для нестандартных имён нужен флаг -var-file:
terraform apply -var-file="production.tfvars"
terraform apply -var-file="secrets.tfvars"

Разница по безопасности:

  • Если файл содержит реальные секреты (ключи доступа, пароли) — добавьте в .gitignore
  • Для учебного окружения без секретов — можно коммитить terraform.tfvars
  • В продакшене — используйте переменные окружения TF_VAR_имя или Vault/Secrets Manager

Хардкод значений vs переменные

Старый подход — хардкод в main.tf

# main.tf — ПЛОХО: хардкод всего
provider "aws" {
  region = "us-east-1"   # хардкод региона
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"   # хардкод AMI
  instance_type = "t2.micro"
  key_name      = "my-key"

  # Если нужно изменить тип инстанса — менять в main.tf
  # Если нужно другое окружение — дублировать весь файл
}

Современный подход — переменные и tfvars

# variables.tf
variable "aws_region"    { default = "eu-central-1" }
variable "instance_type" { default = "t2.micro" }
variable "ami_id"        { default = "ami-0de02246788e4a354" }
variable "key_pair_name" { default = "ich" }

# main.tf
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
  key_name      = var.key_pair_name
}

# terraform.tfvars — для dev
instance_type = "t2.micro"

# production.tfvars — для prod
instance_type = "t3.medium"  # переопределяем только нужные параметры

Bash-скрипты vs Terraform для инфраструктуры

Старый императивный подход — Bash

# Терминал — СТАРЫЙ СПОСОБ: создание S3 через скрипты
# Не идемпотентно: повторный запуск = ошибка "bucket already exists"

#!/bin/bash
aws s3api create-bucket \
  --bucket my-dev-bucket \
  --region eu-central-1 \
  --create-bucket-configuration LocationConstraint=eu-central-1

aws s3api put-bucket-tagging \
  --bucket my-dev-bucket \
  --tagging 'TagSet=[{Key=Environment,Value=dev}]'

echo "Bucket created"

Современный декларативный подход — Terraform

# main.tf — TERRAFORM: идемпотентно, безопасно повторять
# Повторный terraform apply — Terraform увидит, что бакет уже создан,
# и ничего не изменит (или применит только разницу)

resource "aws_s3_bucket" "dev_bucket" {
  bucket = "my-dev-bucket"

  tags = {
    Environment = "dev"
  }
}
# terraform apply — создаст бакет если не существует, обновит теги если изменились

Ключевое преимущество Terraform: идемпотентность. Можно запускать terraform apply многократно — будут применяться только фактические изменения. Bash-скрипты при повторном запуске обычно падают с ошибкой.


Хранение state: локальный vs remote

Из лекции — локальный state (для учёбы)

# По умолчанию state хранится локально
# terraform.tfstate — появляется в рабочей директории после apply
# Проблемы при командной работе: у каждого разработчика свой state

Рекомендуется для команд — remote state (S3 + DynamoDB)

# backend.tf — remote state для командной работы
terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "dev/terraform.tfstate"
    region         = "eu-central-1"
    dynamodb_table = "terraform-state-locks"  # блокировка параллельных apply
    encrypt        = true
  }
}
⚠️ Проверить по документации: для использования S3 backend нужно предварительно создать бакет и DynamoDB-таблицу. Terraform Cloud также предоставляет remote state бесплатно для небольших команд. Актуальная документация: S3 Backend Docs.