cdk8s-plus-25
Version:
cdk8s+ is a software development framework that provides high level abstractions for authoring Kubernetes applications. cdk8s-plus-25 synthesizes Kubernetes manifests for Kubernetes 1.25.0
190 lines (138 loc) • 7.43 kB
Markdown
# cdk8s+ (cdk8s-plus)
Hey there! Thanks for taking an interest in contributing to cdk8s+ 😀
> Before you continue, please make sure you've read the general procedural contribution guidance for this repository: [Contributing to cdk8s](../../CONTRIBUTING.md)
## Design Principles
As already mentioned in the [README](./README.md), this library is in very early stages of development.
Even so, there are several design principles we would like to try and maintain:
> Note: nothing is set in stone, if you feel these principles are in some way limiting in providing the best API possible, please feel
free to voice your concerns and even submit a PR to amend the principles themselves.
### Mutability
As you will notice, objects in this API are mutable on collections and have
read-only accessors for primitives.
For example:
```typescript
import * as kplus from 'cdk8s-plus-17';
const pod = new kplus.Pod(parent, 'Pod', {
replicas: 4
});
// mutating the pod spec with another volume
pod.spec.addVolume(volume);
// mutating the pod spec with another container
pod.spec.addContainer(container);
// returns the resolved value of "replicas"
assert(pod.replicas === 4);
```
When an object is instantiated, it is initialized through a set of properties
("props"). In many cases, these properties will have default values. After an
object is already initialized it should be possible to:
1. **Read** resolved values of primitive values through properties by the same
name:
```ts
interface FooProps {
/**
* @default 10
**/
readonly replicas?: number;
}
class Foo extends Construct {
public readonly replicas: number;
constructor(scope: Construct, id: string, props: FooProps = { }) {
super(scope, id);
this.replicas = props.replicas ?? 10;
}
}
```
2. **Mutate collections (lists/maps)**: since mutation of unordered collections
is a safe operation in respect to ordering (anyone can add items to a set or
a new key to a map without "racing" with other areas in the code), we should
offer `addXxx` mutation methods for lists and maps:
```ts
interface FooProps {
readonly bar?: string[];
readonly baz?: { [key: string]: string };
}
class Foo ... {
public addBar(item: string): void { ... }
public addBaz(key: string, value: string): void { ... }
}
```
3. **Read collections through immutable copies**: the API should also include
properties for obtaining a copy of collections so they can be inspected but
not modified (continuing the previous example):
```ts
class Foo ... {
private readonly _bar: string[];
private readonly _baz: { [k: string]: string };
constructor() {
this._bar = props.bar ?? [];
this._baz = props.baz ?? {};
}
// use spreads to create a copy
public get bar() { return [ ...this._bar ]; }
public get baz() { return { ...this._baz }; }
}
```
The reasoning behind this is three fold:
1. Kubernetes spec objects have an extremely large surface area. Configuring all
properties in the constructor can easily result in cluttered and un-readable
code. Exposing post instantiation methods can provide a cleaner, more
semantic mechanism of configuration.
2. This library aims to reduce the complexity of creating Kubernetes
configuration files. An important enabler to achieve this, is the ability to
auto wire different resources to work together. To that end, post
instantiation mutations are often required.
3. The reason we only allow mutations of (unordered) collections and not
primitive values is in order to protect against the situation where multiple
places in your code attempt to write conflicting values to a primitive, and
the order in which they write now becomes important (i.e. a small, unrelated
refactor may change the order). This problem does not exist with unordered
collections.
### Non leaky
We strive to provide a full abstraction that does not expose the underlying [auto-generated](./imports/k8s.d.ts) api objects.
Many times, this may result in some code duplication or redundancy. Even though it itches our developer nerves, we do not shy away from it.
> **Sometimes, a little duplication is better than a lot of dependencies.**
## Making a pull request
This repository is set up to maintain one cdk8s+ library for each of the **three
latest versions** of kubernetes. Each library may have slightly different code.
Because of that, contributing requires a few extra steps to make sure we can
apply the feature or bug fix to all the appropriate libraries.
We currently track each version on a separate branch:
- k8s-25/main
- k8s-24/main
- k8s-23/main
In most cases, all you need to do is make a change to the library corresponding
to latest version of kubernetes (i.e to the `k8s-25/main` branch). To do this,
you can just follow the standard process for making a pull request: fork the
repository, create your own branch, and add your changes. When you are finished,
you should run "npx projen build" to make sure all tests pass and documentation
is automatically updated.
When you clone the repo, it will check out the branch corresponding to the
latest version (`k8s-25/main`), and when you create the pull request on GitHub, it
should automatically target this branch. We will take care of backporting your
change to the other branches corresponding to cdk8s-plus-23 and cdk8s-plus-24
once the changes are merged to cdk8s-plus-25.
> Note: In some situations, you might only want to make a change to a library
targeting an older kubernetes version. For example, `IngressV1Beta` is not
available in cdk8s-plus-25, so changing it would require making a change to
cdk8s-plus-24 and cdk8s-plus-23. If you need to make a pull request to a version
of cdk8s-plus that isn't the latest version, create your branch from the corresponding
`k8s-XX/main` branch, and when you submit the pull request on GitHub, make sure the
target branch matches your base branch. The pull request should target the latest branch that your fix
applies for - so in the example above, only a PR to `k8s-24/main` is required,
and we will backport it to `k8s-23/main`.
### Developer Certificate Of Origin (DCO)
Every commit should be signed-off in compliance with the [Developer Certificate Of Origin](./DCO).
You can sign your commits by using the `git commit -s` command.
> To configure automatic signoff, see [git-hooks](./git-hooks/README.md).
## API Reference
We generate a full [API reference](./docs) automatically during build time. Make
sure to always run `yarn build` and committing the `API.md` file before
submitting a pull request.
## Project Metadata
There are several metadata files that are used by this project:
- `package.json` - Standard node project metadata file.
- `tsconfig.json` - TypeScript configuration file that controls the compilation process.
- `tsconfig.jest.json` - Configuration file used by the `jest` testing framework to enable seamless test execution without explicitly compiling source files.
- `.eslintrc.json` - [ESLint](https://eslint.org/) configuration file.
All these files are managed by the [projen](https://www.npmjs.com/package/projen) tool, and are automatically generated during build time.
Changes to these files should be performed solely via the [projenrc](./.projenrc.js) config file.