💻 Примеры: Terraform для AWS

⚡ Минимальная конфигурация S3-бакета

# providers.tf
terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}
provider "aws" { region = "eu-central-1" }

# main.tf
resource "aws_s3_bucket" "bucket" {
  bucket = var.bucket_name
  tags   = { Name = var.bucket_name, Environment = "dev" }
}

# variables.tf
variable "bucket_name" { default = "pd2025-myname-bucket" }
# Терминал — применить
terraform init
terraform plan
terraform apply
aws s3 ls   # проверить создание

Пример 1: S3-бакет (базовый старт)

Первый пример из лекции — создание S3-бакета. Минимальная конфигурация для понимания рабочего цикла Terraform.

Структура файлов

s3-bucket-example/
├── providers.tf      # провайдер AWS
├── main.tf           # ресурс S3
├── variables.tf      # переменные
├── terraform.tfvars  # значения переменных
└── outputs.tf        # имя и ARN бакета

providers.tf — настройка провайдера

# providers.tf
terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
  # Credentials автоматически из ~/.aws/credentials
}

variables.tf — объявление переменных

# variables.tf
variable "aws_region" {
  description = "Регион AWS"
  type        = string
  default     = "eu-central-1"
}

variable "bucket_name" {
  description = "Глобально уникальное имя S3-бакета"
  type        = string
  default     = "pd2025-myname-bucket"
}

variable "environment" {
  description = "Название окружения (dev/staging/prod)"
  type        = string
  default     = "dev"
}

terraform.tfvars — значения переменных

# terraform.tfvars
aws_region   = "eu-central-1"
bucket_name  = "pd2025-myname-bucket"
environment  = "dev"

main.tf — ресурс S3-бакета

# main.tf
resource "aws_s3_bucket" "app_bucket" {
  bucket = var.bucket_name

  tags = {
    Name        = var.bucket_name
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

outputs.tf — вывод информации после apply

# outputs.tf
output "bucket_name" {
  description = "Имя созданного S3-бакета"
  value       = aws_s3_bucket.app_bucket.id
}

output "bucket_arn" {
  description = "ARN S3-бакета"
  value       = aws_s3_bucket.app_bucket.arn
}

output "bucket_region" {
  description = "Регион, в котором создан бакет"
  value       = var.aws_region
}

Последовательность команд

# Терминал (PowerShell или bash)
# Перейти в директорию проекта
cd s3-bucket-example

# Шаг 1: Инициализация — скачать провайдер AWS
terraform init

# Шаг 2: Предпросмотр — убедиться, что создаётся правильное
terraform plan -var-file="terraform.tfvars"

# Шаг 3: Создать S3-бакет (введите "yes" при подтверждении)
terraform apply -var-file="terraform.tfvars"

# Шаг 4: Проверить создание через AWS CLI
aws s3 ls

# Шаг 5: Просмотр outputs
terraform output

# Шаг 6: Удалить ресурсы после завершения работы
terraform destroy -var-file="terraform.tfvars"
# Сохранить вывод: terraform destroy -var-file="terraform.tfvars" | Tee-Object -FilePath destroy-output.txt
⚠️ Проверить по документации: имена S3-бакетов должны быть глобально уникальными среди всех аккаунтов AWS. Если имя уже занято — apply упадёт с ошибкой. Используйте уникальный префикс (ваша группа + имя). Актуальные ограничения: S3 Bucket Naming Rules.

Пример 2: EC2-инстанс с Docker (полная конфигурация)

Развёртывание EC2-инстанса с автоматической установкой Docker через user_data — разбивка по файлам из лекции (раздел «Использование переменных, outputs.tf, providers.tf»).

Структура файлов

ec2-docker-example/
├── providers.tf          # провайдер AWS с required_providers
├── main.tf               # Security Group + EC2 instance
├── variables.tf          # объявление переменных
├── terraform.tfvars      # значения (НЕ секреты)
├── outputs.tf            # публичный IP, ID инстанса, SSH-команда
├── install_ec2_docker.sh # user_data: установка Docker на EC2
└── .gitignore            # исключить .terraform/, *.tfstate

providers.tf

# providers.tf
terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

variables.tf

# variables.tf
variable "aws_region" {
  description = "Регион AWS"
  type        = string
  default     = "eu-central-1"
}

variable "ami_id" {
  description = "ID AMI для EC2 (Amazon Linux 2023, eu-central-1)"
  type        = string
  default     = "ami-0de02246788e4a354"
}

variable "instance_type" {
  description = "Тип EC2-инстанса"
  type        = string
  default     = "t2.micro"
}

variable "key_pair_name" {
  description = "Имя Key Pair для SSH-доступа"
  type        = string
  default     = "ich"
}

variable "volume_size" {
  description = "Размер корневого тома в GB"
  type        = number
  default     = 10
}

variable "sg_name" {
  description = "Имя Security Group"
  type        = string
  default     = "terraform-web-sg"
}

terraform.tfvars

# terraform.tfvars
# Значения для конкретного студента (уникальные имена обязательны!)
aws_region    = "eu-central-1"
instance_type = "t2.micro"
key_pair_name = "ich"
volume_size   = 10
sg_name       = "pd2025-myname-sg"

install_ec2_docker.sh — user_data скрипт

# install_ec2_docker.sh
#!/bin/bash

# Обновляем пакеты
dnf update -y

# Amazon Linux 2023: Docker, плагин Compose v2 и Git одним dnf
dnf install -y docker docker-compose-plugin git

# Запускаем Docker и добавляем в автозапуск
systemctl start docker
systemctl enable docker

# Добавляем пользователя ec2-user в группу docker
usermod -aG docker ec2-user

# Проверяем, что Compose v2 доступен как подкоманда docker
docker compose version

echo "Docker installation complete" >> /var/log/user-data.log

main.tf — Security Group и EC2

# main.tf

# Security Group: разрешить SSH (22) и HTTP (80)
resource "aws_security_group" "web_sg" {
  name        = var.sg_name
  description = "Allow SSH and HTTP"

  # SSH — только ваш IP в продакшене, 0.0.0.0/0 для учёбы
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "SSH access"
  }

  # HTTP
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "HTTP"
  }

  # HTTPS
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "HTTPS"
  }

  # Весь исходящий трафик разрешён
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name      = var.sg_name
    ManagedBy = "Terraform"
  }
}

