Skip to main content

CI license Code style: black

pdk8s

Generating Kubernetes definitions (yaml) with python, inspired by cdk8s. The main use case is to use those definitions with helm. This means cdk8s does replace all the templating that helm does - but helm still takes care of rolling out your changes to your cluster.

Getting started

Installing pdk8s

Prerequisites

  • Python >= 3.7.
  • Python knowledge

Installation via PyPi

pdk8s is available on PyPi, you can install it with your preferred python package manage, pip, pipenv, etc:

pip install pdk8s

Intro

The format of pdk8s charts is similar to helm charts, just that they are python instead of yaml. Your “python chart" must define the following variables:

  • name: Name of your chart
  • chart_version: This is the chart version. This version number should be incremented each time you make changes to the chart and its templates, including the app version. Versions are expected to follow Semantic Versioning.
  • app_version: This is the version number of the application being deployed. This version number should be incremented each time you make changes to the application. Versions are not expected to follow Semantic Versioning. They should reflect the version the application is using.
  • chart: Your chart. A list or pdk8s.k8s.Chart (or actually any iterable python object) of k8s resources.

If you had a déjà vu while reading - that is because the description for chart_version and app_version are copied straight from Helm ;)

Getting started

$ pdk8s init
chart_name [awesome chart]: Webserver Example
slug [webserver_example]: 
chart_version [0.1.0]: 
app_version [0.1.0]: 

You will find a new folder and files named: webserver_example/chart.py. Inside this file you will find a hello world example:

chart = [
    k8s.Deployment(name='deployment',
                    spec=k8s.DeploymentSpec(
                        replicas=2,
                        selector=k8s.LabelSelector(match_labels=label),
                        template=k8s.PodTemplateSpec(
                        metadata=k8s.ObjectMeta(labels=label),
                        spec=k8s.PodSpec(containers=[
                            k8s.Container(
                            name='hello-kubernetes',
                            image='paulbouwer/hello-kubernetes:1.7',
                            ports=[k8s.ContainerPort(container_port=8080)])]))))
]

Which you can turn into a running helm chart with:

$ pdk8s synth

You will find your generated chart under dist:

├── chart.py
└── dist
    ├── Chart.yaml
    ├── templates
    │   └── generated.yaml
    └── values.yaml

Per default pdk8s synth loads the chart.py in the current directory. You can also use -i to specify a different python file. Also the chart.py generated by pdk8s init provides the same api as pdk8s except without the -i option:

$ ./chart.py synth

Creating Ressources

Creating a service:

from pdk8s import k8s

service = k8s.Service(name="service",
            spec=k8s.ServiceSpec(
                type="LoadBalancer",
                ports=[k8s.ServicePort(port=80, target_port=8080)],
                selector={"app": "hello-k8s"}))

chart = [service]

All pdk8s classes are pydantic data classes. Which provides - among other things - automatic conversion for parameters, so you can just as well write:

from pdk8s import k8s

k8s.Service(name="service",
            spec={
                "type": "LoadBalancer",
                "ports": [{"port": 80, "target_port": 8080}],
                "selector": {"app": "hello-k8s"}})

Manipulating

All attributes can be manipulated after creation:

deployment = k8s.Deployment(name='deployment',
                    spec=k8s.DeploymentSpec(
                        replicas=2))

deployment.spec.replicas = math.randint(0, 666)

Note 1: Automatic casting is only available on creation. deployment.spec = {"replicas": 2} would not work.

Note 2: Currently all required parameters must be provided at creation time. You cannot create an empty k8s.Deployment(). This might change.

CamelCase names

The Kubernetes APIs use camelCase for naming attributes, while python usually uses snake_case. pdk8s also follows the snake_case convention, same as cdk8s.

pdk8s provides aliases for all arguments:

k8s.ServicePort(port=80, target_port=8080)
k8s.ServicePort(port=80, targetPort=8080)

