the future of Kubernetes application deployments? - revisited

Agenda

  • Who's talking?
  • What's cdk8s?
  • What's new?
  • What's to come?

Who's talking?

  • Max aka brennerm
  • Freelance DevOps Engineer
  • Kubernetes, Cloud Infrastructure
  • coding @ github.com/brennerm
  • writing @ shipit.dev
  • other interests: motorcycles, bikes, sports

What's cdk8s?

CDK8s is a software development framework for defining Kubernetes applications and reusable abstractions using familiar programming languages and rich object-oriented APIs.

Kubernetes manifest evolution

plain YAML → kustomize → Helm → cdk8s

            apiVersion: apps/v1
            kind: Deployment
            metadata:
              name: my-deployment
            spec:
              replicas: 2
              selector:
                matchLabels:
                  app: my-app
              template:
                metadata:
                  labels:
                    app: my-app
                spec:
                  containers:
                    - image: my-app:1.0
                      name: my-app
          

            class MyChart(Chart):
              def __init__(self, scope: Construct, id: str):
                  super().__init__(scope, id)

                  label = {"app": "my-app"}

                  k8s.KubeDeployment(self,
                    'my-deployment',
                    spec=k8s.DeploymentSpec(
                      replicas=2,
                      selector=k8s.LabelSelector(match_labels=label),
                      template=k8s.PodTemplateSpec(
                        metadata=k8s.ObjectMeta(labels=label),
                        spec=k8s.PodSpec(containers=[
                          k8s.Container(
                            name='my-app',
                            image='my-app:1.0'
                          )
                        ])
                      )
                    )
                  )

            app = App()
            MyChart(app, "my-app")
            app.synth()
          

App

  • container for charts
  • entry point for the synthesizing process

Chart

  • container for constructs
  • results in a single Kubernetes manifest
  • can declare namespace and labels for all resources

Construct

  • L1 → autogenerated Kubernetes objects
  • L2 → abstractions on top of L1s

            export class WebService extends Construct {
              constructor(scope: Construct,
                          id: string,
                          options: WebServiceOptions) {
                super(scope, id);
              
                const port = options.port || 80;
                const containerPort = options.containerPort || 8080;
                const label = { app: Names.toLabelValue(this) };
                const replicas = options.replicas ?? 1;
              
                new KubeService(this, 'service', {
                  ...
                });
              
                new KubeDeployment(this, 'deployment', {
                  ...
                });
              }
            }
          

CLI

  • installation: npm install -g cdk8s-cli
  • init - starts a new project
  • import - provides classes for K8s or CRD objects
  • synth - generates K8s manifest from cdk8s code

workflow


            $ cdk8s init python-app
            Initializing a project from the python-app template
            ...
            =========================================================

             Your cdk8s Python project is ready!

               cat help      Prints this message  
               cdk8s synth   Synthesize k8s manifests to dist/
               cdk8s import  Imports k8s API objects to "imports/k8s"

              Deploy:
               kubectl apply -f dist/*.k8s.yaml

            =========================================================
            $ ls
            cdk8s.yaml  dist  help  imports  main.py  Pipfile  Pipfile.lock
            $ vi main.py
            $ cdk8s synth
            dist/my-app.k8s.yaml
            $ kubectl apply -f dist/my-app.k8s.yaml
            $ cdk8s synth -p | kubectl apply -f -
          

What's new?

Helm support

  • contribution by Matthew Bonig

              class MyChart extends cdk8s.Chart {
                constructor(scope: Construct, id: string) {
                  super(scope, id);
                
                  const redis = new Helm(this, 'redis', {
                    chart: 'bitnami/redis',
                    values: {
                      sentinel: {
                        enabled: true
                      }
                    }
                  });
                }
              }
              
              const master = redis.apiObjects
                .find(o => o.name === 'my-redis-master');
              
              master.metadata.addAnnotation(
                'my.annotation', 'hey-there'
              );
      		  
  • use Include construct for plain YAML manifests

cdk8s+

  • library built on top of cdk8s
  • includes high level objects and functions
  • aims to simplify day-to-day use cases
  • will align with Kubernetes version

          const chart = new cdk8s.Chart(app, 'my-chart');

          const appData = new kplus.ConfigMap(chart, 'AppData');
          appData.addDirectory(path.join(__dirname, 'app'));
          const appVolume = kplus.Volume.fromConfigMap(appData);

          const deployment = new kplus.Deployment(chart,
            'Deployment',
            { replicas: 3 }
          );
          const appPath = '/var/lib/app';
          const port = 80;
          const container = deployment.addContainer({
            image: 'node:14.4.0-alpine3.12',
            command: ['node', 'index.js', `${port}`],
            port: port,
            workingDir: appPath,
          });

          container.mount(appPath, appVolume);
          deployment.expose(8080,
            {serviceType: kplus.ServiceType.LOAD_BALANCER}
          )
          

Java support


          final Map<String, String> selector = new HashMap<>();
          selector.put("app", "hello-k8s");

          final List<ServicePort> servicePorts = new ArrayList<>();

          final ServicePort servicePort = new ServicePort.Builder()
            .port(80)
            .targetPort(IntOrString.fromNumber(8080))
            .build();
          servicePorts.add(servicePort);

          final ServiceSpec serviceSpec = new ServiceSpec.Builder()
            .type("LoadBalancer")
            .selector(selector)
            .ports(servicePorts)
            .build();

          final KubeServiceProps serviceProps =
            new KubeServiceProps.Builder()
            .spec(serviceSpec)
            .build();

          new KubeService(this, "service", serviceProps);
          

What's to come?

Go bindings


            $ cdk8s init golang-app
          

working towards 1.0

  • main goal: stability
  • cdk8s+ API will be finished

ideas

  • Helm chart generation
  • publish constructs as CRDs
  • bundle Docker images

Give your vote!

Thanks for joining!

open questions?

  • twitter: @__brennerm
  • email: max@shipit.dev

Huge thanks for the orga!

Enjoy the rest of the talks!