Skip to content

Commit

Permalink
feat(eks): Support cdk8s charts (#10562)
Browse files Browse the repository at this point in the history
Natively integrate EKS with the `cdk8s` library.

Closes #9670

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
iliapolo committed Oct 6, 2020
1 parent bf2c629 commit e51921d
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 53 deletions.
122 changes: 122 additions & 0 deletions packages/@aws-cdk/aws-eks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Table Of Contents
* [Applying Kubernetes Resources](#applying-kubernetes-resources)
* [Kubernetes Manifests](#kubernetes-manifests)
* [Helm Charts](#helm-charts)
* [CDK8s Charts](#cdk8s-charts)
* [Patching Kuberentes Resources](#patching-kubernetes-resources)
* [Querying Kubernetes Resources](#querying-kubernetes-resources)
* [Using existing clusters](#using-existing-clusters)
Expand Down Expand Up @@ -811,6 +812,127 @@ const chart2 = cluster.addHelmChart(...);
chart2.node.addDependency(chart1);
```

#### CDK8s Charts

[CDK8s](https://cdk8s.io/) is an open-source library that enables Kubernetes manifest authoring using familiar programming languages. It is founded on the same technologies as the AWS CDK, such as [`constructs`](https://github.com/aws/constructs) and [`jsii`](https://github.com/aws/jsii).

> To learn more about cdk8s, visit the [Getting Started](https://github.com/awslabs/cdk8s/tree/master/docs/getting-started) tutorials.
The EKS module natively integrates with cdk8s and allows you to apply cdk8s charts on AWS EKS clusters via the `cluster.addCdk8sChart` method.

In addition to `cdk8s`, you can also use [`cdk8s+`](https://github.com/awslabs/cdk8s/tree/master/packages/cdk8s-plus), which provides higher level abstraction for the core kubernetes api objects.
You can think of it like the `L2` constructs for Kubernetes. Any other `cdk8s` based libraries are also supported, for example [`cdk8s-debore`](https://github.com/toricls/cdk8s-debore).

To get started, add the following dependencies to your `package.json` file:

```json
"dependencies": {
"cdk8s": "0.30.0",
"cdk8s-plus": "0.30.0",
"constructs": "3.0.4"
}
```

> Note that the version of `cdk8s` must be `>=0.30.0`.
Similarly to how you would create a stack by extending `@aws-cdk/core.Stack`, we recommend you create a chart of your own that extends `cdk8s.Chart`,
and add your kubernetes resources to it. You can use `aws-cdk` construct attributes and properties inside your `cdk8s` construct freely.

In this example we create a chart that accepts an `s3.Bucket` and passes its name to a kubernetes pod as an environment variable.

Notice that the chart must accept a `constructs.Construct` type as its scope, not an `@aws-cdk/core.Construct` as you would normally use.
For this reason, to avoid possible confusion, we will create the chart in a separate file:

`+ my-chart.ts`
```ts
import * as s3 from '@aws-cdk/aws-s3';
import * as constructs from 'constructs';
import * as cdk8s from 'cdk8s';
import * as kplus from 'cdk8s-plus';

export interface MyChartProps {
readonly bucket: s3.Bucket;
}

export class MyChart extends cdk8s.Chart {
constructor(scope: constructs.Construct, id: string, props: MyChartProps} ) {
super(scope, id);

new kplus.Pod(this, 'Pod', {
spec: {
containers: [
new kplus.Container({
image: 'my-image',
env: {
BUCKET_NAME: bucket.bucketName,
}
})
]
}
});
}
}
```

Then, in your AWS CDK app:

```ts
import * as s3 from '@aws-cdk/aws-s3';
import * as cdk8s from 'cdk8s';
import { MyChart } from './my-chart';

// some bucket..
const bucket = new s3.Bucket(this, 'Bucket');

// create a cdk8s chart and use `cdk8s.App` as the scope.
const myChart = new MyChart(new cdk8s.App(), 'MyChart', { bucket });

// add the cdk8s chart to the cluster
cluster.addCdk8sChart('my-chart', myChart);
```

##### Custom CDK8s Constructs

You can also compose a few stock `cdk8s+` constructs into your own custom construct. However, since mixing scopes between `aws-cdk` and `cdk8s` is currently not supported, the `Construct` class
you'll need to use is the one from the [`constructs`](https://github.com/aws/constructs) module, and not from `@aws-cdk/core` like you normally would.
This is why we used `new cdk8s.App()` as the scope of the chart above.

```ts
import * as constructs from 'constructs';
import * as cdk8s from 'cdk8s';
import * as kplus from 'cdk8s-plus';

export interface LoadBalancedWebService {
readonly port: number;
readonly image: string;
readonly replicas: number;
}

export class LoadBalancedWebService extends constructs.Construct {
constructor(scope: constructs.Construct, id: string, props: LoadBalancedWebService) {
super(scope, id);

const deployment = new kplus.Deployment(chart, 'Deployment', {
spec: {
replicas: props.replicas,
podSpecTemplate: {
containers: [ new kplus.Container({ image: props.image }) ]
}
},
});

deployment.expose({port: props.port, serviceType: kplus.ServiceType.LOAD_BALANCER})

}
}
```

##### Manually importing k8s specs and CRD's

If you find yourself unable to use `cdk8s+`, or just like to directly use the `k8s` native objects or CRD's, you can do so by manually importing them using the `cdk8s-cli`.

See [Importing kubernetes objects](https://github.com/awslabs/cdk8s/tree/master/packages/cdk8s-cli#import) for detailed instructions.

## Patching Kubernetes Resources

The `KubernetesPatch` construct can be used to update existing kubernetes
Expand Down
22 changes: 22 additions & 0 deletions packages/@aws-cdk/aws-eks/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as kms from '@aws-cdk/aws-kms';
import * as lambda from '@aws-cdk/aws-lambda';
import * as ssm from '@aws-cdk/aws-ssm';
import { Annotations, CfnOutput, CfnResource, IResource, Resource, Stack, Tags, Token, Duration } from '@aws-cdk/core';
import * as cdk8s from 'cdk8s';
import { Construct, Node } from 'constructs';
import * as YAML from 'yaml';
import { AwsAuth } from './aws-auth';
Expand Down Expand Up @@ -132,6 +133,16 @@ export interface ICluster extends IResource, ec2.IConnectable {
* @returns a `HelmChart` construct
*/
addHelmChart(id: string, options: HelmChartOptions): HelmChart;

/**
* Defines a CDK8s chart in this cluster.
*
* @param id logical id of this chart.
* @param chart the cdk8s chart.
* @returns a `KubernetesManifest` construct representing the chart.
*/
addCdk8sChart(id: string, chart: cdk8s.Chart): KubernetesManifest;

}

/**
Expand Down Expand Up @@ -617,6 +628,17 @@ abstract class ClusterBase extends Resource implements ICluster {
public addHelmChart(id: string, options: HelmChartOptions): HelmChart {
return new HelmChart(this, `chart-${id}`, { cluster: this, ...options });
}

/**
* Defines a CDK8s chart in this cluster.
*
* @param id logical id of this chart.
* @param chart the cdk8s chart.
* @returns a `KubernetesManifest` construct representing the chart.
*/
public addCdk8sChart(id: string, chart: cdk8s.Chart): KubernetesManifest {
return this.addManifest(id, ...chart.toJson());
}
}

/**
Expand Down
9 changes: 9 additions & 0 deletions packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
import * as ssm from '@aws-cdk/aws-ssm';
import * as cdk8s from 'cdk8s';
import { Annotations, CfnOutput, Resource, Stack, Token, Tags } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { ICluster, ClusterAttributes, KubernetesVersion, NodeType, DefaultCapacityType, EksOptimizedImage, AutoScalingGroupCapacityOptions, MachineImageType, AutoScalingGroupOptions, CommonClusterOptions } from './cluster';
Expand Down Expand Up @@ -371,6 +372,10 @@ export class LegacyCluster extends Resource implements ICluster {
throw new Error('legacy cluster does not support adding helm charts');
}

public addCdk8sChart(_id: string, _chart: cdk8s.Chart): KubernetesManifest {
throw new Error('legacy cluster does not support adding cdk8s charts');
}

/**
* Opportunistically tag subnets with the required tags.
*
Expand Down Expand Up @@ -429,6 +434,10 @@ class ImportedCluster extends Resource implements ICluster {
throw new Error('legacy cluster does not support adding helm charts');
}

public addCdk8sChart(_id: string, _chart: cdk8s.Chart): KubernetesManifest {
throw new Error('legacy cluster does not support adding cdk8s charts');
}

public get vpc() {
if (!this.props.vpc) {
throw new Error('"vpc" is not defined for this imported cluster');
Expand Down
5 changes: 4 additions & 1 deletion packages/@aws-cdk/aws-eks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
"cfn2ts": "0.0.0",
"nodeunit": "^0.11.3",
"pkglint": "0.0.0",
"sinon": "^9.1.0"
"sinon": "^9.1.0",
"cdk8s-plus": "^0.29.0"
},
"dependencies": {
"@aws-cdk/aws-autoscaling": "0.0.0",
Expand All @@ -90,6 +91,7 @@
"@aws-cdk/aws-ssm": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/custom-resources": "0.0.0",
"cdk8s": "^0.30.0",
"constructs": "^3.0.4",
"yaml": "1.10.0"
},
Expand All @@ -106,6 +108,7 @@
"@aws-cdk/aws-ssm": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/custom-resources": "0.0.0",
"cdk8s": "^0.30.0",
"constructs": "^3.0.4"
},
"engines": {
Expand Down
Loading

0 comments on commit e51921d

Please sign in to comment.