Homelab 2 - Deno and cdk8s

cdk and cdk8s

If you’ve used CloudFormation, then you know how much it sucks. You use a weird dialect of YAML to define your AWS resources. Back in 2017 AWS introduced the cdk library. It allows you to generate your CloudFormation YAML using a real language like Go, Python, Java, or TypeScript.

This idea turned out to be execellent, so they did the same thing for Kubernetes with cdk8s. cdk8s seems to be abandonded, but it still works quite well. Since the TypeScript defitions are generated from Kubernetes’ resources (including third-party custom resource definitions!),the library should continue to work for quite a while longer.

Here’s a “hello world” program from cdk8s’ documentation:

import { import ConstructConstruct } from "constructs";
import { import AppApp, import ChartChart } from "cdk8s";
import { import KubeDeploymentKubeDeployment } from "./imports/k8s";

class class MyChartMyChart extends import ChartChart {
  constructor(scope: Constructscope: import ConstructConstruct, ns: stringns: string, appLabel: stringappLabel: string) {
    super(scope: Constructscope, ns: stringns);

    // Define a Kubernetes Deployment
    new import KubeDeploymentKubeDeployment(this, "my-deployment", {
      
spec: {
    replicas: number;
    selector: {
        matchLabels: {
            app: string;
        };
    };
    template: {
        metadata: {
            labels: {
                app: string;
            };
        };
        spec: {
            containers: {
                name: string;
                image: string;
                ports: {
                    containerPort: number;
                }[];
            }[];
        };
    };
}
spec
: {
replicas: numberreplicas: 3,
selector: {
    matchLabels: {
        app: string;
    };
}
selector
: {
matchLabels: {
    app: string;
}
matchLabels
: { app: stringapp: appLabel: stringappLabel } },
template: {
    metadata: {
        labels: {
            app: string;
        };
    };
    spec: {
        containers: {
            name: string;
            image: string;
            ports: {
                containerPort: number;
            }[];
        }[];
    };
}
template
: {
metadata: {
    labels: {
        app: string;
    };
}
metadata
: {
labels: {
    app: string;
}
labels
: { app: stringapp: appLabel: stringappLabel } },
spec: {
    containers: {
        name: string;
        image: string;
        ports: {
            containerPort: number;
        }[];
    }[];
}
spec
: {
containers: {
    name: string;
    image: string;
    ports: {
        containerPort: number;
    }[];
}[]
containers
: [
{ name: stringname: "app-container", image: stringimage: "nginx:1.19.10",
ports: {
    containerPort: number;
}[]
ports
: [{ containerPort: numbercontainerPort: 80 }],
}, ], }, }, }, }); } } const const app: anyapp = new import AppApp(); new constructor MyChart(scope: Construct, ns: string, appLabel: string): MyChartMyChart(const app: anyapp, "getting-started", "my-app"); const app: anyapp.synth();

The result of running this program is a Kubernetes YAML file that you can deploy using kubectl apply:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: getting-started-my-deployment-c85252a6
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - image: nginx:1.19.10
          name: app-container
          ports:
            - containerPort: 80

Why is this useful? Static typing! cdk8s can inform guide you as you write your Kubernetes resources. For example, it can let you know what properties are valid when you’re creating a resource or let you know when you’ve specifiy an invalid property.

Inspired by Xe's blog

cdk8s has support for all of Kubernete’s resources. These definitions are generated by the cdk8s import command, which generates types for every Kubernetes resource on your server including CRDs (custom resource definitions). Here’s an example of a generated definition for 1Password, which I use to handle all of the secrets in my Kubernetes cluster:

export class class OnePasswordItemOnePasswordItem extends ApiObject {
  public constructor(scope: Constructscope: type Construct = /*unresolved*/ anyConstruct, id: stringid: string, props: OnePasswordItemPropsprops: OnePasswordItemProps = {}) {
    super(scope: Constructscope, id: stringid, {
      ...class OnePasswordItemOnePasswordItem.GVK,
      ...props: OnePasswordItemPropsprops,
    });
  }
}

export interface OnePasswordItemProps {
  readonly OnePasswordItemProps.metadata?: anymetadata?: type ApiObjectMetadata = /*unresolved*/ anyApiObjectMetadata;
  readonly OnePasswordItemProps.spec?: OnePasswordItemSpec | undefinedspec?: OnePasswordItemSpec;
  readonly OnePasswordItemProps.type?: string | undefinedtype?: string;
}

export interface OnePasswordItemSpec {
  readonly OnePasswordItemSpec.itemPath?: string | undefineditemPath?: string;
}

Here’s how I use it to store my Tailscale key:

new OnePasswordItem(chart, "tailscale-operator-oauth-onepassword", {
  
spec: {
    itemPath: string;
}
spec
: {
itemPath: stringitemPath: "vaults/v64ocnykdqju4ui6j6pua56xw4/items/mboftvs4fyptyqvg3anrfjy6vu", },
metadata: {
    name: string;
    namespace: string;
}
metadata
: {
name: stringname: "operator-oauth", namespace: stringnamespace: "tailscale", }, });

Takeaway: cdk8s supports all Kubernetes resources, including third-party resources from 1Password, Tailscale, Traefik, etc.

Deno

TODO: write about Deno

Recent posts from blogs that I like

The Coast of Maine: 19th century paintings

Paintings from 1845 by Thomas Cole, Frederic Edwin Church his pupil, Winslow Homer, and other American artists from the 18th century.

via The Eclectic Light Company

Themes from DjangoCon US 2024

via Simon Willison

Some Go web dev notes

I spent a lot of time in the past couple of weeks working on a website in Go that may or may not ever see the light of day, but I learned a couple of things along the way I wanted to write down. Here they are: go 1.22 now has better routing I’ve never felt motivated to learn any of the Go routing li...

via Julia Evans