cdk8s+ (cdk8s-plus)

repository·k8s-34/main·Indexed 41 days ago

https://github.com/cdk8s-team/cdk8s-plus

A software development framework providing high-level abstractions and hand-crafted constructs for authoring Kubernetes applications. Built on top of cdk8s, it simplifies the creation of Kubernetes resources by offering richer APIs and automatic boilerplate management. Versioned by Kubernetes compatibility, with packages such as cdk8s-plus-32, cdk8s-plus-33, and cdk8s-plus-34 for Kubernetes 1.34.0.

Tokens
35.1K
Snippets
116
Records
135
Agent score
50%

What's inside cdk8s+

  1. What is cdk8s+ (cdk8s-plus)

    k8s-34/main

    cdk8s+ (cdk8s-plus) is a software development framework that provides high-level abstractions for authoring Kubernetes applications. It is built on top of the auto-generated building blocks provided by cdk8s.

    Unlike the base cdk8s library which provides raw mappings to Kubernetes objects, cdk8s+ includes hand-crafted constructs for each native Kubernetes object. These constructs expose richer APIs and reduce the complexity of defining Kubernetes resources by handling much of the boilerplate and relationship management automatically.

  2. Manage network connectivity with Pod connections

    k8s-34/main

    The connections property on a Pod provides a high-level API to automatically manage Network Policies. Using allowTo or allowFrom creates both egress and ingress rules on both ends of the connection to ensure traffic is permitted in both directions.

    By default, calling these methods applies isolation to both the source and the destination pods. If you need to change this behavior, use the isolation option with one of the following values:

    • PodConnectionsIsolation.POD: Only applies isolation (egress rules) to the pod calling the method.
    • PodConnectionsIsolation.PEER: Only applies isolation (ingress rules) to the peer pod.
    • (Default) Both sides are isolated.
    import * as k from 'cdk8s';
    import * as kplus from 'cdk8s-plus-34';
    
    const app = new k.App();
    const chart = new k.Chart(app, 'Chart');
    
    const redis = new kplus.Pod(chart, 'Redis', {
      containers: [{ image: 'redis', portNumber: 6379 }]
    });
    const web = new kplus.Pod(chart, 'Web', {
      containers: [{ image: 'web' }]
    });
    
    // Automatically configures network policies for both pods
    web.connections.allowTo(redis);
    // OR
    redis.connections.allowFrom(web);
  3. Understand PersistentVolume in cdk8s-plus

    k8s-34/main

    A PersistentVolume (PV) represents a piece of storage in a Kubernetes cluster that has been provisioned by an administrator or via Storage Classes. Unlike regular volumes, a PV is detached from a pod's lifecycle and exists even if the pod is shut down.

    In cdk8s-plus, the PersistentVolume construct is used to represent a pre-existing volume in the cluster. It does not create the underlying storage (e.g., in AWS or Azure); it merely manifests that existing storage as a Kubernetes resource.

  4. Configure HPA metrics

    k8s-34/main

    The HorizontalPodAutoscaler supports several types of metrics via the kplus.Metric class:

    • Resource Metrics: Scale based on cluster resources like CPU or memory. Note that resource usage is summed across all containers in a pod, which may not reflect individual container pressure.
    • Pods Metrics: Scale based on a metric describing each pod in the target (e.g., requests-per-second). Requires a labelSelector.
    • Container Metrics: Scale based on a specific container's metric within the target pods.
    • Object Metrics: Scale based on a metric describing a single Kubernetes object (e.g., an Ingress).
    • External Metrics: Scale based on metrics not associated with any Kubernetes object (e.g., an SQS queue).
    // Resource CPU
    kplus.Metric.resourceCpu(kplus.MetricTarget.averageUtilization(70))
    
    // Pods Metrics
    kplus.Metric.pods({
      name: 'requests-per-second',
      target: kplus.MetricTarget.averageUtilization(50),
      labelSelector: kplus.LabelSelector.of({ labels: { app: 'scraper' } }),
    })
    
    // Container Memory
    kplus.Metric.containerMemory(kplus.MetricTarget.value(4096))
    
    // Object Metrics
    kplus.Metric.object({
      object: ingress,
      name: 'requests-per-second',
      target: kplus.MetricTarget.averageUtilization(50),
    })
    
    // External Metrics
    kplus.Metric.external({
      labelSelector: kplus.LabelSelector.of({ labels: { app: 'scraper' } }),
      name: 'sqs-queue',
      target: kplus.MetricTarget.averageUtilization(50),
    })
  5. How Pod scheduling works in cdk8s+

    k8s-34/main

    cdk8s+ provides a unified scheduling API on Pod (and all workload resources like Deployment, StatefulSet, etc.) that collapses complex Kubernetes scheduling features into two main concepts:

    1. Node Selection: Controlling which nodes pods are scheduled on by selecting node attributes (Assignment, Attraction, and Toleration).
    2. Pod Selection: Controlling which nodes pods are scheduled on by looking at other pods (Co-location and Separation).
  6. How Network Policies work in cdk8s+

    k8s-34/main

    Network policies control inter-pod traffic at the IP or port level (OSI layer 3 or 4).

    Key Concepts:

    • Isolation: By default, pods are non-isolated (can initiate any outgoing traffic and accept any incoming traffic). Once a NetworkPolicy applies to a pod in a specific direction (ingress or egress), that pod becomes isolated in that direction.
    • Additivity: Policies are additive and do not conflict. The allowed connections are the union of all applicable policies. Order of evaluation does not matter.
    • Bi-directional Requirement: For a connection to succeed, the source pod's egress policy must allow it AND the destination pod's ingress policy must allow it.
  7. Use the Job construct

    k8s-34/main
    The Job construct in cdk8s-plus allows you to define Kubernetes Jobs for ad-hoc provisioning or long-running processing tasks. While similar to regular Pods, Jobs offer additional properties like ttlAfterFinished. You can add containers to the Job using the addContainer method.
  8. Configure StorageClass for PersistentVolumeClaims

    k8s-34/main

    The storageClassName property determines how the backing volume is provisioned.

    • Default behavior: If storageClassName is not set, Kubernetes will either use the cluster's default storage class for dynamic provisioning or look for a pre-existing volume that has no storage class assigned.
    • Explicit Storage Class: Provide a string (e.g., 'large-ebs') to request a specific storage class. Kubernetes will then attempt to locate an existing volume with that class or provision a new one using the appropriate provisioner.
    • Disable Dynamic Provisioning: Pass an empty string "" to storageClassName. This ensures the volume is not assigned to any storage class, effectively disabling dynamic provisioning and requiring a pre-existing volume.
    // Explicit storage class
    const claim = new kplus.PersistentVolumeClaim(chart, 'Claim', {
      storage: cdk8s.Size.gibibytes(50),
      storageClassName: 'large-ebs',
    });
    
    // Disable dynamic provisioning
    const claim = new kplus.PersistentVolumeClaim(chart, 'Claim', {
      storage: cdk8s.Size.gibibytes(50),
      storageClassName: "",
    });
  9. Understand Role Based Access Control (RBAC) in cdk8s+

    k8s-34/main

    RBAC allows you to restrict actions on Kubernetes resources by creating roles with specific rules. These rules are purely additive; there are no 'deny' rules.

    There are two main hierarchies for roles and bindings:

    1. Namespaced Resources (e.g., Pods, Deployments):

      • Use Role to define permissions within a specific namespace.
      • Use RoleBinding to grant those permissions to a subject within a namespace.
    2. Non-Namespaced/Cluster Resources (e.g., Nodes, URLs):

      • Use ClusterRole to define permissions cluster-wide.
      • Use ClusterRoleBinding to grant those permissions cluster-wide.

    Roles can be bound to Kubernetes subjects, which include User, Group, or ServiceAccount.

  10. Allow bi-directional connections easily

    k8s-34/main

    Manually configuring both egress (on source) and ingress (on destination) can be complex, especially across namespaces. If the source is a managed Pod or Workload, you can use the .connections API to simplify this into a single call.

    import * as k from 'cdk8s';
    import * as kplus from 'cdk8s-plus-34';
    
    const app = new k.App();
    const chart = new k.Chart(app, 'Chart');
    
    const web = new kplus.Pod(chart, 'Web', { 
      containers: [{ image: 'web' }],
      metadata: { namespace: 'n1' }
    });
    
    const redis = new kplus.Pod(chart, 'Redis', { 
      containers: [{ image: 'redis', portNumber: 6379 }],
      metadata: { namespace: 'n2' }
    });
    
    // Automatically configures egress on 'web' and ingress on 'redis'
    web.connections.allowTo(redis);
    
    // OR
    
    // Automatically configures ingress on 'redis' from 'web'
    redis.connections.allowFrom(web);
  11. Configure a Job to delete itself after completion

    k8s-34/main

    You can use the ttlAfterFinished property in the Job constructor to automatically clean up a Job after it has finished its execution successfully. This property accepts a Duration object. This is useful for ad-hoc provisioning tasks or one-off processing jobs to prevent stale Job resources from accumulating in your cluster.

    import * as kplus from 'cdk8s-plus-34';
    import { Construct } from 'constructs';
    import { App, Chart, ChartProps, Duration } from 'cdk8s';
    
    export class MyChart extends Chart {
      constructor(scope: Construct, id: string, props: ChartProps = { }) {
        super(scope, id, props);
    
        // let's define a job spec, and set a 1 second TTL.
        const job = new kplus.Job(this, 'LoadData', {
          ttlAfterFinished: Duration.seconds(1)
        });
    
        // now add a container to all the pods created by this job
        job.addContainer({
          image: 'loader'
        });
      }
    }
    
    const app = new App();
    new MyChart(app, 'Job');
    app.synth();
  12. Use PersistentVolumeClaim Templates with StatefulSets

    k8s-34/main

    When using StatefulSet, you can define volumeClaimTemplates to provide stable, persistent storage for each pod. Each pod in the set receives its own unique PersistentVolumeClaim (e.g., name-statefulset-0).

    To use these templates:

    1. Define the templates in the StatefulSet constructor via volumeClaimTemplates or using the addVolumeClaimTemplate method.
    2. Reference the volumes in your container's volumeMounts using Volume.fromName(chart, templateName, volumeName).
    import * as kplus from 'cdk8s-plus-32';
    import { Size } from 'cdk8s';
    
    // Reference a volume defined in a template
    const dataVolume = Volume.fromName(chart, "pvc-template-data", "data-volume")
    
    // Create a StatefulSet with PVC templates
    const statefulSet = new kplus.StatefulSet(this, 'StatefulSet', {
      containers: [{
        image: 'nginx',
        volumeMounts: [{
          volume: dataVolume,
          path: '/data',
        }, {
          volume: Volume.fromName(chart, "pvc-template-temp", "temp-volume"),
          path: '/data',
        }],
      }],
      volumeClaimTemplates: [{
        name: dataVolume.name,
        storage: Size.gibibytes(10),
        accessModes: [kplus.PersistentVolumeAccessMode.READ_WRITE_ONCE],
        storageClassName: 'standard',
      }, {
        name: 'temp-volume',
        storage: Size.gibibytes(10),
        accessModes: [kplus.PersistentVolumeAccessMode.READ_WRITE_ONCE],
        storageClassName: 'standard',
      }],
    });
    
    // Or add PVC templates after creation
    statefulSet.addVolumeClaimTemplate({
      name: 'logs-volume',
      storage: Size.gibibytes(5),
      accessModes: [kplus.PersistentVolumeAccessMode.READ_WRITE_ONCE],
    });