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.
Читайте также в нашем блоге:
Автор: Алексей