Представьте, что вы настроили сервер в облаке: накликали мышкой нужные галочки в веб-консоли, создали базу данных, открыли пару портов. Всё работает. А через месяц нужно поднять точно такую же копию для тестов — и вы уже не помните, какие именно галочки нажимали. Знакомо? Именно эту боль решает 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 и доставку, и как всё это связывается с автоматическими релизами в разделе про ветвление и релизы.