← [Раздел](README.md) · [Главная](../README.md)

# Terraform и Infrastructure as Code

## Цель

Понять **Infrastructure as Code (IaC)** на примере Terraform: провайдеры, ресурсы, state, модули, окружения и как архитектор совместно с платформенной командой описывает сеть, БД и IAM без «кликов в консоли».

## Предварительно

- [CI/CD и GitOps](ci-cd-i-gitops.md)
- Общее представление об облаке: VPC, subnet, security group

## Время

~75 минут

---

## Зачем IaC

| Ручная консоль | IaC (Terraform) |
|----------------|---------------|
| «Кто создал этот SG?» | Git blame |
| Drift между staging и prod | Один модуль, разные tfvars |
| Восстановление после аварии | `terraform apply` |
| Review инфраструктуры | Pull request |

Архитектурные решения о топологии сети и границах сервисов **должны быть в коде**.

---

## Базовая структура

```hcl
terraform {
  required_version = ">= 1.6"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  backend "s3" {
    bucket = "tfstate-example-staging"
    key    = "shop/network/terraform.tfstate"
    region = "eu-central-1"
  }
}

provider "aws" {
  region = var.region
}

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  tags = {
    Name = "shop-staging"
  }
}
```

Имена и CIDR — **учебные**. В проде — согласованная адресация.

---

## Variables и outputs

```hcl
variable "region" {
  type    = string
  default = "eu-central-1"
}

output "vpc_id" {
  value = aws_vpc.main.id
}
```

`terraform.tfvars` для staging:

```hcl
region = "eu-central-1"
```

Prod — отдельный tfvars + отдельный state.

---

## State — критичный артефакт

**State** хранит соответствие «имя в коде → ID в облаке».

| Правило | Почему |
|---------|--------|
| Remote backend (S3 + lock) | Не хранить на ноутбуке |
| Locking (DynamoDB) | Два apply одновременно ломают state |
| Не коммитить state в Git | Секреты, drift |
| Backup state | Disaster recovery IaC |

---

## Модули

```text
modules/postgres/
  main.tf
  variables.tf
  outputs.tf

environments/staging/main.tf  → module "db" { ... }
environments/production/main.tf
```

Модуль инкапсулирует **паттерн** (managed PostgreSQL + subnet group). Окружения отличаются `instance_class`, `multi_az`.

---

## Plan и apply в CI

```bash
terraform fmt -check
terraform validate
terraform plan -out=plan.tfplan
# human or policy review
terraform apply plan.tfplan
```

**Plan** на PR — обязателен. **Apply** — только с main или после approve.

Инструменты policy: **OPA**, **Sentinel**, `terraform plan` + conftest.

---

## Импорт существующей инфраструктуры

`terraform import` — мост от legacy к IaC. Дорого и болезненно; планируйте поэтапно: сеть → БД → k8s.

---

## Связь с Kubernetes

Частый split:

| Terraform | Kubernetes / GitOps |
|-----------|----------------------|
| VPC, RDS, IAM, S3 | Deployment, Service, Ingress |
| EKS/GKE cluster | Workloads внутри |

Кластер — Terraform; приложения — Argo CD. Не смешивайте без причины.

---

## Секреты в Terraform

| Плохо | Хорошо |
|-------|--------|
| `password = "secret"` в .tf | Vault, SSM Parameter Store |
| State с plaintext паролем | Encryption at rest, sensitive outputs |

Используйте `sensitive = true` на outputs.

---

## Типичные ошибки

| Ошибка | Последствие |
|--------|-------------|
| Monolith root module | Невозможно переиспользовать |
| Нет workspace/env split | Prod случайно затронут |
| Ignore lifecycle без ADR | Ручные правки вечны |
| Giant apply без плана | Сюрприз: удалён ресурс |

---

## Альтернативы

Pulumi (языки программирования), CloudFormation (AWS-native), Crossplane (k8s CRD). **Принципы** те же: декларативность, review, state.

---

## Самопроверка

1. Зачем remote state?
2. Чем модуль отличается от root module?
3. Почему `terraform plan` на PR обязателен?
4. Как разделить ответственность Terraform и GitOps?

---

## Дальше

→ [Раздел 11 — Паттерны](../11-patterns/README.md)  
← [CI/CD и GitOps](ci-cd-i-gitops.md)
