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

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

Что такое CDK

CDK (Cloud Development Kit, «набор для разработки облака») — это фреймворк, который позволяет описывать облачную инфраструктуру кодом на привычном языке программирования. Вы пишете программу, запускаете её, и на выходе получаете готовые ресурсы в AWS.

Ключевая идея в двух словах: CDK ничего не разворачивает напрямую. Он берёт ваш код, превращает его в обычный CloudFormation-шаблон (это называется «синтез»), а затем отдаёт этот шаблон CloudFormation, который уже создаёт и обновляет ресурсы. То есть собственного движка развёртывания у CDK нет — движок это CloudFormation. CDK — удобная надстройка перед ним.

Зачем это нужно, если можно писать 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-конструкт может развернуть сразу контейнерный сервис вместе с балансировщиком нагрузки, сетью и правами доступа — то, что вручную заняло бы десятки строк.

Правило для новичка простое: по умолчанию берите L2. Они закрывают большинство задач. К L1 спускайтесь только за редкой настройкой, а L3 берите, когда узнаёте в нём ровно свою задачу.

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();

Обратите внимание на три аргумента у каждого конструкта: scope (родитель — где он живёт), id (имя внутри родителя) и свойства. Из пары «родитель + id» CDK строит уникальный путь до каждого ресурса в дереве.

Как CDK превращается в CloudFormation

Здесь полезно увидеть весь путь от кода до работающих ресурсов по шагам. Команды запускаются через CLI-инструмент cdk.

Шаг 0 — cdk bootstrap (один раз на аккаунт и регион). Готовит вспомогательные ресурсы, которые CDK нужны для работы: бакет для артефактов, права доступа. Делается единожды.

cdk bootstrap

Шаг 1 — cdk synth (синтез). Запускает вашу программу и генерирует из неё CloudFormation-шаблон. Это и есть та самая «компиляция» кода в шаблон. Шаблон можно открыть и прочитать глазами — полезно, чтобы понять, что именно создастся.

cdk synth

Шаг 2 — cdk diff (что изменится). Сравнивает то, что описано в коде, с тем, что уже развёрнуто, и показывает разницу: какие ресурсы добавятся, изменятся или удалятся. Привычка смотреть diff перед развёртыванием спасает от случайных правок.

cdk diff

Шаг 3 — cdk deploy (развёртывание). Отдаёт шаблон CloudFormation, и тот создаёт или обновляет ресурсы. Развёртыванием по-прежнему занимается CloudFormation — со всеми его свойствами: откатом при ошибке, отслеживанием состояния, безопасным обновлением.

cdk deploy

Удалить всё созданное стеком можно командой cdk destroy. А связать эти команды в автоматический конвейер — задача отдельная, про неё стоит почитать в принципах CI/CD-конвейеров.

На каких языках пишут

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

  • TypeScript (и JavaScript)
  • Python
  • Java
  • Go
  • C#

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

Примеры в этой статье на 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

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

CDK выбирают там, где инфраструктуры много и она меняется часто, а команда уже живёт в мире кода: те же редакторы, те же отзывы на изменения, тот же репозиторий. Особенно удобно, когда инфраструктура повторяется — несколько одинаковых окружений или десяток однотипных сервисов: цикл и функция убирают копирование, которого в статичном шаблоне не избежать.

Типичные ошибки новичков:

  • Думать, что CDK сам разворачивает ресурсы. Нет — он синтезирует CloudFormation-шаблон, а разворачивает CloudFormation. Все ограничения и поведение наследуются от него.
  • Сразу лезть на уровень L1. Cfn-конструкты многословны и без значений по умолчанию. Начинайте с L2 и спускайтесь ниже только при реальной необходимости.
  • Развёртывать без cdk diff. Без взгляда на разницу легко удалить ресурс, который не собирались трогать.
  • Забывать про cdk bootstrap. Первое развёртывание в новом аккаунте или регионе без него просто не пройдёт.
  • Менять созданные CDK ресурсы руками в консоли. Тогда код и реальность расходятся, и следующий deploy ведёт себя непредсказуемо. Источник правды — код.

Куда двигаться дальше. Полезно понять сам CloudFormation — раз CDK строит шаблоны для него, знание основы убирает магию. Рядом стоит посмотреть на Terraform — другой подход к той же задаче, чтобы понимать, из чего выбирают. Тему состояния и доставки инфраструктуры стоит освоить, когда дойдёте до командной работы: где хранится состояние, как раскатывать изменения безопасно. А чтобы понимать, какими ресурсами вы вообще управляете, держите под рукой основы AWS, сеть и права доступа IAM — без понимания самих сервисов любой инструмент управления ими остаётся набором заклинаний.