Package: pdk8s
pdk8sGenerating Kubernetes definitions (yaml) with python, inspired bycdk8s.  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 startedInstalling pdk8sPrerequisitesPython >= 3.7.Python knowledgeInstallation via PyPipdk8s is available on PyPi, you can install it with your preferred python package manage,pip,pipenv, etc:pip install pdk8sIntroThe format ofpdk8scharts 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 chartchart_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 followSemantic 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 orpdk8s.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 forchart_versionandapp_versionare copied straight from Helm ;)Getting started$pdk8sinit
chart_name[awesomechart]:WebserverExample
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:$pdk8ssynthYou will find your generated chart underdist:├── chart.py
└── dist
    ├── Chart.yaml
    ├── templates
    │   └── generated.yaml
    └── values.yamlPer defaultpdk8s synthloads thechart.pyin the current directory.  You can also use-ito specify a different python file.  Also thechart.pygenerated bypdk8s initprovides the same api aspdk8sexcept without the-ioption:$./chart.pysynthCreating RessourcesCreating a service:frompdk8simportk8sservice=k8s.Service(name="service",spec=k8s.ServiceSpec(type="LoadBalancer",ports=[k8s.ServicePort(port=80,target_port=8080)],selector={"app":"hello-k8s"}))chart=[service]Allpdk8sclasses arepydanticdata classes.  Which provides - among other things - automatic conversion for parameters, so you can just as well write:frompdk8simportk8sk8s.Service(name="service",spec={"type":"LoadBalancer","ports":[{"port":80,"target_port":8080}],"selector":{"app":"hello-k8s"}})ManipulatingAll 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 emptyk8s.Deployment().  This might change.CamelCase namesThe Kubernetes APIs use camelCase for naming attributes, while python usually uses snake_case.pdk8salso follows the snake_case convention, same ascdk8s.pdk8sprovides 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 makespdk8s.k8s.parsepossible).Importing existing chartsYou might already have templates you want to build upon, you can easily import them usingpdk8s.k8s.parse. Let's assume you have the followingchart.yaml:apiVersion:v1kind:Servicemetadata:name:servicespec:ports:-port:80targetPort:8080selector:app:hello-k8stype:LoadBalancerWith:importpdk8sfrompdk8simportk8smy_chart=k8s.parse("example/chart.yaml")my_chart[0].name="service_new"pdk8s.synth(my_chart)You get:apiVersion:v1kind:Servicemetadata:name:service_newspec:ports:-port:80targetPort:8080selector:app:hello-k8stype:LoadBalancerCompatibility to cdk8sThere are a few differences that make code between thecdk8sandpdk8sincompatible.  A good overview can be archived by comparing the following to examples:cdk8s examplepdk8s examplePure pythoncdk8sis written in TypeScript and with the power of jsii usable from other languages, as python.pdk8sis 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, apdk8sis focused on providing an awesome experience writing charts in python: Readable tracebacks, happy IDE and linters, ...Context / ConstructsCurrently, there is no equivalent of "constructs" inpdk8s.  Incdk8shighlevel 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, ...)whereselfis the context.Inpdk8sthere 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.NamesIncdk8snames are automatically made unique by adding a hash to it.pdk8sdoes not observe this behavior.  Also inpdk8snames must be provided as keyword argument.# cdk8sk8s.Service(Chart("hello"),"service")# kind: Service# apiVersion: v1# metadata:#   name: hello-service-9878228b# pdk8sk8s.Service(name='service')# kind: Service# apiVersion: v1# metadata:#   name: serviceIntOrString# cdk8sk8s.ServicePort(port=80,target_port=k8s.IntOrString.from_number(8080))# pdk8sk8s.ServicePort(port=80,target_port=8080)# k8s.IntOrString might be added for compatibility later onWhyTODO explain why this exists (NIH syndrom)Design DecisionsGenerate at build timeGenerate everything at build time and not runtime as it makes it easier for linters and other dev tools, like IDEs.Attribute caseCamelCase?NamingVersioningDevelopment and buildingCurrently, generating the code ofpdk8sdepends on a patched version ofdatamodel-code-generator.  I am working on upstreaming changes to not depend on local patches anymore.Sourceshttps://github.com/kubernetes/kubernetes/tree/master/api/openapi-spec- openapi definition.https://github.com/instrumenta/kubernetes-json-schema- JSON Schema of Kubernetes API, generated from official openapi definitions.  Used by cdk8s.