Инфраструктура как код (IaC): когда железо становится программным обеспечением

Представьте, что вы архитектор. Вместо того чтобы вручную класть каждый кирпич, смешивать цемент и прокладывать проводку, вы создаёте цифровую модель здания и включаете громадный 3d принтер Нажимаете кнопку - и через месяц на стройплощадке появляется готовый дом, точно соответствующий чертежам. Инфраструктура как код (Infrastructure as Code, IaC) - это именно такой подход к созданию и управлению IT-инфраструктурой.

Что такое IaC? Короткое определение

Инфраструктура как код - это практика управления и предоставления вычислительной инфраструктуры (серверы, сети, базы данных) с использованием конфигурационных файлов, которые обрабатываются как обычный программный код.

Проще говоря: вы пишете код, который создает инфраструктуру, вместо того чтобы вручную нажимать кнопки в веб-интерфейсе или выполнять команды по ssh.

Эволюция: от ручного управления к IaC

Эпоха ручного управления (до 2010-х)

Системный администратор:
1. Заходит в веб-интерфейс AWS/GCP
2. Вручную создает виртуальную машину
3. Подключается по SSH
4. Устанавливает ПО, настраивает
5. Записывает что сделал в Wiki (или не записывает)

Проблемы: - Неповторимость: Создать точно такую же инфраструктуру невозможно - Дрейф конфигурации: Со временем серверы "уплывают" от исходного состояния - Медленно: Создание продакшена занимает дни или недели - Ошибкоопасно: Человеческий фактор на каждом шагу

Эпоха скриптов (2000-е)

#!/bin/bash
# Скрипт создания сервера (упрощенно)
aws ec2 run-instances --image-id ami-12345 --count 1 --instance-type t2.micro
ssh ubuntu@server "apt-get update && apt-get install nginx"
scp nginx.conf ubuntu@server:/etc/nginx/
ssh ubuntu@server "systemctl restart nginx"

Лучше, но проблемы остаются: - Скрипты линейны и хрупки - Нет идемпотентности (повторный запуск может сломать всё) - Сложно управлять зависимостями

Эра IaC (2010-е — настоящее время)

# Файл Terraform: инфраструктура как код
resource "aws_instance" "web_server" {
  ami           = "ami-12345"
  instance_type = "t2.micro"

  tags = {
    Name = "Web Server"
    Environment = "production"
  }
}