Both work and result in the same result. This is for compatibility when importing from other sources (and makes pdk8s.k8s.parse possible).

Importing existing charts

You might already have templates you want to build upon, you can easily import them using pdk8s.k8s.parse. Let's assume you have the following chart.yaml:

apiVersion: v1
kind: Service
metadata:
  name: service
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-k8s
  type: LoadBalancer

With:

import pdk8s
from pdk8s import k8s

my_chart = k8s.parse("example/chart.yaml")
my_chart[0].name = "service_new"
pdk8s.synth(my_chart)

You get:

apiVersion: v1
kind: Service
metadata:
  name: service_new
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-k8s
  type: LoadBalancer

Compatibility to cdk8s

There are a few differences that make code between the cdk8s and pdk8s incompatible. A good overview can be archived by comparing the following to examples:

Pure python

cdk8s is written in TypeScript and with the power of jsii usable from other languages, as python. pdk8s is written in pure python with no bridge to other languages. This means you are limited to python and cannot reuse charts written in other languages. Therefore, a pdk8s is focused on providing an awesome experience writing charts in python: Readable tracebacks, happy IDE and linters, ...

Context / Constructs

Currently, there is no equivalent of "constructs" in pdk8s. In cdk8s highlevel objects (e.g. Service) are special: They have an extra argument (the first one) which is the context in which they are defined, e.g. k8s.Service(self, ...) where self is the context.

In pdk8s there is no special treatment of these types. There might be later on, but they would be added and not replaced.

This allows for more flexibility on how to construct your chart generator.

Names

In cdk8s names are automatically made unique by adding a hash to it. pdk8s does not observe this behavior. Also in pdk8s names must be provided as keyword argument.

# cdk8s
k8s.Service(Chart("hello"), "service")
# kind: Service
# apiVersion: v1
# metadata:
#   name: hello-service-9878228b


# pdk8s
k8s.Service(name='service')
# kind: Service
# apiVersion: v1
# metadata:
#   name: service

IntOrString

# cdk8s
k8s.ServicePort(port=80, target_port=k8s.IntOrString.from_number(8080))

# pdk8s
k8s.ServicePort(port=80, target_port=8080)
# k8s.IntOrString might be added for compatibility later on

Why

TODO explain why this exists (NIH syndrom)

Design Decisions

Generate at build time

Generate everything at build time and not runtime as it makes it easier for linters and other dev tools, like IDEs.

Attribute case

CamelCase?

Naming

Versioning

Development and building

Currently, generating the code of pdk8s depends on a patched version of datamodel-code-generator. I am working on upstreaming changes to not depend on local patches anymore.

Sources

Metadata

Release files for pdk8s 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pdk8s 0.2.2
File Size Uploaded
pdk8s-0.2.2.tar.gz 131.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pdk8s 0.2.2
File Interpreter ABI Platform
pdk8s-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 331.5 kB

Release files / pdk8s-0.2.2.tar.gz

Download URL pdk8s-0.2.2.tar.gz
Size 131.7 kB
Tags Source
SHA-256 checksum
How to use checksums
c5f6ffb489aa6528cbd0847c85987ae9a79e4d30ad6484f9a26a4097e1e9b2b5
BLAKE2b-256 checksum
How to use checksums
d236c17872e7c2fc6edf1656dc0f948eee435bf32009d0f91f3e3c304734591a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.0.9 CPython/3.8.3 Linux/5.7.7-200.fc32.x86_64

Release files / pdk8s-0.2.2-py3-none-any.whl

Download URL pdk8s-0.2.2-py3-none-any.whl
Size 199.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2f71141f52289d996c75d8debb13b420bdafe6370128fe614019e2c08938c833
BLAKE2b-256 checksum
How to use checksums
a34f617371af79e69f3cbbdac6e8cbc0d5bcecc597817fed14beaef365a908b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.0.9 CPython/3.8.3 Linux/5.7.7-200.fc32.x86_64

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page