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

Идея простая: вместо того чтобы настраивать облако руками, вы описываете желаемую инфраструктуру в текстовых файлах — а специальная программа сама создаёт всё по этому описанию. Эти файлы можно положить в git, показать коллеге на ревью, откатить к прошлой версии. Никакого «а что я там нажимал» — есть код, и код всегда прав.

Что такое инфраструктура как код

Инфраструктура — это всё, на чём работает ваше приложение: виртуальные машины, базы данных, сети, хранилища, правила доступа. Раньше всё это создавали вручную через панель управления или серию команд. Подход IaC переносит это в файлы, которые читаются и человеком, и машиной.

Аналогия: рецепт блюда. Можно готовить «на глаз» и каждый раз получать чуть разный результат, а можно записать точный рецепт — граммы, минуты, температура. По рецепту блюдо повторит и другой человек, и вы через год. Файл инфраструктуры — это и есть такой рецепт для облака.

Что это даёт на практике:

  • Воспроизводимость. Одним и тем же файлом разворачиваете идентичные окружения для разработки, тестов и продакшена.
  • История изменений в git. Видно, кто, когда и зачем добавил базу данных — обычный git log.
  • Ревью. Изменение инфраструктуры проходит через pull request, как любой код.
  • Откат. Что-то сломалось — возвращаетесь к прошлой рабочей версии файла.
  • Никакого «забыл, что нажимал»: источник правды один — файл.

Базовые сведения о самом облаке — в статье основы AWS.

Declarative против imperative

Это главная развилка в мире IaC, и понять её важно с самого начала. Есть два способа описать, чего вы хотите.

Imperative (императивный) — вы описываете КАК, по шагам: «создай сервер, потом подключи к нему диск, потом открой порт 80». Это последовательность команд. Похоже на навигатор, который диктует каждый поворот: «через 200 метров направо».

Declarative (декларативный) — вы описываете ЧТО хотите получить в итоге: «должен существовать сервер с диском и открытым портом 80». А уже инструмент сам решает, какие шаги нужны, чтобы привести реальность к этому состоянию. Это как сказать водителю адрес — а маршрут он построит сам.

Большинство популярных инструментов IaC — декларативные. Terraform и CloudFormation работают именно так. Например, в Terraform на языке HCL вы описываете конечное состояние — хранилище в облаке:

resource "aws_s3_bucket" "example" {
  bucket = "my-unique-bucket-name"

  tags = {
    Name        = "My bucket"
    Environment = "Dev"
  }
}

То же самое в CloudFormation выглядит как YAML-шаблон:

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  ExampleBucket:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: Name
          Value: My bucket

Заметьте: ни там, ни там нет слов «создай», «потом», «если уже есть — пропусти». Вы просто описали, что хранилище должно существовать с такими тегами. Решать, создавать его или менять существующее, будет сам инструмент.

Особняком стоит CDK (Cloud Development Kit). Его пишут как обычную программу — на TypeScript, Python, Java или других языках. Но это не делает его императивным: код CDK не создаёт ресурсы напрямую, а синтезирует declarative-шаблон CloudFormation, который потом и применяется. То есть CDK — это удобная обёртка, дающая привычный язык программирования поверх декларативного движка:

import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';

export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    new s3.Bucket(this, 'MyFirstBucket');
  }
}

Команда cdk synth превратит этот код в шаблон CloudFormation (в человекочитаемом виде его можно посмотреть как YAML), а cdk deploy его применит. Подробный разбор каждого инструмента — в статьях про Terraform, CloudFormation и CDK.

Что такое state

Чтобы декларативный инструмент мог понять, что нужно изменить, ему нужна память. Эта память называется state (состояние) — это «слепок» того, что инструмент знает о реальной инфраструктуре: какие ресурсы он создал, с какими настройками и идентификаторами.

Аналогия: список покупок с галочками. Вы пришли в магазин со списком (это ваш код — чего вы хотите) и отмечаете, что уже лежит в корзине (это state — что уже есть). Сравнив одно с другим, вы точно знаете, что ещё докупить.

Когда вы запускаете terraform plan, Terraform делает ровно это: сравнивает ваш код (желаемое состояние) со state (то, что, по его данным, уже создано) и показывает разницу — что добавит, что изменит, что удалит. Только после terraform apply изменения применяются по-настоящему.

