rubric/modules/devopsmodules/devops_terraform.go
2026-07-27 16:45:21 +03:00

346 lines
13 KiB
Go
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package devopsmodules
import (
"rubric/utils"
)
var TerraformModule = Module{
Key: "terraform",
Aliases: []string{"tf", "iac", "infra", "opentofu", "tofu"},
Title: "Terraform / OpenTofu — инфраструктура как код",
Description: "HCL, провайдеры, ресурсы, state, модули, workspace, форк OpenTofu",
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("OpenTofu — форк Terraform")
utils.Code(`OpenTofu — открытый форк Terraform, созданный в 2023 году после того,
как HashiCorp сменил лицензию Terraform с MPL 2.0 на BSL 1.1 (Business Source License).
Форк собран из последней MPL-версии Terraform (1.5.x) и живёт под управлением
Linux Foundation — то есть под вендор-нейтральным, многосторонним управлением,
а не под контролем одной компании.
# Установка:
curl --proto '=https' --tlsv1.2 -fsSL \
https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
chmod +x install-opentofu.sh
./install-opentofu.sh --install-method standalone
tofu version
# Совместимость: тот же HCL, тот же формат state, те же провайдеры —
# миграция практически всегда сводится к замене бинаря:
alias terraform=tofu`)
utils.Section("Почему в 2026 лучше выбрать OpenTofu")
utils.Code(`1. Лицензия
OpenTofu — MPL 2.0, одобрена OSI, без коммерческих ограничений.
Terraform (с версии 1.6) — BSL 1.1, не одобрена OSI. BSL не мешает
обычному использованию "terraform apply" для своей инфраструктуры,
но запрещает предлагать Terraform как конкурирующий управляемый сервис —
это касается вендоров SaaS/managed-платформ, не рядовых инженеров.
2. Управление (governance)
OpenTofu развивается комитетом под эгидой Linux Foundation —
роадмап не завязан на коммерческие приоритеты одной компании.
Terraform принадлежит HashiCorp (с 2025 года — в составе IBM).
3. Функции, которых нет в открытом Terraform CLI:
- нативное шифрование state и plan-файлов (KMS/PBKDF2) —
важно, если бэкенду state нельзя полностью доверять
- provider for_each — итерация по нескольким конфигурациям одного провайдера
- раннее вычисление переменных, в т.ч. в конфигурации backend
- флаг -exclude (точечное исключение ресурсов из plan/apply)
- собственный открытый реестр провайдеров/модулей registry.opentofu.org
4. Открытость без риска vendor lock-in
Если однажды понадобится вернуться на Terraform — это тоже
практически замена бинаря, конфигурация и state совместимы.
Что осталось только в Terraform:
Terraform Stacks и часть функций тесно интегрированы с HCP Terraform
(управляемой платформой HashiCorp) — в открытом бинаре их нет.
Итог: для новых проектов в 2026 OpenTofu — выбор по умолчанию с меньшим риском:
идентичный синтаксис, та же экосистема провайдеров, плюс нативное шифрование
state и вендор-нейтральное управление. Если уже есть большая инвестиция в
Terraform/HCP и используются Stacks — есть смысл остаться или мигрировать не спеша.`)
utils.Note("tofu — почти всегда совместимая замена terraform: 'alias terraform=tofu', большинство конфигураций и .tfstate работают без изменений")
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()
}