resource "aws_security_group" "web_sg" {
  name = "web-security-group"

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

Преимущества: - Повторимость: тот же код = та же инфраструктура - Версионирование: изменения хранятся в Git - Автоматизация: инфраструктура создается сама - Идемпотентность: повторный запуск не ломает систему

Зачем SRE нужен IaC? Без этого просто невозможно!

1. Устранение рутины (Toil Elimination)

Без IaC: SRE тратит 20% времени на создание/настройку серверов
С IaC: Инфраструктура создается автоматически, SRE тратит время на улучшение кода инфраструктуры

2. Консистентность и соответствие compliance

Пример для банка: требуется, чтобы все продакшен-серверы: - Имели шифрование дисков - Отправляли логи в центральное хранилище - Имели определенные security groups

Без IaC: проверяем каждый сервер вручную, находим расхождения, чиним
С IaC: в коде инфраструктуры эти требования зашиты навсегда. Новые серверы создаются уже соответствующими требованиям.

3. Восстановление после катастроф (Disaster Recovery)

Сценарий: Дата-центр в Москве сгорел.

Без IaC: Паника. Вспоминаем, что было настроено. Пытаемся воссоздать вручную. Занимает дни.
С IaC: Запускаем тот же код Terraform в другом регионе (Питер). Инфраструктура поднимается за часы.

4. Масштабирование и эксперименты

Хотите протестировать новую архитектуру?
Без IaC: Боимся трогать прод. Создаем вручную копию (неполную). Тестируем.
С IaC: Создаем новый environment из кода. Тестируем. Уничтожаем после тестов. Быстро и безопасно.

Принципы IaC для SRE

Принцип 1: Идемпотентность

Сколько бы раз вы ни запускали код, результат должен быть одинаковым.

Пример неидемпотентного кода (плохо):

echo "server_name localhost;" >> /etc/nginx/nginx.conf
# При каждом запуске добавляет строку снова и снова

Пример идемпотентного кода (хорошо, Ansible):

- name: Ensure nginx config is correct
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: restart nginx
# При каждом запуске проверяет и приводит к нужному состоянию

Принцип 2: Декларативность против императивности

Императивный подход (как делать):

# Псевдокод
def setup_server():
    create_vm()
    wait_for_vm_ready()
    install_nginx()
    configure_nginx()
    start_nginx()

Декларативный подход (что хотим получить):

# Terraform
resource "aws_instance" "web" {
  ami = "ubuntu-20.04"
  instance_type = "t2.micro"

  user_data = <<-EOF
              #!/bin/bash
              apt-get update
              apt-get install -y nginx
              systemctl start nginx
              EOF
}

Декларативный подход предпочтительнее: мы описываем желаемое состояние, а система сама понимает, как его достичь.

Принцип 3: Верификация и тестирование

Инфраструктурный код это тоже код. И его нужно тестировать.

Пирамида тестирования IaC:

        ↗ Интеграционные тесты
       ↗ (Test Kitchen, Terratest)
      ↗ Модульные тесты
     ↗ (ChefSpec, pytest-terraform)
    / Синтаксические проверки
   / (terraform validate, yamllint)
  / Статический анализ
 / (tflint, checkov, terrascan)

Пример теста для Terraform:

// Terratest тест
func TestTerraformWebServer(t *testing.T) {
    terraformOptions := &terraform.Options{
        TerraformDir: "../infra",
    }

    defer terraform.Destroy(t, terraformOptions)
    terraform.InitAndApply(t, terraformOptions)

    // Проверяем, что сервер отвечает
    publicIp := terraform.Output(t, terraformOptions, "public_ip")
    url := fmt.Sprintf("http://%s", publicIp)
    http_helper.HttpGetWithRetry(t, url, nil, 200, "Welcome to nginx", 30, 5*time.Second)
}

Основные инструменты IaC

1. Terraform (HashiCorp) — лидер рынка

Для чего: Provisioning (создание) облачной инфраструктуры Язык: HCL (HashiCorp Configuration Language) Принцип: Декларативный

# Создаем VPC, подсети, EC2 инстанс и security group
provider "aws" {
  region = "eu-west-1"
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
}

resource "aws_instance" "app" {
  ami           = "ami-12345"
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.public.id

  tags = {
    Name = "Application Server"
  }
}

Почему SRE любят Terraform: - Поддерживает 100+ провайдеров (AWS, GCP, Azure, Kubernetes, GitHub...) - План применения (terraform plan) показывает что изменится - State management (знает текущее состояние инфраструктуры)

2. Ansible (Red Hat) - конфигурационный менеджер

Для чего: Configuration Management (настройка уже созданных серверов) Язык: YAML Принцип: Императивный (но с идемпотентностью)

- name: Configure web server
  hosts: webservers
  become: yes

  tasks:
  - name: Ensure nginx is installed
    apt:
      name: nginx
      state: present

  - name: Ensure nginx is running
    service:
      name: nginx
      state: started
      enabled: yes

  - name: Deploy website
    copy:
      src: /local/path/index.html
      dest: /var/www/html/

3. Pulumi - инфраструктура на настоящих языках программирования

Для чего: Provisioning на стероидах Язык: TypeScript, Python, Go, .NET Принцип: Декларативный, но с полной мощью языков программирования

// Создаем Kubernetes кластер на TypeScript
import * as k8s from "@pulumi/kubernetes";

// Создаем Namespace
const appNamespace = new k8s.core.v1.Namespace("app-ns", {
    metadata: { name: "application" }
});

// Создаем Deployment
const appDeployment = new k8s.apps.v1.Deployment("app", {
    metadata: { namespace: appNamespace.metadata.name },
    spec: {
        replicas: 3,
        selector: { matchLabels: { app: "webapp" } },
        template: {
            metadata: { labels: { app: "webapp" } },
            spec: {
                containers: [{
                    name: "webapp",
                    image: "nginx:latest",
                    ports: [{ containerPort: 80 }]
                }]
            }
        }
    }
});

Преимущество для SRE: можно использовать циклы, условия, функции, модули, всё как в обычном программировании.

Рабочий процесс SRE с IaC

Стандартный workflow:

1. Разработчик делает изменения в коде приложения
2. SRE обновляет код инфраструктуры (добавляет ресурсы, меняет конфигурацию)
3. Pull Request в Git
4. Автоматические проверки:
   - Синтаксис
   - Политики безопасности
   - План изменений
   - что-то еще
5. Ревью кода инфраструктуры (как и любого другого кода)
6. Мерж → автоматическое применение через CI/CD
7. Мониторинг результата

Пример CI/CD пайплайна для Terraform:

# .gitlab-ci.yml
stages:
  - validate
  - plan
  - apply

terraform-validate:
  stage: validate
  script:
    - terraform init
    - terraform validate

terraform-plan:
  stage: plan
  script:
    - terraform init
    - terraform plan -out=planfile
  artifacts:
    paths:
      - planfile

terraform-apply:
  stage: apply
  script:
    - terraform apply -auto-approve planfile
  only:
    - main  # Автоматически применяем только в main ветке

Проблемы и вызовы IaC

1. State management (особенно в Terraform)

State-файл *.tfstate знает, что у нас развернуто. Если он потеряется или повредится, то Terraform перестанет понимать, что происходит.

Решение: Хранить state в удаленном бэкенде (S3 + DynamoDB для блокировок или Consul, или что-то другое).

terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "production/terraform.tfstate"
    region = "eu-west-1"

    dynamodb_table = "terraform-locks"  # Для блокировок
    encrypt        = true
  }
}