terraform plan
terraform apply

У CloudFormation роль state играет сам стек (stack) на стороне AWS — облако само хранит, какие ресурсы относятся к этому шаблону. У Terraform state — это отдельный файл (terraform.tfstate), который в командной работе хранят не на ноутбуке, а в общем месте, например в объектном хранилище, чтобы у всех была одна версия правды.

Idempotency простыми словами

Страшное слово idempotency (идемпотентность) на деле означает очень понятную вещь: повторный запуск без изменений в коде ничего не ломает и ничего не дублирует.

Аналогия: выключатель света со словами «выключено» вместо «переключить». Сколько раз ни нажми «выключено» — свет останется выключенным. А если бы кнопка была «переключить», каждое нажатие меняло бы состояние, и результат зависел бы от числа нажатий.

Именно так ведут себя декларативные инструменты. Вы описали «нужно одно хранилище». Запустили — хранилище создалось. Запустили ещё раз тот же код, не меняя его — инструмент сравнит код со state, увидит, что всё уже на месте, и ничего не сделает. Не появится второе хранилище, ничего не сломается.

terraform apply
terraform apply

Второй apply на неизменённом коде завершится сообщением вроде «0 added, 0 changed, 0 destroyed». Это и есть идемпотентность в действии — и именно благодаря ей запускать IaC безопасно хоть каждый день: лишнего он не натворит.

Что такое drift

А теперь представьте: кто-то из коллег зашёл в веб-консоль и поменял настройку руками — например, переключил тип сервера. В коде по-прежнему написано одно, а в реальности уже другое. Вот это расхождение и называется drift (дрейф): реальность разошлась с кодом.

Drift опасен тем, что незаметен. Файлы выглядят как раньше, но облако работает иначе. А при следующем apply инструмент может «откатить» ручную правку обратно к тому, что записано в коде, — и сломать то, что коллега чинил вручную.

Поэтому в инструментах есть способ обнаружить дрейф. В Terraform это запуск, который только сверяет реальность со state, ничего не меняя в инфраструктуре:

terraform apply -refresh-only

Terraform сходит в облако, посмотрит фактическое состояние ресурсов и сообщит: «объекты изменились вне Terraform». В CloudFormation для того же есть отдельная команда обнаружения дрейфа:

aws cloudformation detect-stack-drift --stack-name my-stack

Лечение дрейфа простое по идее: либо вернуть реальность к коду (применить шаблон заново), либо внести ручную правку в код, чтобы он отражал новое желаемое состояние. Главное правило, которое экономит нервы: меняем инфраструктуру через код, а не руками в консоли — тогда дрейфу просто неоткуда взяться.

Где это применяется

Infrastructure as Code — это фундамент, на котором стоит почти вся современная эксплуатация облака. Несколько типичных мест, где вы с этим столкнётесь:

  • Автоматический деплой. IaC — естественная часть пайплайнов: код инфраструктуры применяется так же автоматически, как и код приложения. См. принципы пайплайна и стратегии релизов.
  • Одинаковые окружения. Разработка, тесты и продакшен поднимаются из одних файлов — отличаются только параметрами.
  • Kubernetes. Манифесты Kubernetes — это тоже декларативное описание желаемого состояния, та же философия «опиши ЧТО, а не КАК». Начать стоит с основ Kubernetes и деплоя и конфигурации.

Типичные ошибки начинающих, которых легко избежать, если помнить материал выше:

  • Правят инфраструктуру руками «по-быстрому» — и получают drift, который потом всплывает в самый неподходящий момент. Любое изменение — через код.
  • Теряют или не делят state. В команде state должен лежать в общем месте, иначе двое разработчиков случайно затрут изменения друг друга.
  • Боятся повторно запускать apply. Из-за идемпотентности повторный запуск на неизменённом коде безопасен — бояться нечего.
  • Путают imperative и declarative и пытаются писать «по шагам» там, где инструмент ждёт описания конечного состояния.

Что учить дальше: возьмите один инструмент и пройдите его целиком — например, Terraform как самый универсальный, CloudFormation как родной для AWS или CDK, если ближе обычный язык программирования. Затем посмотрите, как state и доставка устроены в командной работе, в статье про state и доставку, и как всё это связывается с автоматическими релизами в разделе про ветвление и релизы.