package devopsmodules import ( "rubric/utils" ) var TerraformModule = Module{ Key: "terraform", Aliases: []string{"tf", "iac", "infra"}, Title: "Terraform — инфраструктура как код", Description: "HCL, провайдеры, ресурсы, state, модули, workspace", Run: showTerraform, } func showTerraform() { utils.Header("DevOps — Terraform") utils.Section("Основы и установка") utils.Code(`Terraform — декларативный IaC инструмент от HashiCorp. Описываешь желаемое состояние → Terraform приводит инфраструктуру к нему. # Установка: # https://developer.hashicorp.com/terraform/install # Linux (apt): wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor \ -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=...] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \ | sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update && sudo apt install terraform terraform version terraform -install-autocomplete`) utils.Section("Жизненный цикл") utils.Code(`terraform init # скачать провайдеры, инициализировать backend terraform validate # проверить синтаксис terraform fmt # форматировать код terraform plan # показать что изменится terraform apply # применить изменения terraform destroy # удалить всю инфраструктуру terraform plan -out=plan.tfplan # сохранить план terraform apply plan.tfplan # применить сохранённый план terraform apply -auto-approve # без подтверждения (CI/CD) terraform apply -target=aws_instance.web # только конкретный ресурс terraform plan -var="region=eu-west-1" terraform plan -var-file="prod.tfvars"`) utils.Section("Синтаксис HCL") utils.Code(`# main.tf — основная конфигурация: terraform { required_version = ">= 1.7" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } backend "s3" { bucket = "my-tf-state" key = "prod/terraform.tfstate" region = "eu-west-1" encrypt = true } } provider "aws" { region = var.aws_region profile = "myprofile" }`) utils.Code(`# variables.tf — входные переменные: variable "aws_region" { description = "AWS регион" type = string default = "eu-west-1" } variable "instance_count" { type = number default = 2 } variable "allowed_cidrs" { type = list(string) default = ["10.0.0.0/8"] } variable "tags" { type = map(string) default = { Environment = "production" Team = "backend" } } variable "db_password" { type = string sensitive = true # не показывать в логах }`) utils.Code(`# outputs.tf — выходные значения: output "web_ip" { value = aws_instance.web.public_ip description = "Публичный IP веб-сервера" } output "db_endpoint" { value = aws_db_instance.main.endpoint sensitive = true }`) utils.Code(`# Использование переменных: resource "aws_instance" "web" { ami = data.aws_ami.ubuntu.id instance_type = "t3.micro" count = var.instance_count tags = merge(var.tags, { Name = "web-${count.index + 1}" }) } # locals — локальные вычисляемые значения: locals { name_prefix = "${var.project}-${var.environment}" common_tags = { Project = var.project Environment = var.environment ManagedBy = "terraform" } }`) utils.Section("Основные ресурсы (AWS)") utils.Code(`# Data sources — чтение существующих ресурсов: data "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-*-22.04-amd64-server-*"] } } data "aws_vpc" "default" { default = true } # EC2: resource "aws_instance" "web" { ami = data.aws_ami.ubuntu.id instance_type = "t3.micro" subnet_id = aws_subnet.public.id vpc_security_group_ids = [aws_security_group.web.id] key_name = "mykey" user_data = file("scripts/init.sh") root_block_device { volume_size = 20 encrypted = true } lifecycle { create_before_destroy = true ignore_changes = [ami] } tags = local.common_tags } # Security Group: resource "aws_security_group" "web" { name = "${local.name_prefix}-web-sg" vpc_id = aws_vpc.main.id ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } # S3 Bucket: resource "aws_s3_bucket" "assets" { bucket = "${local.name_prefix}-assets" } resource "aws_s3_bucket_versioning" "assets" { bucket = aws_s3_bucket.assets.id versioning_configuration { status = "Enabled" } }`) utils.Section("Модули (Modules)") utils.Code(`# Модуль — переиспользуемая конфигурация # modules/ec2/main.tf, variables.tf, outputs.tf # Использование модуля: module "web_servers" { source = "./modules/ec2" # или из реестра: # source = "terraform-aws-modules/ec2-instance/aws" # version = "~> 5.0" instance_count = 3 instance_type = "t3.small" vpc_id = aws_vpc.main.id subnet_ids = aws_subnet.public[*].id tags = local.common_tags } output "web_ips" { value = module.web_servers.public_ips } # Популярные модули из реестра registry.terraform.io: # terraform-aws-modules/vpc/aws # terraform-aws-modules/eks/aws # terraform-aws-modules/rds/aws`) utils.Section("State и Backend") utils.Code(`# State — файл состояния (terraform.tfstate) # Хранит текущее состояние инфраструктуры. # НЕ коммити в Git! Содержит секреты. # Remote backend — общий state для команды: # S3 + DynamoDB (для lock): backend "s3" { bucket = "my-tf-state" key = "prod/terraform.tfstate" region = "eu-west-1" encrypt = true dynamodb_table = "tf-state-lock" # блокировка } # Команды state: terraform state list # список ресурсов в state terraform state show aws_instance.web # детали ресурса terraform state mv aws_instance.old aws_instance.new # переименовать terraform state rm aws_instance.web # убрать из state (не удалять) terraform import aws_instance.web i-1234567890 # импортировать существующий # Workspace — несколько окружений в одном конфиге: terraform workspace list terraform workspace new staging terraform workspace select production # В коде: terraform.workspace → "staging" / "production"`) utils.Section("Лучшие практики") utils.Code(`Структура проекта: infra/ ├── modules/ # переиспользуемые модули │ ├── vpc/ │ ├── eks/ │ └── rds/ ├── environments/ │ ├── staging/ │ │ ├── main.tf │ │ ├── variables.tf │ │ └── staging.tfvars │ └── production/ │ ├── main.tf │ └── production.tfvars └── .terraform.lock.hcl # версии провайдеров (коммитить!) Правила: - Всегда планируй перед apply: terraform plan - Remote state с блокировкой для командной работы - Раздели state по окружениям и компонентам - Используй .terraform.lock.hcl в git - sensitive = true для секретных переменных - Используй terragrunt для DRY-конфигураций Инструменты: tflint — линтинг Terraform tfsec — статический анализ безопасности checkov — security и compliance checks terragrunt — обёртка для DRY-конфигурации atlantis — автоматизация PR для Terraform`) utils.Footer() }