ОБЛАКА: AWS AWS CDK

Обязательно

AWS CDK: инфраструктура как программа

Constructs · App · Stack

Код на привычном языке синтезирует CloudFormation, конструкты L1, L2 и L3 задают уровень абстракции.

1. Код создаёт ресурсы как объекты

1 / 5

App содержит Stack, конструкты создают bucket, database или function. Язык остаётся привычным.

  • Ресурсы типизированы.
  • Логика повторяется кодом.
  • Тесты проверяют инфраструктуру.
CDK AppStack + constructsОбычный код вместо YAML

2. L1 соответствует CloudFormation ресурсу

2 / 5

Конструкт L1 описывает CfnBucket или другой ресурс почти напрямую. Свойства остаются знакомыми.

  • Минимальная абстракция.
  • Полный контроль свойств.
  • Подходит особым настройкам.
L1 CfnBucketdirect CFN resourceCloudFormationAWS::S3::Bucket

3. L2 и L3 содержат практики по умолчанию

3 / 5

L2 добавляет удобные настройки, L3 объединяет ресурсы в архитектурный паттерн.

  • Безопасные defaults.
  • Меньше повторного кода.
  • Defaults проверяются на соответствие.
L2 constructsecure defaultsL3 patterncomposed architectureАбстракция с проверкой

4. Synth превращает код в шаблон

4 / 5

cdk synth создаёт CloudFormation YAML, diff сравнивает стек, deploy применяет его через CloudFormation.

  • Шаблон можно проверить.
  • Bootstrap готовит окружение.
  • Diff виден до деплоя.
CDK codeSynthDiffDeployCFN template → стек

5. Тесты проверяют инфраструктуру как код

5 / 5

Assertions и snapshot показывают свойства ресурсов до синтеза. Опасные разрешения не попадают в шаблон.

  • Тестируются IAM и ресурсы.
  • Snapshot виден на ревью.
  • Изменения defaults осознаются.
CDK codeAssertions + snapshotSafe templateОшибки ловятся до деплоя

Представьте, что вы описываете нужные вам облачные ресурсы — корзину для файлов, базу данных, функцию — не галочками в консоли и не длинным YAML-файлом, а обычным кодом на том языке, который вы уже знаете. Создали объект «бакет» — получили бакет. Это и есть AWS CDK: способ описывать инфраструктуру как программу.

CDK не заменяет привычные инструменты, а надстраивается над ними. Под капотом всё равно работает CloudFormation — родной для AWS движок развёртывания. CDK лишь даёт вам писать поверх него на нормальном языке вместо ручной верстки шаблонов. Если слова «инфраструктура как код» пока звучат абстрактно, загляните в основы инфраструктуры как кода, а сюда возвращайтесь за конкретикой про CDK.

код на TypeScript конструкты в стеке cdk synth шаблон CloudFormation cdk diff что изменится CloudFormation создаёт ресурсы

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 нет «главного» языка. Он поддерживает несколько языков, и библиотека у них общая:

Это не «обёртки разного качества». Под капотом работает 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 не берут при чужом языке команды, простой статичной инфраструктуре и втором облаке.

Что почитать дальше