Представьте, что вы описываете нужные вам облачные ресурсы — корзину для файлов, базу данных, функцию — не галочками в консоли и не длинным YAML-файлом, а обычным кодом на том языке, который вы уже знаете. Создали объект «бакет» — получили бакет. Это и есть AWS CDK: способ описывать инфраструктуру как программу.
CDK не заменяет привычные инструменты, а надстраивается над ними. Под капотом всё равно работает CloudFormation — родной для AWS движок развёртывания. CDK лишь даёт вам писать поверх него на нормальном языке вместо ручной верстки шаблонов. Если слова «инфраструктура как код» пока звучат абстрактно, загляните в основы инфраструктуры как кода, а сюда возвращайтесь за конкретикой про CDK.
CDK останавливается на шаблоне: движка развёртывания у него нет. Всё, что происходит после diff, делает CloudFormation со своими откатами, пределами и задержками поддержки новых сервисов.
Что такое CDK
CDK (Cloud Development Kit, «набор для разработки облака») — это фреймворк, который позволяет описывать облачную инфраструктуру кодом на привычном языке программирования. Вы пишете программу, запускаете её, и на выходе получаете готовые ресурсы в AWS.
Ключевая идея в двух словах: CDK ничего не разворачивает напрямую. Он берёт ваш код, превращает его в обычный CloudFormation-шаблон (это называется «синтез»), а затем отдаёт этот шаблон CloudFormation, который уже создаёт и обновляет ресурсы.
Зачем это нужно, если можно писать CloudFormation вручную? Потому что код даёт то, чего нет у статичного шаблона:
- циклы и условия — создать десять одинаковых очередей в цикле, а не копировать блок десять раз;
- переменные и функции — вынести повторяющийся кусок в функцию;
- автодополнение и проверку типов в редакторе — опечатку видно сразу, а не при развёртывании;
- готовые библиотеки — целый набор сервисов «из коробки» с разумными настройками.
Главная библиотека называется aws-cdk-lib — это вторая версия CDK (v2), в неё собраны все сервисы AWS в одном пакете. Отдельно идёт пакет constructs — базовый строительный материал, о котором ниже.
Конструкты: L1, L2, L3
Конструкт (construct) — это базовый кирпичик CDK. Любой элемент инфраструктуры, который вы описываете, — это конструкт: бакет, база данных, целая сеть. Конструкты вкладываются друг в друга, и из мелких собираются крупные.
Конструкты делятся на три уровня по степени «удобности». Хорошая аналогия — сборка мебели:
L1 — «отдельные доски и саморезы». Это конструкты с приставкой Cfn в имени (например CfnBucket). Каждый L1 один-к-одному повторяет ресурс CloudFormation: все поля те же, ничего не упрощено, разумных значений по умолчанию нет — вы задаёте всё сами. Это самый низкий уровень, к нему спускаются редко, когда нужного свойства нет на уровнях выше.
new s3.CfnBucket(this, 'RawBucket', {
versioningConfiguration: { status: 'Enabled' },
});
L2 — «готовый шкаф с инструкцией». Это «причёсанные» конструкты с удобными настройками по умолчанию и понятными методами. Тот же бакет на уровне L2 — это просто s3.Bucket: он подставит разумные значения за вас, а лишние детали скроет. Включить версионирование — один параметр.
new s3.Bucket(this, 'AppBucket', {
versioned: true,
});
L3 — «готовая комната под ключ». Это паттерны: композиции из нескольких L2-конструктов, решающие типовую задачу целиком. Один L3-конструкт может развернуть сразу контейнерный сервис вместе с балансировщиком нагрузки, сетью и правами доступа — то, что вручную заняло бы десятки строк. Выглядит это так:
new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'Orders', {
cluster,
cpu: 512,
memoryLimitMiB: 1024,
desiredCount: 2,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('123456789012.dkr.ecr.eu-central-1.amazonaws.com/orders:1.4.2'),
containerPort: 8080,
environment: { SPRING_PROFILES_ACTIVE: 'prod' },
},
publicLoadBalancer: true,
});
Двенадцать строк создают: описание задачи, сервис, балансировщик с правилом маршрутизации, целевую группу с проверкой работоспособности, группы безопасности с нужными правилами, роль задачи, роль исполнения, группу журналов. В шаблоне это превращается примерно в четыреста строк — и это то самое впечатление, ради которого CDK и берут.
Оборотная сторона тоже есть, и знать её надо заранее: вы получаете набор решений, принятых автором конструкта. Что именно создалось, видно только в сгенерированном шаблоне, а поменять отдельную деталь получается через свойства конструкта (их много, но не все) или через запасной люк, о котором ниже. Поэтому L3 хорош, когда задача узнаётся целиком, и мешает, когда требования отличаются в мелочах.
Только не принимайте «разумные значения» за гарантию безопасности. Какие именно умолчания включатся, зависит от версии aws-cdk-lib и от флагов совместимости в файле cdk.json, а список этот со временем меняется. То, что для вас важно — шифрование, запрет публичного доступа, поведение при удалении, — задавайте явно, а не надейтесь, что библиотека угадала.
Правило для новичка простое: по умолчанию берите L2. Они закрывают большинство задач. К L1 спускайтесь только за редкой настройкой, а L3 берите, когда узнаёте в нём ровно свою задачу.
«Спуститься на L1» при этом не значит выбросить L2 и переписать ресурс с нуля. У каждого L2-конструкта под капотом лежит его L1-двойник, и до него можно дотянуться прямо из кода — приём называется escape hatch, «запасной люк»:
const bucket = new s3.Bucket(this, 'AppBucket', { versioned: true });
const cfnBucket = bucket.node.defaultChild as s3.CfnBucket;
cfnBucket.accelerateConfiguration = { accelerationStatus: 'Enabled' };
Вы продолжаете пользоваться удобным L2, а редкое свойство, до которого он не добрался, дописываете на уровне шаблона. Именно это и делает совет «начинайте с L2» выполнимым.
App и Stack
У описания на CDK есть строгая иерархия из трёх уровней вложенности — её удобно держать в голове как «папки».
- App — корень всего, само приложение CDK. Это та точка, с которой запускается синтез. App ничего не разворачивает сам — он лишь контейнер для стеков.
- Stack — стек. Это и есть единица развёртывания: один Stack превращается ровно в один CloudFormation-стек. Внутри одного App может быть несколько Stack — например, отдельно сеть, отдельно база, отдельно приложение.
- Конструкты — кирпичики (L1/L2/L3) лежат внутри Stack.
Получается дерево: App → Stack → конструкты. Свой стек вы описываете как класс, наследующий Stack, а ресурсы создаёте в его конструкторе.
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class AppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new s3.Bucket(this, 'AppBucket', { versioned: true });
}
}
Точка входа — это файл, где создаётся App и в него добавляются стеки:
import * as cdk from 'aws-cdk-lib';
import { AppStack } from './app-stack';
const app = new cdk.App();
new AppStack(app, 'AppStack');
app.synth();
Двух файлов, однако, мало: инструмент cdk должен знать, какую программу ему запускать. За это отвечает файл cdk.json в корне проекта с полем app. Положите два файла рядом без него — и cdk synth ответит --app is required.
{
"app": "npx ts-node --prefer-ts-exts bin/app.ts"
}
Руками его обычно не пишут: проект заводят командой cdk init (о ней ниже), и она раскладывает и точку входа, и cdk.json сама.
Ещё одно свойство стека, про которое легко забыть, — env: в какой аккаунт и регион он поедет.
new AppStack(app, 'AppStack', {
env: { account: '111122223333', region: 'eu-central-1' },
});
Без env стек получается «безразличным к окружению»: шаблон выйдет переносимым, а аккаунт и регион подставятся из настроек профиля AWS в момент развёртывания. Звучит удобно, но за это платят: такой стек не умеет заглядывать в уже существующие ресурсы — ему негде их искать, пока неизвестно, где искать. Как только понадобится найти готовую сеть или свежий образ, env придётся указать явно.
Обратите внимание на три аргумента у каждого конструкта: scope (родитель — где он живёт), id (имя внутри родителя) и свойства. Из пары «родитель + id» CDK строит уникальный путь до каждого ресурса в дереве.
Как CDK превращается в CloudFormation
Здесь полезно увидеть весь путь от кода до работающих ресурсов по шагам. Команды запускаются через CLI-инструмент cdk.
Шаг 0 — cdk bootstrap (один раз на аккаунт и регион). Готовит вспомогательные ресурсы, которые CDK нужны для работы: бакет для артефактов, реестр образов, набор ролей и параметр с версией. И тут есть три вещи, о которых стоит знать заранее, потому что «делается единожды» — не вся правда.
У подготовки есть версия. В параметрах аккаунта сохраняется номер, и новые версии CDK иногда требуют номер выше. Симптом: развёртывание падает с сообщением про несовместимую версию подготовки и просьбой выполнить её заново. То есть bootstrap — это не разовое действие, а редко обновляемая зависимость.
Подготовка создаёт роли с широкими правами. По умолчанию роль развёртывания получает права администратора аккаунта — именно поэтому CDK может создать что угодно. Для боевого аккаунта это часто неприемлемо, и права ограничивают явно:
cdk bootstrap aws://123456789012/eu-central-1 \
--cloudformation-execution-policies arn:aws:iam::aws:policy/PowerUserAccess \
--trust 111111111111
--cloudformation-execution-policies задаёт, что вообще позволено создавать (без этого флага — администратор), а --trust перечисляет аккаунты, которым разрешено развёртывать в этот. Частая ошибка: повторная подготовка без этого флага молча возвращает права администратора — флаг надо указывать каждый раз, поэтому команду держат в скрипте, а не в памяти.
Что именно создаётся и зачем. Бакет — для артефактов: шаблонов, архивов с кодом функций, файлов. Реестр образов — для образов контейнеров, собранных CDK. Роли — для развёртывания, публикации артефактов и поиска значений. Отсюда и ответ на вопрос «зачем CDK бакет»: он лежит в основе следующего раздела.
cdk bootstrap
Шаг 1 — cdk synth (синтез). Запускает вашу программу и генерирует из неё CloudFormation-шаблон. Это и есть та самая «компиляция» кода в шаблон. Шаблон можно открыть и прочитать глазами — полезно, чтобы понять, что именно создастся.
cdk synth
Шаг 2 — cdk diff (что изменится). Сравнивает то, что описано в коде, с тем, что уже развёрнуто, и показывает разницу: какие ресурсы добавятся, изменятся или удалятся. Привычка смотреть diff перед развёртыванием спасает от случайных правок.
cdk diff
Шаг 3 — cdk deploy (развёртывание). Отдаёт шаблон CloudFormation, и тот создаёт или обновляет ресурсы. Развёртыванием по-прежнему занимается CloudFormation — со всеми его свойствами: откатом при ошибке, отслеживанием состояния, безопасным обновлением.
cdk deploy
Снести стек можно командой cdk destroy. И вот тут ждёт ловушка, которая стоит денег: уйдёт не всё, что стек создал. У части L2-конструктов — и s3.Bucket среди них — поведение при удалении по умолчанию «сохранить»: стек исчезнет, а хранилище останется висеть в аккаунте, и счёт за него продолжит приходить. Для боевых данных это правильное умолчание, случайная команда не унесёт базу. Но если ресурс временный и должен умирать вместе со стеком, скажите об этом явно:
new s3.Bucket(this, 'TempBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
А связать эти команды в автоматический конвейер — задача отдельная, про неё стоит почитать в принципах CI/CD-конвейеров.
Тесты: то, чего нет у шаблонов
Главное отличие «инфраструктуры как программы» от YAML — не циклы, а возможность проверить результат тестом. Это тот аргумент, который убеждает программиста, и он же чаще всего остаётся за кадром.
Проверяют не облако, а сгенерированный шаблон: собрали стек в памяти, получили шаблон, сделали утверждения о его содержимом. Быстро (секунды), без доступа в AWS и без денег.
import { App, Stack } from 'aws-cdk-lib';
import { Template, Match } from 'aws-cdk-lib/assertions';
test('у бакета включено шифрование и запрещён публичный доступ', () => {
const stack = new StorageStack(new App(), 'Test');
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::S3::Bucket', {
BucketEncryption: Match.objectLike({
ServerSideEncryptionConfiguration: Match.anyValue(),
}),
PublicAccessBlockConfiguration: {
BlockPublicAcls: true, BlockPublicPolicy: true,
IgnorePublicAcls: true, RestrictPublicBuckets: true,
},
});
});
test('база не удаляется вместе со стеком', () => {
const template = Template.fromStack(new DataStack(new App(), 'Test'));
template.hasResource('AWS::RDS::DBInstance', {
DeletionPolicy: 'Retain',
});
});
test('ровно две функции и ни одной лишней роли', () => {
const template = Template.fromStack(new AppStack(new App(), 'Test'));
template.resourceCountIs('AWS::Lambda::Function', 2);
});
Три вида проверок, которые окупаются больше всего:
Требования безопасности. Шифрование включено, публичный доступ закрыт, журналирование настроено, у ролей нет права «всё со всем». Это то, что на ревью проверяют глазами и пропускают, а тест не пропустит никогда.
Необратимые вещи. У базы и хранилища с данными стоит политика сохранения при удалении стека. Один тест против целого класса аварий.
Снимок шаблона. Есть готовый приём: сохранить весь сгенерированный шаблон как эталон и сравнивать с ним при каждом прогоне (expect(template.toJSON()).toMatchSnapshot()). Тогда любое непреднамеренное изменение — в том числе от обновления библиотеки CDK — становится видно как разница в тесте. Это самый дешёвый способ поймать «библиотека поменяла значения по умолчанию».
Что этими тестами не проверяется: что инфраструктура действительно работает. Шаблон может быть правильным и не развернуться (не хватило квоты, имя занято, нет прав). Для этого есть отдельный вид проверок — развернуть в тестовом аккаунте и прогнать проверки по живым ресурсам; в CDK для этого есть свой механизм (integ-tests), но он дороже и медленнее, поэтому его берут для конструктов, которые отдают другим командам.
Когда CDK не брать
Список причин, по которым от CDK осознанно отказываются.
Команда не пишет на поддерживаемых языках. CDK живёт в TypeScript, Python, Java, C# и Go; если основной язык другой, вы получаете инфраструктуру на языке, который в команде знают двое.
Инфраструктура простая и статичная. Один сервис, база, балансировщик, две среды — тут выигрыш от программы близок к нулю, а цена (сборка, зависимости, обновления библиотеки, подготовка аккаунта) вполне реальна. Простой шаблон или набор слоёв поверх манифестов проще.
Нужна не только AWS. CDK описывает AWS. Инфраструктура в двух облаках или AWS плюс сторонние сервисы (домены, наблюдаемость, репозитории) — это Terraform с его провайдерами, или Pulumi, если хочется именно программы.
Нужен читаемый артефакт для ревью и аудита. Изменение в коде CDK не показывает, что именно изменится в облаке: cdk diff показывает, а запрос на изменение в репозитории — нет. Там, где ревью инфраструктуры делают по тексту изменений (а это частое требование в регулируемых средах), декларативное описание выигрывает: видно ровно то, что поменяется.
Есть риск «программы вместо описания». Инфраструктуру на языке общего назначения легко превратить в приложение: условия, наследование, генерация имён, три уровня абстракций. Через год никто не может ответить, что именно развёрнуто, без запуска синтеза. Это не недостаток инструмента, а его соблазн — и команда, которая не готова держать дисциплину, с декларативным описанием получит более предсказуемый результат.
Обратное тоже стоит сказать: CDK особенно хорош там, где инфраструктуры много и она однотипна (десятки сервисов по одному шаблону, среда на каждую ветку, конструкт-стандарт для всей компании), и там, где бессерверные приложения — из-за сборки и выкладки артефактов одной командой.
Где это применяется
CDK выбирают там, где инфраструктуры много и она меняется часто, а команда уже живёт в мире кода: те же редакторы, те же отзывы на изменения, тот же репозиторий. Особенно удобно, когда инфраструктура повторяется — несколько одинаковых окружений или десяток однотипных сервисов: цикл и функция убирают копирование, которого в статичном шаблоне не избежать.
Типичные ошибки новичков:
- Думать, что CDK сам разворачивает ресурсы. Нет — он синтезирует CloudFormation-шаблон, а разворачивает CloudFormation. Все ограничения и поведение наследуются от него.
- Сразу лезть на уровень L1.
Cfn-конструкты многословны и без значений по умолчанию. Начинайте с L2 и спускайтесь ниже только при реальной необходимости. - Развёртывать без
cdk diff. Без взгляда на разницу легко удалить ресурс, который не собирались трогать. - Забывать про
cdk bootstrap. Первое развёртывание в новом аккаунте или регионе без него просто не пройдёт. - Менять созданные CDK ресурсы руками в консоли. Тогда код и реальность расходятся, и следующий
deployведёт себя непредсказуемо. Источник правды — код.
Глубже: ассеты: код функции и образ контейнера прямо из папкирасширенное
Одна из главных причин брать CDK под бессерверные приложения — то, что он умеет собирать и выкладывать артефакты сам. В шаблоне CloudFormation вы обязаны указать, где лежит архив с кодом функции; CDK берёт папку с кодом и делает всё остальное.
// код лямбды из локальной папки: CDK упакует и выложит
new lambda.Function(this, 'Import', {
runtime: lambda.Runtime.JAVA_21,
handler: 'ru.acme.ImportHandler::handleRequest',
code: lambda.Code.fromAsset('build/libs/import.jar'),
memorySize: 1024,
timeout: Duration.seconds(30),
});
// образ контейнера собирается из Dockerfile и публикуется в реестр
new ecs.FargateTaskDefinition(this, 'Task').addContainer('app', {
image: ecs.ContainerImage.fromAsset('./service'),
});
// статические файлы выкладываются в бакет
new s3deploy.BucketDeployment(this, 'Site', {
sources: [s3deploy.Source.asset('./web/dist')],
destinationBucket: siteBucket,
});
Что происходит при развёртывании: CDK считает контрольную сумму содержимого, выкладывает архив в подготовленный бакет (или собирает и публикует образ в подготовленный реестр) и подставляет в шаблон настоящие адреса. Изменилось содержимое — изменилась сумма, значит артефакт новый и функция обновится; не изменилось — повторная выкладка не нужна. Это и есть ответ на вопрос из предыдущего раздела, зачем подготовка создаёт бакет и реестр.
Сборка на ходу. Для некоторых языков CDK умеет ещё и собирать: NodejsFunction запускает сборщик и упаковывает зависимости, PythonFunction устанавливает пакеты, а для языков со своей системой сборки (Java, Kotlin, .NET) сборка остаётся за ней — CDK берёт уже готовый архив. Часть сборок выполняется внутри контейнера, чтобы результат не зависел от машины разработчика; значит, для развёртывания в этом случае нужен работающий Docker — в том числе в конвейере.
Отсюда практические выводы. Артефакты имеют размер, и подготовленный бакет надо чистить (у него есть правило жизненного цикла, но старые версии копятся). Сборка контейнером замедляет развёртывание и требует Docker на машине. И самое приятное: обновление кода функции — это обычный cdk deploy, без отдельных шагов публикации.
Глубже: контекст и поиск существующего: почему шаблон разный на разных машинахрасширенное
Тонкость, которая удивляет и объясняет часть непонятных различий. CDK умеет читать существующую инфраструктуру во время синтеза:
const vpc = ec2.Vpc.fromLookup(this, 'Vpc', { tags: { Name: 'shared-prod' } });
Такой поиск выполняется не при развёртывании, а при генерации шаблона: CDK обращается к вашему аккаунту, находит сеть и подставляет в шаблон её настоящие идентификаторы. Отсюда два следствия.
Для поиска нужен доступ к аккаунту и указанные явно аккаунт и регион у стека. Без них CDK не знает, где искать, и либо падает, либо подставляет фиктивные значения (vpc-12345), которые не развернутся.
Результат кэшируется в cdk.context.json. Найденные значения записываются в этот файл, и дальше синтез берёт их оттуда, не обращаясь в облако. Файл коммитят в репозиторий — именно это делает сборку повторяемой и не зависящей от прав на чтение аккаунта. И это же объясняет разный шаблон на разных машинах: у одного файл есть, у другого нет, и значения берутся заново.
Когда кэш надо сбросить (сеть пересоздали, добавили подсеть):
cdk context --clear # очистить весь кэш
cdk context # посмотреть, что в нём лежит
Практический вывод. Поиск существующего удобен и добавляет скрытую зависимость от состояния облака. Часто чище передавать идентификаторы параметрами (через свойства стека, из параметров хранилища настроек), а поиск оставлять для того, что действительно стабильно. Если поиск используется, файл контекста обязателен в репозитории, а команда очистки — в инструкции для тех, кто будет разбираться, почему шаблон изменился без правки кода.
Глубже: на каких языках пишутрасширенное
Важный момент, который часто понимают неправильно: у CDK нет «главного» языка. Он поддерживает несколько языков, и библиотека у них общая:
- TypeScript (и JavaScript)
- Python
- Java
- Go
- C#
Это не «обёртки разного качества». Под капотом работает jsii — технология, которая транслирует одну и ту же библиотеку на TypeScript во все перечисленные языки автоматически, поэтому набор конструктов, их свойства и поведение одинаковы везде. Выбирайте тот язык, на котором уже пишет ваша команда, — так инфраструктура живёт рядом с остальным кодом, в одном репозитории и с одними привычками.
Одинаковая библиотека, правда, не означает одинаковую обжитость. Чаще всего CDK пишут на TypeScript и Python: на них больше примеров, статей и готовых конструктов от сообщества. Поддержка Go появилась позже остальных, и подсмотреть чужое решение на нём труднее. Сами конструкты и их поведение от этого не меняются — разница в количестве доступного чужого опыта.
Примеры в этой статье на TypeScript просто потому, что это самый частый выбор для документации и обучения, а не потому, что он «правильный». Тот же бакет на Python выглядит так же по смыслу:
from aws_cdk import Stack, aws_s3 as s3
from constructs import Construct
class AppStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
s3.Bucket(self, "AppBucket", versioned=True)
Создать новый проект на нужном языке помогает команда cdk init с флагом --language (typescript, python, java, go, csharp).
cdk init app --language=python
Глубже: что наследуется от CloudFormationрасширенное
«Все ограничения наследуются» — верно, и вот те, которые реально встречаются.
Пределы стека. У одного стека ограничено число ресурсов (500), выходов, параметров и отображений. Для CDK это чувствительнее, чем для рукописных шаблонов: один L3-конструкт создаёт десятки ресурсов, и упереться в предел можно неожиданно быстро. Лечится разбиением на несколько стеков — а это, в свою очередь, означает передачу значений между ними.
Размер шаблона. Шаблон, загружаемый напрямую, ограничен килобайтами; больший обязан лежать в хранилище объектов — CDK делает это сам через подготовленный бакет, но предел всё равно есть (около 1 МБ), и сгенерированные шаблоны к нему приближаются быстрее рукописных.
Время развёртывания и отсутствие частичного отката. Развёртывание идёт последовательно по зависимостям, и большой стек обновляется минутами. Если что-то упало посередине, CloudFormation откатывает весь стек — нельзя «оставить успешное и повторить неудавшееся». В худшем случае стек застревает в состоянии неудачного отката, и его приходится расшивать вручную, как описано в статье про CloudFormation.
Не все сервисы и свойства. Всё, чего нет в CloudFormation, нет и в CDK — включая новые возможности, которые приезжают с задержкой. Обходится тем же способом: пользовательский ресурс, и в CDK для него есть удобная обёртка (AwsCustomResource), что делает приём заметно дешевле, чем в чистом шаблоне.
Состояние — у CloudFormation. Своего файла состояния у CDK нет, и это плюс: нечего терять и блокировать. Обратная сторона — расхождение между кодом и реальностью решается средствами CloudFormation (проверка расхождений, обновление стека), а не командами инструмента.
Коротко
- CDK описывает инфраструктуру кодом на TypeScript, Python, Java, Go или C#, а разворачивает всё равно CloudFormation: cdk synth даёт шаблон, cdk deploy отдаёт его сервису.
- Конструкты трёх уровней: L1 повторяет ресурс один к одному, L2 даёт разумные умолчания и методы, L3 собирает типовую задачу целиком; по умолчанию берут L2, к L1 спускаются через escape hatch.
- Иерархия App → Stack → конструкты; один Stack это один стек CloudFormation, cdk.json говорит инструменту, что запускать, а env фиксирует аккаунт и регион.
- cdk bootstrap один раз на аккаунт и регион создаёт бакет, реестр и роли; у подготовки есть версия, а роль развёртывания по умолчанию администратор, и для боевого аккаунта её сужают.
- cdk diff смотрят перед каждым deploy; cdk destroy не удалит бакет с данными, потому что у части L2-конструктов политика сохранения по умолчанию.
- Ассеты: код функции и образ контейнера CDK выкладывает сам по контрольной сумме, а для части языков ещё и собирает; бакет артефактов надо чистить.
- Тесты проверяют сгенерированный шаблон за секунды без облака: требования безопасности, необратимые вещи, снимок шаблона; что инфраструктура работает, они не проверяют.
- Поиск существующего идёт при синтезе и кэшируется в cdk.context.json, который коммитят; чаще чище передавать идентификаторы параметрами.
- От CloudFormation наследуются предел в 500 ресурсов на стек, размер шаблона, последовательное развёртывание и задержка новых сервисов; CDK не берут при чужом языке команды, простой статичной инфраструктуре и втором облаке.
Что почитать дальше
- CloudFormation — движок, для которого CDK строит шаблоны.
- Terraform — когда нужна не только AWS или читаемый артефакт для ревью.
- State, секреты и конвейер — как развёртывание встраивают в CI.
- Принципы конвейера доставки — куда положить synth, diff и deploy.