Kubernetes стал стандартом для запуска микросервисных (и не только) приложений. Компании разных размеров — от стартапов до enterprise — стараются проектировать свои приложения готовыми для запуска в Kubernetes-кластере.

А для запуска приложения в K8s обычно используют Helm-шаблоны с описанием манифестов. Хотя формат шаблонов легко читается и прост в изучении, он может вызвать определенные сложности, когда логика деплоя приложения разрастается, когда создаются дополнительные тестовые контуры (с деплоем только отдельных частей приложения) и т.д. При активном использовании Go-шаблонов рефакторинг манифестов может превратиться в нетривиальную задачу*.
Что делать, если у разработчиков нет времени разбираться со всеми тонкостями Helm-шаблонов, синтаксисом YAML и Go templates, но нужно запустить приложение в Kubernetes? Ответом на этот вопрос может стать использование cdk8s.
* Хотя применение Go-шаблонов и позволяет внедрять некоторые продвинутые возможности в таких шаблонах, чтобы этого добиться, придется «выкручиваться» с Helm-шаблонизацией по максимуму. О некоторых таких хитростях мы писали в этой статье.
Что такое cdk8s

cdk8s — это фреймворк с открытым исходным кодом для генерации ресурсов Kubernetes. Название расшифровывается как Cloud Development Kit for Kubernetes.
Основная идея cdk8s заключается в том, что с ним вместо Helm-шаблонов для управления ресурсами и приложениями в Kubernetes можно использовать привычные языки разработки: TypeScript, JavaScript, Python и Java. Недавно также появилась поддержка Go, хотя формальный issue по этому поводу ещё не закрыли. Список этих языков будет расширяться и в дальнейшем — например, можно найти тикеты по Rust или Ruby.
Разработкой и поддержкой проекта занимается AWS, а также более широкое сообщество (на данный момент у GitHub-репозитория около 50 контрибьюторов в кодовую базу и около 2500 звёзд).
При использовании cdk8s для описания Kubernetes-объектов вы получаете все преимущества знакомого вам языка, а также все возможности привычной IDE: подсказки типов, автозаполнение, циклы и итерации, совместно используемые модули и классы… Кроме того, применение тестов поможет избежать ошибок, повысить продуктивность и избавиться от написания огромного количества Helm-шаблонов.
После того, как необходимые для работы приложения ресурсы спроектированы с помощью фреймворка, cdk8s сгенерирует для него Helm-шаблоны, которые легко развернуть в K8s с помощью команды kubectl apply или другой утилиты.
cdk8s работает локально, но все сгенерированные Helm-шаблоны можно применить к любому кластеру Kubernetes.
Компоненты cdk8s
Фреймворк cdk8s состоит из трех основных компонентов:
ядро фреймворка,
библиотека конструкций,
интерфейс командной строки.
Библиотека конструкций (на базе constructs) — набор основных компонентов для создания манифестов для конкретного объекта: Pod, Service, Deployment, ReplicaSet и т.д.
Конструкции позволяют:
создавать API абстракции, используя строго типизированные типы данных;
взаимодействовать с методами и свойствами;
тестировать, используя знакомые инструменты и методы тестирования.
Чтобы воспользоваться библиотекой конструкций, достаточно подключить ее в коде через import { Construct } from 'constructs';.
Интерфейс командной строки позволяет инициализировать шаблон для cdk8s на нужном языке программирования и сгенерировать конечные манифесты.
Пример использования cdk8s на TypeScript
Технически, cdk8s — это набор библиотек, который устанавливается как npm-пакет и является кроссплатформенным. Минимальные т��ебования для работы cdk8s на TypeScript (JavaScript) — установить Node.js и npm.
После этого инсталляция фреймворка выполняется командой:
$ npm install -g cdk8s-cli
Для инициализации проекта cdk8s нужно использовать утилиту командной строки с указанием шаблона языка — например, python-app или javascript-app. Далее будем рассматривать для примера работу с TypeScript:
$ mkdir /app $ cd /app $ cdk8s init typescript-app
В результате выполнения команды у нас в директории будет создана структура проекта:
app@cdk8s:/app# cdk8s init typescript-app Initializing a project from the typescript-app template npm notice created a lockfile as package-lock.json. You should commit this file. + constructs@3.3.75 + cdk8s@1.0.0-beta.18 + cdk8s-plus-17@1.0.0-beta.20 added 11 packages from 10 contributors and audited 11 packages in 2.863s 1 package is looking for funding run `npm fund` for details found 0 vulnerabilities + @types/jest@26.0.23 + jest@27.0.4 + @types/node@15.12.0 + ts-jest@27.0.2 + typescript@4.3.2 added 423 packages from 297 contributors and audited 436 packages in 53.492s 25 packages are looking for funding run `npm fund` for details found 0 vulnerabilities + cdk8s-cli@1.0.0-beta.19 added 131 packages from 106 contributors and audited 567 packages in 10.449s 63 packages are looking for funding run `npm fund` for details found 0 vulnerabilities > app@1.0.0 import /app > cdk8s import k8s > app@1.0.0 compile /app > tsc > app@1.0.0 test /app > jest "-u" PASS ./main.test.ts Placeholder ✓ Empty (8 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 1 passed, 1 total Time: 2.588 s Ran all test suites. > app@1.0.0 synth /app > cdk8s synth dist/app.k8s.yaml ======================================================================================================== Your cdk8s typescript project is ready! cat help Print this message Compile: npm run compile Compile typescript code to javascript (or "yarn watch") npm run watch Watch for changes and compile typescript in the background npm run build Compile + synth Synthesize: npm run synth Synthesize k8s manifests from charts to dist/ (ready for 'kubectl apply -f') Deploy: kubectl apply -f dist/*.k8s.yaml Upgrades: npm run import Import/update k8s apis (you should check-in this directory) npm run upgrade Upgrade cdk8s modules to latest version npm run upgrade:next Upgrade cdk8s modules to latest "@next" version (last commit) ========================================================================================================
Имя сгенерированного YAML-файла (в нашем случае это dist/app.k8s.yaml) зависит от параметров, с которыми производится вызов библиотеки. В этом файле будут содержаться все ресурсы, которые использовались при генерации. При желании можно разделить генерацию манифестов на разные файлы.
Содержимое dist/app.k8s.yaml, созданного на этапе инициализации библиотеки, сейчас будет пустым.
Изучим файл TypeScript-приложения (main.ts) на примере из Getting Started и увидим там базовый шаблон без определения компонентов Kubernetes. Исправим это, добавив два объекта: Deployment и Service. Для этого приведем файл к следующему виду:
import { Construct } from 'constructs'; import { App, Chart, ChartProps } from 'cdk8s'; // imported constructs import { KubeDeployment, KubeService, IntOrString } from './imports/k8s'; export class MyChart extends Chart { constructor(scope: Construct, id: string, props: ChartProps = { }) { super(scope, id, props); const label = { app: 'hello-k8s' }; new KubeService(this, 'service', { spec: { type: 'LoadBalancer', ports: [ { port: 80, targetPort: IntOrString.fromNumber(8080) } ], selector: label } }); new KubeDeployment(this, 'deployment', { spec: { replicas: 2, selector: { matchLabels: label }, template: { metadata: { labels: label }, spec: { containers: [ { name: 'hello-kubernetes', image: 'paulbouwer/hello-kubernetes:1.7', ports: [ { containerPort: 8080 } ] } ] } } } }); } } const app = new App(); new MyChart(app, 'hello'); app.synth();
Мы добавили сервис типа LoadBalancer и Deployment, который будет иметь 2 реплики и предварительно определенный label.
Теперь для генерации манифестов необходимо запустить команду cdk8s synth (от англ. synthesize — «синтезировать»), которая и делает всю «магию»:
$ cdk8s synth dist/hello.k8s.yaml
Файлы с манифестами создаются с именем hello, которое мы передали в качестве параметра для инициализации объекта класса.
Теперь можно посмотреть на содержимое результирующего файла dist/hello.k8s.yaml: в нем будут перечислены все необходимые компоненты для деплоя приложения (с добавленными нами ресурсами) в кластер Kubernetes:
$ cat dist/hello.k8s.yaml apiVersion: v1 kind: Service metadata: name: hello-service-c8c17160 spec: ports: - port: 80 targetPort: 8080 selector: app: hello-k8s type: LoadBalancer --- apiVersion: apps/v1 kind: Deployment metadata: name: hello-deployment-c8c7fda7 spec: replicas: 2 selector: matchLabels: app: hello-k8s template: metadata: labels: app: hello-k8s spec: containers: - image: paulbouwer/hello-kubernetes:1.7 name: hello-kubernetes ports: - containerPort: 8080
Остается только задеплоить эти YAML-файлы в кластер, например с помощью команды kubectl:
$ kubectl apply -f dist/hello.k8s.yaml
Готово!
Больше готовых примеров использования cdk8s на разных языках можно найти в репозитории проекта.
Заключение
cdk8s — очень перспективный фреймворк для генерации манифестов ресурсов Kubernetes. Разработчики могут достаточно быстро освоить основные компоненты фреймворка, необходимые для запуска приложения в кластере.
На текущий момент есть примеры интеграции cdk8s с Flux в случае использования библиотеки для Python или JavaScript, а также интеграция с Argo (для Python).
В настоящий момент проект имеет статус бета-версии и, по всей видимости, приближается к своему первому стабильному релизу. Несмотря на то, что последний формальный релиз на GitHub — v1.0.0-beta.10 — состоялся полгода назад, разработка cdk8s медленно, но верно продвигается, что подтверждается статистикой за последний месяц.

Возможно, авторы просто перестали публиковать публичные бета-релизы, потому что в документации проекта указана другая актуальная версия:

К слову, в других репозиториях организации на GitHub доступны некоторые дополнения к основному проекту — например, готовые constructs для конкретных приложений (Redis, Grafana) и библиотеку cdk8s-operator для создания Kubernetes-операторов.
Наконец, важно отметить, что в конце прошлого года cdk8s был принят в «песочницу» CNCF.
P.S.
Читайте также в нашем блоге:
