Terraform для малого и среднего бизнеса: практический гайд по IaC
Меня зовут Семёнов Евгений Сергеевич, директор АйТи Фреш. 15+ лет я видел, как компании теряют недели на восстановление «упавшей» облачной инфраструктуры или пересобирают стенд тестирования по памяти коллеги в отпуске. Infrastructure as Code решает это одним подходом: вся конфигурация — в Git, применение — командой, ревью — через Pull Request. Terraform (и его форк OpenTofu) в этой парадигме — рабочая лошадка. Расскажу, как внедрить без лишней мифологии.
Зачем IaC малому бизнесу
Есть миф, что Terraform — для гигантов с тысячами серверов. Неправда. Даже для офиса с 5 виртуалками и одним облачным тестовым стендом IaC даёт три главных эффекта: документированность, воспроизводимость, version control. Когда через полгода в проект приходит новый админ — он поднимает полную копию среды за час вместо двух дней «реверс-инжиниринга».
Terraform или OpenTofu
После смены лицензии HashiCorp в 2023 году появился OpenTofu под эгидой Linux Foundation. Синтаксис совместим до версии 1.5. Для нового проекта я советую OpenTofu. Для существующих — продолжать на Terraform, пока не упрётесь в лицензионные ограничения.
Структура проекта
infrastructure/
├── modules/
│ ├── network/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── compute/
├── envs/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── backend.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ └── prod/
└── README.md
Удалённый state в S3
Никогда не коммитьте terraform.tfstate в Git. Это антипаттерн с точки зрения безопасности (там могут быть пароли) и неудобен для команды.
# envs/prod/backend.tf
terraform {
required_version = ">= 1.5"
backend "s3" {
bucket = "itfresh-tfstate"
key = "prod/terraform.tfstate"
region = "ru-central1"
endpoint = "https://storage.yandexcloud.net"
skip_credentials_validation = true
skip_region_validation = true
dynamodb_table = "tf-lock"
encrypt = true
}
}
Пример: инфраструктура в Yandex Cloud
# envs/prod/main.tf
terraform {
required_providers {
yandex = { source = "yandex-cloud/yandex", version = "0.104.0" }
}
}
provider "yandex" {
token = var.yc_token
cloud_id = var.cloud_id
folder_id = var.folder_id
zone = "ru-central1-a"
}
module "network" {
source = "../../modules/network"
name = "prod-net"
cidr = "10.10.0.0/16"
}
module "web" {
source = "../../modules/compute"
name_prefix = "web"
count = 3
subnet_id = module.network.public_subnet_id
image = "ubuntu-2204-lts"
platform = "standard-v3"
cpu = 2
ram = 4
disk_size = 40
user_data = file("cloud-init.yaml")
}
Модуль compute
# modules/compute/main.tf
variable "count" { type = number }
variable "name_prefix" { type = string }
variable "subnet_id" { type = string }
variable "image" { type = string }
variable "platform" { type = string }
variable "cpu" { type = number }
variable "ram" { type = number }
variable "disk_size" { type = number }
variable "user_data" { type = string }
data "yandex_compute_image" "os" {
family = var.image
}
resource "yandex_compute_instance" "vm" {
count = var.count
name = "${var.name_prefix}-${count.index + 1}"
platform_id = var.platform
resources {
cores = var.cpu
memory = var.ram
}
boot_disk {
initialize_params {
image_id = data.yandex_compute_image.os.id
size = var.disk_size
type = "network-ssd"
}
}
network_interface {
subnet_id = var.subnet_id
nat = true
}
metadata = { user-data = var.user_data }
}
output "ips" {
value = yandex_compute_instance.vm[*].network_interface[0].nat_ip_address
}
Workspaces для окружений
Workspaces удобны, когда один код-база обслуживает dev/stage/prod. Переключение — terraform workspace select prod.
terraform workspace new dev
terraform workspace new prod
terraform workspace list
terraform workspace show
Импорт существующих ресурсов
Реальный мир — это когда у вас уже есть 30 ВМ, созданных руками. Terraform import аккуратно затягивает их в state.
# Современный способ с import блоком (1.5+)
import {
to = yandex_compute_instance.legacy["web-1"]
id = "ef3abc123..."
}
resource "yandex_compute_instance" "legacy" {
for_each = toset(["web-1","web-2","db-1"])
# ... заполняется после terraform plan -generate-config-out=legacy.tf
}
terraform plan -generate-config-out=legacy.tf
CI/CD с GitLab
# .gitlab-ci.yml
stages: [validate, plan, apply]
image: hashicorp/terraform:1.7
variables:
TF_ROOT: envs/prod
before_script:
- cd $TF_ROOT
- terraform init
validate:
stage: validate
script: terraform validate && terraform fmt -check
plan:
stage: plan
script: terraform plan -out tfplan
artifacts:
paths: [envs/prod/tfplan]
apply:
stage: apply
script: terraform apply tfplan
when: manual
only: [main]
Мини-кейс: миграция клиента в облако
Зимой 2025 года к нам пришёл клиент — дистрибьютор промышленного оборудования, офис 70 РМ. Задача: перенести 14 ВМ с физического Dell Xeon Platinum 8280 (дата-центр МТС, 40G Mellanox) в Yandex Cloud для резервирования. Ручная копия клонов заняла бы неделю. За 3 рабочих дня мы написали Terraform-модули: network (VPC+4 подсети+security groups), compute (виртуалки с cloud-init), dns (PTR и A-записи), backup-policy. Первая среда (staging) развернулась за 14 минут с нуля, вторая (prod) — за 11. Rollback-скрипт документирован: `terraform destroy`. Стоимость миграции 220 000 руб., экономия 5 рабочих дней каждый раз, когда нужно поднять тестовую копию.
Безопасность state и secrets
- Шифрование в S3 (SSE-KMS или server-side).
- Блокировка через DynamoDB или consul для одновременных apply.
- Secrets — только через
sensitive = trueв variables. - Vault или Bitwarden для токенов, никаких terraform.tfvars в Git.
- Отдельные IAM-роли для CI/CD и для dev-админов.
Типичные ошибки
- terraform apply без plan. Всегда сначала план, ревью, потом apply.
- Монолитный main.tf на 2000 строк. Разносите по модулям и env.
- Хардкод ID. Используйте data-блоки для lookup.
- count вместо for_each. count привязан к индексу — удаление среднего пересоздаёт всё за ним.
- Нет pre-commit хуков. terraform fmt, terraform validate, tflint, checkov — обязательно.
Внедрим Terraform в вашу инфраструктуру
Проектирование модулей, миграция существующего парка, CI/CD, ревью процесса. От 120 000 руб. за первую площадку и 3 окружения.
Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш
FAQ — частые вопросы о Terraform
- Зачем малому офису Terraform?
- Воспроизводимость инфраструктуры, версионирование изменений в Git и ревью через Pull Request.
- Где хранить state-файл?
- Только в удалённом backend: S3, Yandex Object Storage, GitLab HTTP backend или Terraform Cloud.
- Что такое модуль?
- Переиспользуемый набор ресурсов с входными и выходными параметрами.
- Можно ли импортировать существующую инфраструктуру?
- Да, команда terraform import или блок import для массового импорта.
- OpenTofu вместо Terraform?
- Форк после смены лицензии HashiCorp, совместим до версии 1.5. Для новых проектов подходит.