cdk8s+¶
cdk8s+ is a library with high level abstractions for authoring Kubernetes applications.
Built on top of the auto-generated building blocks provided by cdk8s, this library includes a hand crafted construct for each native kubernetes object, exposing richer API’s with reduced complexity.
Info
The documentation here relates to version 2.x
of the cdk8s toolchain, which is the latest. If you are still using version 1.x
, please refer to the Migrating from 1.x Guide.
Here is an example of how we would deploy a simple nginx container, once with the low-level API (on the left), and once with the high level abstraction (on the right).
Spec compatibility¶
cdk8s+ is vended as a separate library for each kubernetes spec version. Follow the pane on the left to navigate to the appropriate version you need.
Per kubernetes compatibility guarantees, stable resources in a cdk8s-plus-XX
library are compatible with
any spec version higher or equal to 1.XX.0
. Non-stable resources are not guaranteed to be compatible, as they may be removed in future spec versions.
Notice
cdk8s+ libraries are maintained only for the 3 latest Kubernetes releases. So, if the latest Kubernetes release is N, cdk8s-plus-N
, cdk8s-plus-(N-1)
and cdk8s-plus-(N-2)
will be continously updated
and supported. However, cdk8s-plus-(N-3)
and so on will no longer be actively maintained.
Naming conventions¶
- Stable resources are represented by a construct of the same kind. For example, the
io.k8s.api.core.v1.Pod
resource maps to thePod
construct. - Non stable resources are suffixed with their api version. For example, the
io.k8s.api.networking.v1beta1.Ingress
maps to theIngressV1Beta1
construct.
FAQ¶
I operate Kubernetes version 1.XX
- which cdk8s+ library should I be using?¶
If there is a cdk8s-plus-XX
library that matches your target Kubernetes
version, we recommend using it since all Kubernetes manifests generated using it
will be compatible.
If there is not a matching cdk8s-plus-XX
library, we recommend using the
closest matching version. The manifests generated by cdk8s-plus-XX
may also
work for older versions of Kubernetes, but you might encounter some unsupported
spec properties or invalid manifests.
I’m using cdk8s-plus-XX
- which kubernetes versions will my manifest work on?¶
If you are using stable APIs (those that are not in alpha or beta), manifests
generated in cdk8s-plus-XX
will work in Kubernetes versions 1.XX.0
and
above. Unstable APIs (which are always labeled in cdk8s+ using a suffix, e.g.
IngressV1Beta1
) may work in newer versions of Kubernetes, but it is also
possible they have been removed.
The manifests generated by cdk8s-plus-XX
may also work for older versions of
Kubernetes, but you might encounter some unsupported spec properties or invalid
manifests.
At a glance¶
import * as kplus from 'cdk8s-plus-31';
import * as cdk8s from 'cdk8s';
import * as path from 'path';
// our cdk app
const app = new cdk8s.App();
// our kubernetes chart
const chart = new cdk8s.Chart(app, 'my-chart');
// lets create a volume that contains our app.
// we use a trick with a config map!
const appData = new kplus.ConfigMap(chart, 'AppData');
appData.addDirectory(path.join(__dirname, 'app'));
const appVolume = kplus.Volume.fromConfigMap(appData);
// lets create a deployment to run a few instances of a pod
const deployment = new kplus.Deployment(chart, 'Deployment', {
replicas: 3,
});
// now we create a container that runs our app
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,
});
// make the app accessible to the container
container.mount(appPath, appVolume);
// finally, we expose the deployment as a load balancer service and make it run
deployment.exposeViaService({ serviceType: kplus.ServiceType.LOAD_BALANCER });
// we are done, synth
app.synth();
dist/my-chart.yaml
apiVersion: v1
data:
index.js: |-
var http = require('http');
var port = process.argv[2];
//create a server object:
http.createServer(function (req, res) {
res.write('Hello World!'); //write a response to the client
res.end(); //end the response
}).listen(port); //the server object listens on port 80
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: chart-appdata-configmap-da4c63ab
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations: {}
labels: {}
name: chart-deployment-pod-d4285cc9
spec:
replicas: 3
selector:
matchLabels:
cdk8s.deployment: ChartDeploymentCFC2E30C
template:
metadata:
annotations: {}
labels:
cdk8s.deployment: ChartDeploymentCFC2E30C
spec:
containers:
- command:
- node
- index.js
- "80"
env: []
image: node:14.4.0-alpine3.12
name: main
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/lib/app
name: configmap-chart-appdata-configmap-da4c63ab
workingDir: /var/lib/app
volumes:
- configMap:
name: chart-appdata-configmap-da4c63ab
name: configmap-chart-appdata-configmap-da4c63ab
---
apiVersion: v1
kind: Service
metadata:
annotations: {}
labels: {}
name: chart-deployment-service-pod-42f50c26
spec:
externalIPs: []
ports:
- port: 8080
targetPort: 80
selector:
cdk8s.deployment: ChartDeploymentCFC2E30C
type: LoadBalancer
Getting Started¶
❯ npm install cdk8s-plus-31 cdk8s constructs
import * as kplus from 'cdk8s-plus-31';
import * as cdk8s from 'cdk8s';
const app = new cdk8s.App();
const chart = new cdk8s.Chart(app, 'Chart');
new kplus.Deployment(chart, 'Deployment', {
replicas: 3,
containers: [{
image: 'ubuntu',
}],
});
app.synth();
❯ npm install cdk8s-plus-31 cdk8s constructs
const kplus = require('cdk8s-plus-31');
const cdk8s = require('cdk8s');
const app = new cdk8s.App();
const chart = new cdk8s.Chart(app, 'Chart');
new kplus.Deployment(chart, 'Deployment', {
replicas: 3,
containers: [{
image: 'ubuntu',
}],
});
app.synth();
❯ pip install cdk8s-plus-31 cdk8s
import cdk8s_plus_27 as kplus
import cdk8s
app = cdk8s.App()
chart = cdk8s.Chart(app, 'Chart')
kplus.Deployment(chart, 'Deployment',
replicas=1,
containers=[kplus.ContainerProps(image='ubuntu')]
)
app.synth()
<dependency>
<groupId>org.cdk8s</groupId>
<artifactId>cdk8s</artifactId>
<version>2.5.21</version>
</dependency>
<dependency>
<groupId>org.cdk8s</groupId>
<artifactId>cdk8s-plus-31</artifactId>
<version>2.0.0</version>
</dependency>
package com.mycompany.app;
import software.constructs.Construct;
import org.cdk8s.App;
import org.cdk8s.Chart;
import org.cdk8s.ChartProps;
import org.cdk8s.plus31.Deployment;
import org.cdk8s.plus31.ContainerProps;
import java.util.Arrays;
public class Main extends Chart
{
public Main(final Construct scope, final String id) {
this(scope, id, null);
}
public Main(final Construct scope, final String id, final ChartProps options) {
super(scope, id, options);
Deployment.Builder.create(this, "Deployment")
.replicas(3)
.containers(Arrays.asList(ContainerProps.builder()
.image("ubuntu")
.build()))
.build();
}
public static void main(String[] args) {
final App app = new App();
final Chart chart = new Main(app, "Chart");
app.synth();
}
}
import (
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
"github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2"
"github.com/cdk8s-team/cdk8s-plus-go/cdk8splus31"
)
app := cdk8s.NewApp(nil)
chart := cdk8s.NewChart(app, jsii.String("ubuntu"), nil)
cdk8splus31.NewDeployment(chart, jsii.String("Deployment"), &cdk8splus31.DeploymentProps{
Replicas: jsii.Number(3),
Containers: &[]*cdk8splus31.ContainerProps{{
Image: jsii.String("ubuntu"),
}},
})
app.Synth()
Overcoming Coverage Gaps¶
As mentioned, the APIs offered by cdk8s+ are hand-written by the team as well as the community. As such, you might encounter coverage gaps from time to time; that is, you are trying to configure something but the API doesn’t expose it. There are two kinds of gaps:
Missing Resource¶
When an entire resource is missing, you can supplement it by dropping to the L1 layer of constructs, which are available from within cdk8s+, so you don’t need to install an additional library, or import any resources. For example:
import * as kplus from 'cdk8s-plus-31';
import * as cdk8s from 'cdk8s';
const app = new cdk8s.App();
const chart = new cdk8s.Chart(app, 'Chart');
// a Deployment exists as a higher level objects,
// so we use it.
new kplus.Deployment(chart, 'Deployment', {
replicas: 3,
containers: [{
image: 'ubuntu',
}],
});
// a StorageClass doesn't, so we use the low level objects.
// notice the '.k8s.' addition.
new kplus.k8s.KubeStorageClass(chart, 'StorageClass', {
provisioner: 'kubernetes.io/aws-ebs'
});
app.synth();