Представь команду из пяти человек. Каждый пишет код у себя на ноутбуке и заливает результат на боевой сервер через scp, когда ему кажется, что "вроде работает". Звучит как сюжет фильма ужасов для админа, и так оно и есть. Кто-то перетёр чужие правки, тесты никто не гонял, а на проде вдруг падает то, что вчера работало. Откатиться некуда, потому что версий нет, есть только "та папка, которую Петя случайно не удалил".
Конвейер развёртывания (он же CI/CD pipeline) - это лекарство от этого хаоса. Он превращает выкладку кода из стресса в скучную предсказуемую процедуру. А скучно в проде - это лучший комплимент. Этот урок концептуальный: мы разбираем, как устроен путь прикладного кода от коммита до прода, потому что инфраструктурный конвейер на Terraform (которым мы займёмся дальше) строится по тем же законам. Понимаешь логику деплоя приложения - понимаешь, как Terraform встраивается в эту картину. Заодно увидим, где инфраструктура как код смыкается с прикладным CI/CD: образы, реестр, стратегии выкатки.

Анатомия конвейера: от коммита до прода
Разберём по шагам типичный путь изменения. Не как догму, а как скелет, который каждая команда обвешивает своими деталями.
- Система контроля версий. Всё начинается с git. Код живёт в репозитории, история изменений сохраняется, ветки позволяют работать параллельно. Если git у тебя ещё не на автомате - это база, без неё дальше говорить не о чем.
- Локальный прогон. Перед тем как показывать код кому-то, ты гоняешь его у себя: запускаешь линтер, прогоняешь юнит-тесты, проверяешь, что приложение вообще стартует. Это дешёвый способ не позориться в ревью опечаткой.
- Внесение изменений и ветка. Создаёшь feature-ветку, делаешь коммиты маленькими и осмысленными. Один коммит - одна мысль, а не "fix всё сразу плюс пара рефакторингов до кучи".
- Ревью (pull request). Открываешь PR, коллеги читают diff. Это не только про отлов багов, но и про распространение знаний: кто-то ещё в команде теперь в курсе, что ты натворил.
- Автотесты в CI. При открытии PR автоматически запускается сборка: линт, юнит-тесты, иногда интеграционные. Если красное - мержить нельзя. Робот тут безжалостнее любого ревьюера, и это хорошо.
- Слияние. Зелёный PR с апрувом мержится в основную ветку (main/master). С этого момента изменение считается частью продукта.
- Выпуск версии (release). На основной ветке собирается артефакт: для приложения это чаще всего Docker-образ с тегом версии. Образ кладётся в реестр (registry) - хранилище образов, откуда его потом возьмёт прод.
- Развёртывание (deploy). Готовый образ выкатывается на окружение: сначала, как правило, на staging, потом на production. И вот тут начинается самое интересное - как именно выкатывать.
Допустим, у тебя версия v1 крутится на проде и обслуживает пользователей. Ты собрал v2. Как подменить одно на другое, не уронив сервис? Есть три классических подхода.
Rolling update (постепенное обновление). У тебя несколько одинаковых инстансов за балансировщиком. Ты гасишь их по одному (или маленькими пачками), поднимаешь на новой версии, ждёшь, пока пройдут health-check, и идёшь дальше. В любой момент часть трафика идёт на старую версию, часть на новую. Плюс: не нужно держать двойной парк машин. Минус: какое-то время в проде живут обе версии сразу - база данных и API должны это переживать.
Blue-green. Поднимаешь полностью новый набор машин (green) рядом со старым (blue). Прогоняешь на green smoke-тесты. Когда уверен - переключаешь балансировщик целиком на green одним движением. Если что-то пошло не так, откат мгновенный: вернул трафик на blue. Плюс: чистое переключение, простой откат. Минус: на момент выкатки нужен двойной запас ресурсов, а значит, двойной счёт за облако.
Canary (канарейка). Имя пошло от шахтёров с канарейкой в клетке. Ты выпускаешь новую версию на маленький процент трафика - скажем, 5%. Смотришь метрики: ошибки, задержки, бизнес-показатели. Всё хорошо - наливаешь больше: 25, 50, 100%. Видишь рост ошибок - откатываешь, пострадали только эти 5% пользователей. Плюс: минимальный радиус поражения. Минус: нужен зрелый мониторинг, иначе канарейку ты просто не услышишь.
Где здесь Terraform и инфраструктура
Прикладной код выкатывает CI/CD приложения. Но машины, балансировщики, сети, группы инстансов и сам реестр образов - это инфраструктура, и описывается она кодом через Terraform (или его форк OpenTofu - синтаксис тот же). Именно terraform yandex cloud даёт тебе ту платформу, по которой потом катится приложение.
Покажу минимальный, но осмысленный HCL: реестр образов в Yandex Cloud и группа инстансов с политикой развёртывания. Это та самая точка, где инфра-конвейер обслуживает прикладной.
Код: Выделить всё
terraform {
required_providers {
yandex = {
source = "yandex-cloud/yandex"
}
}
}
provider "yandex" {
zone = "ru-central1-a"
}
# Реестр Container Registry - сюда CI/CD приложения пушит образы
resource "yandex_container_registry" "app" {
name = "app-registry"
folder_id = var.folder_id
}
Код: Выделить всё
resource "yandex_compute_instance_group" "app" {
name = "app-ig"
folder_id = var.folder_id
service_account_id = var.sa_id
instance_template {
platform_id = "standard-v3"
resources {
cores = 2
memory = 2
}
boot_disk {
initialize_params {
image_id = var.app_image_id
size = 20
}
}
network_interface {
subnet_ids = [var.subnet_id]
nat = true
}
}
scale_policy {
fixed_scale {
size = 3
}
}
allocation_policy {
zones = ["ru-central1-a"]
}
# Здесь и живёт стратегия выкатки: меняем по одному, плюс один временный
deploy_policy {
max_unavailable = 1
max_expansion = 1
}
}
Типичные грабли
- Деплой руками "только сегодня и только разок". Этот разок становится привычкой, а конвейер деградирует. Если процесс не в коде - его нет.
- Тесты ради галочки. Зелёный CI, который ничего реально не проверяет, опаснее красного: он усыпляет бдительность.
- Миграции БД врозь с rolling. Если новая версия требует новую колонку, а старая ещё крутится рядом - думай о совместимости вперёд и назад. Сначала аддитивная миграция, потом код, потом чистка.
- Blue-green без оглядки на состояние. Переключил трафик, а сессии и фоновые задачи остались на blue. Stateful-части переключаются не одним движением.
- Canary без метрик. Выкатил 5% и смотришь в потолок. Без мониторинга канарейка - просто медленный полный деплой.
- Образ с тегом latest на проде. Невозможно понять, что именно крутится, и нечем откатиться. Тегируй версии явно.
Руками писать инфру пока не нужно, задача - уложить логику в голове.
- Возьми любой свой пет-проект в git. Нарисуй на бумаге его путь: коммит -> ветка -> PR -> тесты -> мерж -> образ -> деплой. Отметь, какие шаги у тебя уже автоматизированы, а какие ты делаешь руками.
- Для одного из трёх инстансов мысленно прогони rolling-выкатку: какой по очереди гасишь, что проверяешь перед переходом к следующему.
- Прикинь, при каких ошибках на проде ты выберешь canary, а при каких хватит blue-green. Сформулируй критерий выбора одной фразой.
- Найди в HCL выше блок deploy_policy и объясни себе вслух, что произойдёт, если поставить max_unavailable=3 при size=3.
- Чем blue-green отличается от canary по объёму трафика на новой версии и по требованиям к ресурсам?
- Почему при rolling-выкатке нужно следить за совместимостью миграций базы данных?
- Что в Yandex Cloud делает блок deploy_policy у instance_group и как параметры max_unavailable и max_expansion влияют на выкатку?
- Зачем приложению нужен реестр образов (Container Registry) и что плохого в теге latest на проде?
Конвейер прикладного кода - это конвейер: git, локальный прогон, ветка, ревью, автотесты, мерж, сборка образа, деплой. Чем больше шагов автоматизировано, тем спокойнее спится. Стратегий выкатки три: rolling (экономно, но обе версии живут вместе), blue-green (чистое переключение и быстрый откат ценой двойных ресурсов), canary (минимальный радиус поражения, но нужен мониторинг). И главная связка для нас: приложение катится по платформе, а платформу - реестр, группы инстансов, балансировщики, политику деплоя - описывает Terraform. Дальше мы построим уже инфра-конвейер: terraform plan apply, хранение terraform state, модули и ревью прямо на изменения инфраструктуры. Логика та же, просто артефакт другой.