Slide 1

Slide 1 text

CDK and Kubernetes: A Match Made in the Cloud K8SUG - Singapore

Slide 2

Slide 2 text

TABLE OF CONTENTS ● Problem Statement ● Introduction to CDK8s ● Introduction to CDK8s+ ● Demo (if time permits) ● CDK8s Advanced ● CDK8s vs …

Slide 3

Slide 3 text

Kubernetes YAML is complex. Helm? Kustomize? How about … - Testing? - Redistribution? - Extensibility and Customization? PROBLEM STATEMENT

Slide 4

Slide 4 text

Kubernetes YAML is complex. Helm? Kustomize? How about … - grafana.com/blog/2020/01/09/introducing-tanka-our-way-of-deploying-to-kubernetes - kcl-lang.io/blog/2023-05-30-vs-helm - learnk8s.io/templating-yaml-with-code (CUE lang) - blog.palark.com/dhall-language-for-kubernetes-manifests - kubevela.io/blog/2020/12/7/kubevela-the-extensible-app-platform-based-on-open-applicatio n-model-and-kubernetes - … PROBLEM STATEMENT

Slide 5

Slide 5 text

Introduction to CDK8s What is CDK8s and why does it exist?

Slide 6

Slide 6 text

Define Kubernetes applications and reusable abstractions using familiar programming languages and rich object-oriented APIs. cdk8s.io WHAT IS CDK8s How? CDK8s apps synth to dist/ folder apply to cluster(s) directly or through gitOps.

Slide 7

Slide 7 text

WHY CDK8s ● Express the abstraction’s API using strong-typed data types ● Express rich interactions with methods and properties ● Create polymorphic programming models through interfaces and base classes

Slide 8

Slide 8 text

WHY CDK8s ● Share them through regular package managers (no special Helm packaging, OCI, … , just use NPM) ● Test them using our familiar testing tools and techniques (just use JestJS / SnapShot Testing, … no need special Helm testing) ● Version them (use conventional commits and versioning with package.json / Auto manage dependency bumping using NPM ecosystem)

Slide 9

Slide 9 text

CDK8s CORE CONCEPTS ● Constructs ● Apps ● Charts ● ApiObjects

Slide 10

Slide 10 text

Basic building blocks which render down into representation for target framework - CDK → constructs render down to CFN definitions - CDKTF → constructs render down to HCL expressions - CDK8s → constructs render down to k8s Manifests (yaml/json) CONSTRUCTS

Slide 11

Slide 11 text

An app is a construct Entry/Root of the Tree of Constructs. Contains one or more Charts APPS Construct Chart App Chart Construct Construct Construct import { App } from "cdk8s"; const app = new App(); // do all the things … app.synth();

Slide 12

Slide 12 text

A Chart is a construct - Container for constructs Synthesizes to a single YAML manifest* Chart level namespace / labels will applied to all contained constructs CHARTS Construct MyChart App Construct import { App } from "cdk8s"; import { SampleChart } from "./SampleChart" ; const app = new App(); // register chart into app new SampleChart(app, "Sample", { portNumber: 9899, cpuAutoScaleThreshold: 60, }); app.synth(); enum YamlOutputType { /** All resources are output into a single YAML file */ FILE_PER_APP = 0, /** Resources are split into separate files by chart */ FILE_PER_CHART = 1, /** Each resource is output to its own file */ FILE_PER_RESOURCE = 2, /** Each chart in its own folder and each resource in its own file */ FOLDER_PER_CHART_FILE_PER_RESOURCE = 3 }

Slide 13

Slide 13 text

An ApiObject is a construct Represents an entry in a Kubernetes manifest (level 0). In most cases, you won’t use ApiObject directly but rather classes generated through cdk8s import and which extend ApiObject. API OBJECTS 5 // generated by cdk8s import { ApiObject, ApiObjectMetadata , GroupVersionKind } from 'cdk8s'; import { Construct } from 'constructs'; /** * DatadogAgent Deployment with Datadog Operator. * * @schema DatadogAgent */ export class DatadogAgent extends ApiObject {

Slide 14

Slide 14 text

CDK8s CORE

Slide 15

Slide 15 text

CDK8s CORE

Slide 16

Slide 16 text

Introduction to CDK8s+ How does it relate to CDK8s?

Slide 17

Slide 17 text

High level abstractions for authoring Kubernetes applications. Built on top of the auto-generated building blocks provided by cdk8s, this library includes a hand crafted construct for each native kubernetes object, exposing richer API’s with reduced complexity. cdk8s.io/docs/latest/plus WHAT IS CDK8s+ How? CDK8s+ is a separate library With a release per Kubernetes Version - "cdk8s-plus-25" - "cdk8s-plus-26" - "cdk8s-plus-27" - ...

Slide 18

Slide 18 text

WHY CDK8s+? - Intent driven APIs for k8s objects (read: AWS Blog) - Higher level abstractions on top of CDK8s L0 constructs

