291 lines
8.6 KiB
Go
291 lines
8.6 KiB
Go
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()
|
||
}
|