Урок 11-15: Продвинутые функции Terraform

Pavel 08.12.2025 18:57 4 просмотров

Часть 1: Динамические блоки (Dynamic Blocks)

Проблема без Dynamic блоков

# Много повторяющегося кода
resource "aws_security_group" "web" {
  name = "web-sg"

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

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

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/8"]
  }
}

Решение с Dynamic блоками

locals {
  ingress_rules = [
    {
      port        = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      port        = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      port        = 22
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      port        = 3306
      protocol    = "tcp"
      cidr_blocks = ["10.0.0.0/8"]
    }
  ]
}

resource "aws_security_group" "web" {
  name = "web-sg"

  dynamic "ingress" {
    for_each = local.ingress_rules
    content {
      from_port   = ingress.value.port
      to_port     = ingress.value.port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}

Часть 2: Lifecycle правила

Основные директивы Lifecycle

Директива Описание
create_before_destroy Создать новый перед удалением старого
prevent_destroy Запретить удаление ресурса
ignore_changes Игнорировать изменения в определенных атрибутах
replace_triggered_by Пересоздать при изменении другого ресурса

create_before_destroy - Zero Downtime

resource "aws_autoscaling_group" "web" {
  name                = "web-asg"
  vpc_zone_identifier = aws_subnet.main[*].id
  min_size            = 2
  max_size            = 5
  desired_capacity    = 3
  launch_template {
    id      = aws_launch_template.web.id
    version = "$Latest"
  }

  lifecycle {
    create_before_destroy = true  # Создать новый ASG перед удалением старого
  }
}

prevent_destroy - Защита критичных ресурсов

resource "aws_db_instance" "main" {
  identifier     = "main-db"
  engine         = "postgres"
  engine_version = "13.0"
  instance_class = "db.t3.small"

  lifecycle {
    prevent_destroy = true  # Запретить удаление
  }
}

# Попытка destroy выведет ошибку:
# Error: Instance cannot be destroyed
# Resource instance aws_db_instance.main has lifecycle.prevent_destroy set

ignore_changes - Игнорировать внешние изменения

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  lifecycle {
    ignore_changes = [
      ami,              # Игнорировать изменения AMI
      instance_type,    # Игнорировать изменения типа инстанса
      tags              # Игнорировать изменения tags
    ]
  }
}

# Или игнорировать все изменения
lifecycle {
  ignore_changes = all
}

Часть 3: Outputs - Выходные значения

Объявление Outputs

Файл: outputs.tf

output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.web.id
}

output "public_ip" {
  description = "Public IP address"
  value       = aws_instance.web.public_ip
}

output "security_group_id" {
  description = "Security Group ID"
  value       = aws_security_group.web.id
}

output "database_endpoint" {
  description = "Database connection string"
  value       = aws_db_instance.main.endpoint
  sensitive   = true  # Скрывать значение в логах
}

output "all_instance_ips" {
  description = "All instance IPs"
  value       = aws_instance.web[*].public_ip  # Массив IPs
}

output "instance_details" {
  description = "Complete instance details"
  value = {
    id        = aws_instance.web.id
    public_ip = aws_instance.web.public_ip
    type      = aws_instance.web.instance_type
  }
}

Использование Outputs

# Просмотр выходов
terraform output

# Конкретный output
terraform output instance_id

# В JSON формате
terraform output -json

# Сохранить в файл
terraform output -json > outputs.json

Часть 4: Зависимости (depends_on)

Явные зависимости

# Зависимость: Internet Gateway должен быть создан перед EIP
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "main-igw"
  }
}

resource "aws_eip" "web" {
  domain = "vpc"

  depends_on = [aws_internet_gateway.main]  # Явная зависимость

  tags = {
    Name = "web-eip"
  }
}

Неявные зависимости (автоматические)

# Terraform автоматически определит зависимость через ссылку
resource "aws_instance" "web" {
  ami                    = "ami-0c55b159cbfafe1f0"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.web.id]  # Автоматическая зависимость

  # Terraform знает, что Security Group должен быть создан перед Instance
}

Сложный пример зависимостей

# 1. VPC
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

# 2. Internet Gateway (зависит от VPC)
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
}

# 3. Subnet (зависит от VPC)
resource "aws_subnet" "main" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
}

# 4. Security Group (зависит от VPC)
resource "aws_security_group" "web" {
  vpc_id = aws_vpc.main.id
  name   = "web-sg"
}

# 5. Instance (зависит от Subnet и Security Group)
resource "aws_instance" "web" {
  ami                    = "ami-0c55b159cbfafe1f0"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.main.id
  vpc_security_group_ids = [aws_security_group.web.id]
}

# 6. EIP (зависит от Instance и Internet Gateway)
resource "aws_eip" "web" {
  instance   = aws_instance.web.id
  domain     = "vpc"
  depends_on = [aws_internet_gateway.main]
}

График зависимостей

terraform graph | dot -Tsvg > graph.svg

# Просмотр зависимостей
terraform graph

Часть 5: Data Sources

Получение данных о существующих ресурсах

# Получить информацию об AMI
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

# Использование в Instance
resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux.id  # Использовать найденный AMI
  instance_type = "t2.micro"

  tags = {
    Name = "web-server"
  }
}

output "ami_id" {
  value = data.aws_ami.amazon_linux.id
}

output "ami_name" {
  value = data.aws_ami.amazon_linux.name
}

Другие полезные Data Sources

# Информация о VPC
data "aws_vpc" "default" {
  default = true
}

# Список подсетей
data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}

# Информация о доступных зонах
data "aws_availability_zones" "available" {
  state = "available"
}

# Использование
resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = "t2.micro"
  subnet_id     = data.aws_subnets.default.ids[0]

  availability_zone = data.aws_availability_zones.available.names[0]
}

Полный пример: Веб-приложение с Advanced функциями

# Получить последний Amazon Linux 2 AMI
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*"]
  }
}

# Launch Template
resource "aws_launch_template" "web" {
  image_id      = data.aws_ami.amazon_linux.id
  instance_type = "t2.micro"

  user_data = base64encode(file("${path.module}/init.sh"))
}

# Auto Scaling Group
resource "aws_autoscaling_group" "web" {
  vpc_zone_identifier = data.aws_subnets.default.ids
  min_size            = 2
  max_size            = 5
  desired_capacity    = 3

  launch_template {
    id      = aws_launch_template.web.id
    version = "$Latest"
  }

  lifecycle {
    create_before_destroy = true
  }

  dynamic "tag" {
    for_each = {
      Name        = "web-server"
      Environment = "production"
    }
    content {
      key                 = tag.key
      value               = tag.value
      propagate_at_launch = true
    }
  }
}

# Outputs
output "asg_name" {
  description = "Auto Scaling Group name"
  value       = aws_autoscaling_group.web.name
}

output "current_size" {
  description = "Current number of instances"
  value       = aws_autoscaling_group.web.desired_capacity
}

Комментарии (0)

Для добавления комментария необходимо войти в аккаунт

Войти / Зарегистрироваться