Slide 19

Slide 19 text

- Decoupled from k8s Group / Version / Kind changes - Simplifies k8s upgrades… - What is the new spec format for HPA from k8s version 1.23 onwards? v2beta2 to v2 upgrade? - What changed from ingress v1beta1 to v1 deprecation in 1.22? See: AWS Blog + Containers from the Couch, simplifying k8s upgrades CDK8s+ Benefits 5

Slide 20

Slide 20 text

Demo time 🤞 4

Slide 21

Slide 21 text

- Sample CDK8s app from samples - Deployment + Service + Ingress - Add HPA - Sample CDK8s construct library for Datadog Operator CRDs - Add DataDog Monitor to deployment Demo 5

Slide 22

Slide 22 text

CDK8s Advanced 10 Tips and Tricks

Slide 23

Slide 23 text

- You can leverage all existing helm charts! (and customize the result) - Cdk8s integrates well with CDKTF (and CDK) using Resolvers - Mind shift required! from pure declarative to OOP Abstractions (configurable objects) Tips and Tricks

Slide 24

Slide 24 text

- Runs helm template and imports the yaml into memory - Allows manipulation / interaction with all Helm chart resources CDK8s Helm Support export class MyChart extends Chart { constructor(scope: Construct, id: string) { super(scope, id); new Helm(this, "redis", { chart: "bitnami/redis", values: { sentinel: { enabled: true, }, }, }); } } const redis = new Helm(this, "redis", { chart: "bitnami/redis", values: { sentinel: { enabled: true, }, }, }); const master = redis.apiObjects.find( (o) => o.name === "foo-redis-master" ); master?.metadata.addAnnotation( "my.annotation", "hey-there" );

Slide 25

Slide 25 text

Example usage: Fetch deploy time values from IaC CDK8s Resolvers

Slide 26

Slide 26 text

export interface MyChartProps { // constructor props (just like my helm chart values 🎉) readonly tag: string readonly createServiceAccount?: boolean; readonly secretsARN?: string; readonly reportsBucketMap?: Record; } export class SampleChart extends Chart { constructor(scope: Construct, id: string, props: MyChartProps) { super(scope, id); const deployment = new Deployment(this, "Deployment"); const container = deployment.addContainer({// ... }); if (props.secretsARN) { const sp = new MySecretsProvider(props.secretsARN); // add volume to deploymand and mount volume to container sp.mountSecrets(container, { path: "/mnt/secrets", }); } if (props.reportsBucketMap) { for (const [k, v] of props.reportsBucketMap) { container.env.addVariable( // ... ); } } Tips and Tricks - Mind Shift import { App } from "cdk8s"; import { SampleChart } from "./SampleChart" ; const app = new App(); // register chart into app new SampleChart(app, "Sample", { tag: "f87dfd1", secretsARN: "arn://...", reportsBucketMap: { fooReports: "s3://...", barReports: "s3://...", bazReports: "s3://...", }); app.synth(); PSEUDO CODE

Slide 27

Slide 27 text

Tips and Tricks - Mind Shift export interface MyChartProps { readonly tag: string } export class SampleChart extends Chart { readonly private deployment: kplus.Deployment readonly private container: kplus.Container readonly private sp: MySecretProvider constructor(scope: Construct, id: string, props: MyChartProps) { super(scope, id); this.deployment = new Deployment(this, "Deployment"); this.container = deployment.addContainer({ // container spec }); } public mountSecrets(secretsARN: string) { if(this.sp){ // unmount if already exists? (or throw error?) this.sp.unmountSecrets(container) } this.sp = new MySecretsProvider(props.secretsARN); // add volume to deployment and mount volume to container this.sp.mountSecrets(container, { path: "/mnt/secrets", }); } import { App } from "cdk8s"; import { SampleChart } from "./SampleChart" ; const app = new App(); const chart = new SampleChart(app, "Sample", { tag: "f87dfd1", }); chart.mountSecrets("arn://...") chart.addReportsBucket("fooReports", "arn://...") chart.addReportsBucket("barReports", "arn://...") app.synth(); PSEUDO CODE

Slide 28

Slide 28 text

CDK8s vs … 4

Slide 29

Slide 29 text

CDK8s vs … 5 CDK8s Kustomize Helm Authoring (IDE + Intellisense) Language of choice Established language servers Yaml Yaml + gotemplates Custom helm IDE plugins Testing Established test frameworks i.e. JestJS ?? Niche, custom tooling Distribution Established package managers. I.e. Npmjs / Pypip / Maven / go pkg / NuGet / … Niche, custom http/git Niche, Helm registries / OCI Versioning Expressive version constraints for dependencies Git ref? Semver, but no version constraint support only pinned CRD support Strongly typed interfaces auto generated from OpenAPI Specs Schemaless yaml Schemaless yaml nindented text templates

Slide 30

Slide 30 text

Thank you