Ручное управление 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— гарантирует, что все члены команды используют совместимую версию Terraformsource = "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.