Containers

Announcing the general availability of cdk8s and support for Go

The CDK8s project is excited to announce General Availability and support for the Go programming language. CDK8s, a CNCF Sandbox project, is an open-source software development framework for defining Kubernetes applications using general-purpose programming languages. The output of a CDK8s program is Kubernetes YAML that you can apply directly to any cluster. To learn more about the motivation behind CDK8s please see the original launch blog post or CNCF Webinar.

General Availability (i.e 1.0)

Before we dive in, here is a quick recap of the main components comprising the CDK8s project:

  • cdk8s-cli: Command line tool for initializing and synthesizing CDK8s projects.
  • cdk8s: Core library that defines the building blocks of Kubernetes resources.
  • cdk8s-plus: A simplified intent based API for interacting with Kubernetes resources.

With this release, we are marking both the cdk8s-cli and cdk8s as 1.0.
This means we will be complying fully with semantic versioning, and no breaking changes are expected in any of
the following minor version releases.

Note that cdk8s-plus still remains in beta as we gather more community feedback.

In addition to the stability and compatibility support, this release comes with a couple more enhancements:

Go

GoLang has been by far the most requested language support for the CDK8s ever since launch. We are excited to announce that with GA, Go joins Java, Python, and TypeScript as an officially supported language. Go developers can now use CDK8s to define their Kubernetes resources programmatically and easily compose them with low level building blocks generated from the Kubernetes OpenAPI schema.

To get started you’ll need Go and Node.js which you can most likely grab from your package manager. We’ll also need a Kubernetes cluster to deploy to. If you don’t currently have one, you can use kind, eksctl, or any other provider to create one. Next, install the CDK8s CLI by running the following.

$ npm install -g cdk8s-cli

Once the CLI is installed we can create a new directory and initialize a CDK8s app from the Go template.

$ mkdir hello-cdk8s-go
$ cd hello-cdk8s-go
$ cdk8s init go-app

Initializing a project from the go-app template
Importing resources, this may take a few moments...
========================================================================================================

 Your cdk8s Go 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/

Now that your project has been created we can open up main.go in your favorite text editor.

package main

import (
    "github.com/aws/constructs-go/constructs/v3"
    "github.com/aws/jsii-runtime-go"
    "github.com/cdk8s-team/cdk8s-core-go/cdk8s"
)

type MyChartProps struct {
    cdk8s.ChartProps
}

func NewMyChart(scope constructs.Construct, id string, props *MyChartProps) cdk8s.Chart {
    var cprops cdk8s.ChartProps
    if props != nil {
        cprops = props.ChartProps
    }
    chart := cdk8s.NewChart(scope, jsii.String(id), &cprops)

    // define resources here

    return chart
}

func main() {
    app := cdk8s.NewApp(nil)
    NewMyChart(app, "hello-cdk8s-go", nil)
    app.Synth()
}

CDK8s has a few different concepts that we’ll be working with. Constructs are the basic building blocks that can be composed to build higher-level abstractions. ApiObjects are Constructs that represent a Kubernetes resource and Charts (not to be confused with Helm Charts) are containers for your Constructs that will output a Kubernetes manifest.

The CDK8s CLI has automatically imported ApiObjects generated from the Kubernetes OpenAPI spec for us at imports/k8s/k8s.go. You can take a look at this file but don’t be intimidated by it’s size – it represents the entire Kubernetes API.

Import the ApiObjects into your main.go file by adding example.com/hello-cdk8s-go/imports/k8s to the import section at the top. Note: you can change the module name from example.com to whatever you prefer at the top of the go.mod file.

Now we can finish your first Chart! Replace the // define resources here line with the following code that defines a Kubernetes deployment for an Nginx web server image.

labels := map[string]*string{"app": jsii.String("nginx")}

podSpec := &k8s.PodSpec{
    Containers: &[]*k8s.Container{
        {
            Name:  jsii.String("nginx"),
            Image: jsii.String("nginx:latest"),
            Ports: &[]*k8s.ContainerPort{{ContainerPort: jsii.Number(80)}},
        },
    },
}

k8s.NewKubeDeployment(chart, jsii.String("nginx-deployment"), &k8s.KubeDeploymentProps{
    Spec: &k8s.DeploymentSpec{
        Selector: &k8s.LabelSelector{
            MatchLabels: &labels,
        },
        Template: &k8s.PodTemplateSpec{
            Metadata: &k8s.ObjectMeta{
                Labels: &labels,
            },
            Spec: podSpec,
        },
    },
})

With your ApiObjects in place it’s time to synth which will run your CDK8s app and write your Kubernetes manifest.

$ cdk8s synth
dist/hello-cdk8s-go.k8s.yaml

If you open up dist/hello-cdk8s-go.k8s.yaml you’ll see the YAML that was generated from your plain old Go code. Pretty neat, right?

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-cdk8s-go-nginx-deployment-c8413b4d
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - image: nginx:latest
          name: nginx
          ports:
            - containerPort: 80

All that’s left is to apply your manifest to the cluster and test it out.

$ kubectl apply -f dist/hello-cdk8s-go.k8s.yaml
deployment.apps/hello-cdk8s-go-nginx-deployment-c8413b4d created

POD_NAME=$(kubectl get pods -l app=nginx -o jsonpath='{.items[0].metadata.name}')
kubectl port-forward $POD_NAME 8080:80

If you open http://localhost:8080 in your browser you should be greeted with “Welcome to nginx!” confirming your success.

CDK8s+

The low level CDK8s resources are powerful, but also still carry a significant cognitive load caused by the overwhelming set of properties and resources. To address this, we created CDK8s+, which provides a set of simplified intent based API’s built on top of the same low level resources we just used.

For example, to achieve the same result we had before, but this time with the help of CDK8s+:

import (
      "github.com/cdk8s-team/cdk8s-plus-go/cdk8splus22"
    )

cdk8splus22.NewDeployment(app, jsii.String("nginx"), &cdk8splus22.DeploymentProps{
    Containers: &[]*cdk8splus22.ContainerProps{
        {
            Image: jsii.String("nginx:latest"),
        },
    },
})

You can read more about CDK8s+ in our original launch blog post.

One of the main goals for CDK8s+ is to reduce cognitive load, leaving very little room for making authoring mistakes. To achieve this, we decided to make CDK8s+ target a specific version of Kubernetes. This way, authors are not exposed to functionality that might not be available in the Kubernetes cluster they are operating.

Prior to this launch, we only supported CDK8s+ API’s for Kubernetes version 1.17. This meant that we weren’t able to enhance the API’s with features that were added in higher versions. With this release, we introduce multiple CDK8s+ libraries, corresponding to the 3 latest versions of Kubernetes.

For more information on CDK8s+ versioning and vending strategy, see CDK8s+ FAQ.

CDK8s+ remains in beta while we collect community feedback. Please share yours!

Next Steps

We hope you give CDK8s a try. A great place to start is with the getting started guide and the examples in the repository. If you are interested in contributing or providing feedback please join the mailing list and attend one of our monthly community meetings.