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 за последний месяц

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

К слову, в других репозиториях организации на GitHub доступны некоторые дополнения к основному проекту — например, готовые constructs для конкретных приложений (Redis, Grafana) и библиотеку cdk8s-operator для создания Kubernetes-операторов.

Наконец, важно отметить, что в конце прошлого года cdk8s был принят в «песочницу» CNCF.

P.S.

Читайте также в нашем блоге: