KCL and KPM: The Art of Managing Kubernetes Configurations
A Practical Guide to Simplifying Kubernetes Configuration Management Using KCL and KPM.
What is KCL
KCL is an open-source, constraint-based record and functional programming language. It leverages mature programming language technology and practices to facilitate the writing of many complex configurations. KCL is designed to improve modularity, scalability, and stability around configuration, simplify logic writing, speed up automation, and create a thriving extension ecosystem. To learn more about specific KCL usage scenarios, please refer to the KCL website. This blog will not go into too much detail about that.
What is KPM
KPM is the KCL package manager. KPM downloads your KCL package’s dependencies, compiles your KCL packages, makes packages, and uploads them to the kcl package registry.
Why use KCL
When we manage the Kubernetes resources, we often maintain it by hand, or use Helm and Kustomize tools to maintain our YAML configurations or configuration templates, and then apply the resources to the cluster through kubectl tools. However, as a “YAML engineer”, maintaining YAML configuration every day is undoubtedly trivial and boring, and prone to errors. For example as follows:
apiVersion: apps/v1
kind: Deployment
metadata: ... # Omit
spec:
selector:
matchlabels:
cell: RZ00A
replicas: 2
template:
metadata: ... # Omit
spec:
tolerations:
- effect: NoSchedules
key: is-over-quota
operator: Equal
value: 'true'
containers:
- name: test-app
image: images.example/app:v1 # Wrong ident
resources:
limits:
cpu: 2 # Wrong type. The type of cpu should be str
memory: 4Gi
# Field missing: ephemeral-storage
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: is-over-quota
operator: In
values:
- 'true'
- The structured data in YAML is untyped and lacks validation methods, so the validity of all data cannot be checked immediately.
- YAML has poor programming ability. It is easy to write incorrect indents and has no common code organization methods such as logical judgment. It is easy to write a large number of repeated configurations and difficult to maintain.
- The design of Kubernetes is complex, and it is difficult for users to understand all the details, such as the
toleration
andaffinity
fields in the above configuration. If users do not understand the scheduling logic, it may be wrongly omitted or superfluous added.
Therefore, KCL expects to solve the following problems in Kubernetes YAML resource management:
- Use production-level high-performance programming language to write code to improve the flexibility of configuration, such as conditional statements, loops, functions, package management and other features to improve the ability of configuration reuse.
- Improve the ability of configuration semantic verification at the code level, such as optional/required fields, types, ranges, and other configuration checks.
- Provide the ability to write, combine, and abstract configuration blocks, such as structure definition, structure inheritance, constraint definition, etc.
How to use KCL to generate and manage Kubernetes resources
First, you can visit the KCL Quick Start to download and install KCL according to the instructions, and then prepare a Kubernetes environment.
Generate Kubernetes manifests
We can write the following KCL code and name it main.k
. KCL is inspired by Python. Its basic syntax is very close to Python, which is easy to learn. The configuration mode is simple, k [: T] = v
, where k
denotes the configured attribute name, v
denotes the configured attribute value and : T
denotes an optional type annotation.
apiVersion = "apps/v1"
kind = "Deployment"
metadata = {
name = "nginx"
labels.app = name
}
spec = {
replicas = 3
selector.matchLabels = metadata.labels
template.metadata.labels = metadata.labels
template.spec.containers = [
{
name = metadata.name
image = "${metadata.name}:1.14.2"
ports = [{ containerPort = 80 }]
}
]
}
In the above KCL code, we declare the apiVersion
, kind
, metadata
, spec
and other variables of a Kubernetes Deployment
resource, and assign the corresponding contents respectively. In particular, we will assign metadata.labels
fields are reused in spec.selector.matchLabels
and spec.template.metadata.labels
field. It can be seen that, compared with YAML, the data structure defined by KCL is more compact, and configuration reuse can be realized by defining local variables.
We can get a Kubernetes YAML file by executing the following command line
kcl main.k
The output is
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Of course, we can use KCL together with kubectl and other tools. Let’s execute the following commands and see the result:
$ kcl main.k | kubectl apply -f -
deployment.apps/nginx-deployment configured
It can be seen from the command line that it is completely consistent with the deployment experience of using YAML configuration and kubectl application directly.
Check the deployment status through kubectl
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 15s
How to use KPM to manage Kubernetes resources
You can get kpm
from the kpm github release and set the kpm
binary path to the environment variable PATH.
# KPM_INSTALLATION_PATH is the path of the `kpm` binary.
export PATH=$KPM_INSTALLATION_PATH:$PATH
Use the following command to ensure that you install kpm
successfully.
kpm --help
Set environment variables
You need to set an environment variable KPM_HOME
to hold the KCL packages downloaded by kpm
.
Note: kpm
does not support downloading external packages into the current kcl package directory, so make sure that '$KPM_HOME' is not in the same directory as the current KCL package.
# The directory to save the packages downloaded by Kpm.
export KPM_HOME="/user/xxx/xxx/path"
To ensure that KCLVM can find the packages downloaded by kpm
, you need to set the environment variables $KCLVM_VENDOR_HOME
and point it to $KPM_HOME
for KCLVM after downloading KCLVM.
export KCLVM_VENDOR_HOME=$KPM_HOME
Init an empty KCL package
First, create an empty folder for the KCL package and go into that folder.
mkdir my_package # create an empty folder 'my_package'
cd my_package # go into the folder 'my_package'
Create a new kcl package named my_package
.
kpm init my_package
kpm
will create two kcl package configuration files: kcl.mod
and kcl.mod.lock
in the directory where you executed the command.
- my_package
|- kcl.mod
|- kcl.mod.lock
|- # You can write your kcl program directly in this directory.
kcl.mod.lock
is the file generated by kpm
to fix the dependency version. Do not modify this file manually.
kpm
initializes kcl.mod
for an empty project as shown below:
[package]
name = "my_package"
edition = "0.0.1"
version = "0.0.1"
Add a dependency from Git Registry
If you need to use the KCL model in Konfig to write the kcl program.
kpm add -git https://github.com/awesome-kusion/konfig.git -tag v0.0.1
You can see that kpm
adds the dependency you just added to kcl.mod.
[package]
name = "my_package"
edition = "0.0.1"
version = "0.0.1"
[dependencies]
# 'konfig' is the package name
# If you want to use the contents of this package,
# you need to write the import statment with the package name 'konfig' as the prefix.
konfig = { git = "https://github.com/awesome-kusion/konfig.git", tag = "v0.0.1" }
Write a KCL program that uses the content in konfig
Create the main.k
file in the current package.
- my_package
|- kcl.mod
|- kcl.mod.lock
|- main.k # Your KCL program.
And write the following into the main.k
file.
import konfig.base.pkg.kusion_kubernetes.api.apps.v1 as apps
demo = apps.Deployment {
metadata.name = "nginx-deployment"
spec = {
replicas = 3
selector.matchLabels = {
app = "nginx"
}
template.metadata.labels = {
app = "nginx"
}
template.spec.containers = [
{
name = "nginx"
image = "nginx:1.14.2"
ports = [
{containerPort = 80}
]
}
]
}
}
Use the kpm
compile the kcl package
You can use kpm
to compile the main.k
file you just wrote.
kcl main.k -S demo
If you get the following output, congratulations !, you have successfully compiled your kcl package with kpm
.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: "nginx:1.14.2"
name: nginx
ports:
- containerPort: 80
Integration OAM into KCL
Kubevela and Open Application Model (OAM) brings modular, extensible, and portable design for modeling application deployment with higher level yet consistent API.
For the same ways, You can use OAM in KCL code directly just like follows:
import konfig.base.pkg.kusion_kubevela.v1beta1
app: v1beta1.Application {
metadata.name = "webservice-app"
spec.components = [{
name = "front-end"
type = "webservice"
properties = {
image = "oamdev/testapp:v1"
cmd = ["node", "server.js"]
ports = [{port = 8080, expose = True}]
exposeType = "NodePort"
cpu = "0.5"
memory = str(512Mi)
}
traits = [
{
type = "scaler"
properties.replicas = 1
}
]
}]
}
Run the following commands
$ kcl main.k -S app
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: webservice-app
spec:
components:
- name: front-end
properties:
image: "oamdev/testapp:v1"
cmd:
- node
- server.js
ports:
- port: 8080
expose: true
exposeType: NodePort
cpu: "0.5"
memory: 512Mi
traits:
- properties:
replicas: 1
type: scaler
type: webservice
Want More?
See KCL Website and KCL v0.4.6 Release Note for more information.
- KCL Website: https://kcl-lang.github.io/
- KCL v0.4.6 Release Note: https://medium.com/dev-genius/kcl-v0-4-6-is-coming-rust-based-ide-extension-helm-kustomize-kpt-integrations-cc785ad0156c