2. Дрейф состояния (State Drift)

Кто-то вручную изменил инфраструктуру в обход IaC. Теперь код и реальность расходятся.

Решение: - Запретить ручные изменения (IAM политики) - Регулярно запускать terraform plan для обнаружения дрейфа - Инструменты типа AWS Config для мониторинга compliance

3. Сложность рефакторинга

Например, переименование ресурса в Terraform - это уничтожение старого ресурса и создание нового (может быть downtime).

Решение: moved блоки (Terraform 1.1+):

moved {
  from = _instance.old_name
  to   = _instance.new_name
}

4. Секреты и чувствительные данные

Код инфраструктуры хранится в Git. Но пароли, ключи API — нет.

Решение: - Использовать менеджеры серетов (например, HashiCorp Vault) - Никогда не хранить секреты в коде

data "aws_secretsmanager_secret" "db_password" {
  name = "production/db/password"
}

resource "aws_db_instance" "database" {
  # ...
  password = data.aws_secretsmanager_secret.db_password.secret_string
}

Продвинутые практики для SRE

1. Модульный подход (Terraform Modules)

Создавайте переиспользуемые модули:

modules/
├── networking/
│   ├── main.tf
│   ├── variables.tf
│   └── outputs.tf
├── compute/
└── database/

environments/
├── production/
│   └── main.tf  # использует модули
└── staging/
    └── main.tf

2. Policy as Code (Open Policy Agent, OPA)

Автоматическая проверка, что инфраструктура соответствует политикам:

# policy.rego - запрещаем создание инстансов без тегов
deny[msg] {
    resource := input.resource_changes[_]
    resource.type == "aws_instance"
    not resource.change.after.tags
    msg := "AWS instances must have tags"
}

3. GitOps для инфраструктуры

Инфраструктура обновляется автоматически при изменении кода в Git (как в Kubernetes с ArgoCD, но для облачной инфраструктуры).

IaC и культура SRE

Смена мышления:

Старое: "Инфраструктура это железо, которое нужно настраивать"
Новое: "Инфраструктура это программный продукт, который нужно разрабатывать"

Новые роли в команде SRE:

  • Infrastructure Developer: пишет и поддерживает код инфраструктуры
  • Platform Engineer: создает внутренние платформы на основе IaC
  • Reliability Architect: проектирует устойчивые системы через код

Почему без IaC сегодня нет SRE

Без IaC мы: - Тратим время на рутину вместо решения реальных проблем - Не можем гарантировать консистентность сред - Боимся вносить изменения - Медленно восстанавливаемся после сбоев - Не соответствуем современным стандартам инженерии

С IaC мы: - Управляем инфраструктурой как программным продуктом - Можем воспроизвести любое окружение за минуты - Вносим изменения безопасно (с review и тестами) - Имеем документацию в виде исполняемого кода - Спим спокойно, зная, что инфраструктура предсказуема

Ключевой показатель для SRE: время от коммита в Git до работающей инфраструктуры. С ручным подходом это дни. С IaC это минуты.

IaC это это не просто "ещё один инструмент". Это фундаментальный переворот в том, как мы думаем об инфраструктуре. Это переход от ремесла к инженерии. И для SRE это не опция, а необъодимость, потому что в мире, где от инфраструктуры зависит доступность сервисов, управлять ею вручную это не просто неэффективно, это очень опасно.