# EC2-инстанс с установкой Docker через user_data
resource "aws_instance" "web_server" {
  ami                    = var.ami_id
  instance_type          = var.instance_type
  key_name               = var.key_pair_name
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  # Скрипт установки Docker (выполняется при первом запуске)
  user_data = file("install_ec2_docker.sh")

  # Конфигурация корневого тома
  root_block_device {
    volume_size = var.volume_size
    volume_type = "gp3"
  }

  tags = {
    Name      = "WebServer-Docker"
    ManagedBy = "Terraform"
  }
}

outputs.tf

# outputs.tf
output "instance_id" {
  description = "ID EC2-инстанса"
  value       = aws_instance.web_server.id
}

output "instance_public_ip" {
  description = "Публичный IP-адрес EC2-инстанса"
  value       = aws_instance.web_server.public_ip
}

output "security_group_id" {
  description = "ID созданной Security Group"
  value       = aws_security_group.web_sg.id
}

output "ssh_command" {
  description = "Команда для SSH-подключения"
  value       = "ssh -i ~/.ssh/${var.key_pair_name}.pem ec2-user@${aws_instance.web_server.public_ip}"
}

Развёртывание EC2

# Терминал (PowerShell или bash)
cd ec2-docker-example

# Инициализация
terraform init

# Предпросмотр с переменными
terraform plan -var-file="terraform.tfvars"

# Применение (обязательно уникальные имена в tfvars!)
terraform apply -var-file="terraform.tfvars"
# Введите "yes"

# После успешного apply — посмотреть outputs (IP инстанса)
terraform output
# Пример вывода:
# instance_public_ip = "3.73.50.191"
# ssh_command = "ssh -i ~/.ssh/ich.pem ec2-user@3.73.50.191"

# Подключиться по SSH и проверить Docker
ssh -i ~/.ssh/ich.pem ec2-user@3.73.50.191
docker --version
docker ps

# Удалить инфраструктуру после работы
terraform destroy -var-file="terraform.tfvars"
⚠️ Проверить по документации: AMI ID ami-0de02246788e4a354 специфичен для региона eu-central-1 и учебного окружения. В других регионах AMI ID будет другим. Актуальный AMI Amazon Linux 2023 для вашего региона найдите в консоли EC2 → Launch instance → выберите AMI. Вместо хардкода можно использовать data source (пример в Справочнике).

Пример 3: Модуль для создания нескольких инстансов

Пример из лекции — создание трёх EC2-инстансов через модуль и for_each:

# main.tf — использование модуля с for_each

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

locals {
  instances = {
    web1 = {
      name          = "Web Server 1"
      ami           = "ami-0de02246788e4a354"
      instance_type = "t2.micro"
    }
    web2 = {
      name          = "Web Server 2"
      ami           = "ami-0de02246788e4a354"
      instance_type = "t2.micro"
    }
    web3 = {
      name          = "Web Server 3"
      ami           = "ami-0de02246788e4a354"
      instance_type = "t2.micro"
    }
  }
}

module "ec2_instances" {
  source = "./modules/ec2_instance"

  for_each = local.instances

  ami           = each.value.ami
  instance_type = each.value.instance_type
  name          = each.value.name
}
Что происходит: for_each итерирует по мап local.instances. Для каждого ключа (web1, web2, web3) Terraform создаёт отдельный экземпляр модуля. each.value.ami обращается к полям текущего элемента. Чтобы добавить новый сервер — достаточно добавить запись в locals.