Skip to content

Kubernetes Concepts

Every exported resource declaration becomes a Kubernetes manifest document in the generated YAML. The serializer handles the translation automatically:

  • Resolves the correct apiVersion and kind from the resource type
  • Converts the export name to a kebab-case metadata.name
  • Nests user properties under spec (or at the top level for specless types like ConfigMap)
  • Merges default labels and annotations from defaultLabels()/defaultAnnotations()

Every Kubernetes resource has four standard fields:

FieldSourceExample
apiVersionResolved from resource typeapps/v1
kindResolved from resource typeDeployment
metadataFrom metadata property{ name: "my-app", labels: {...} }
specFrom spec property or remaining propsResource-specific configuration

K8s resources are organized by API group:

GroupapiVersionResources
Corev1Pod, Service, ConfigMap, Secret, Namespace, ServiceAccount
Appsapps/v1Deployment, StatefulSet, DaemonSet, ReplicaSet
Batchbatch/v1Job, CronJob
Networkingnetworking.k8s.io/v1Ingress, NetworkPolicy
RBACrbac.authorization.k8s.io/v1Role, ClusterRole, RoleBinding, ClusterRoleBinding
Autoscalingautoscaling/v2HorizontalPodAutoscaler
Policypolicy/v1PodDisruptionBudget

Nested objects like containers, probes, and volumes are expressed as property types:

import { Deployment, Container, Probe, ResourceRequirements } from "@intentius/chant-lexicon-k8s";
export const app = new Deployment({
metadata: { name: "my-app" },
spec: {
replicas: 2,
selector: { matchLabels: { app: "my-app" } },
template: {
metadata: { labels: { app: "my-app" } },
spec: {
containers: [
new Container({
name: "app",
image: "my-app:1.0",
resources: new ResourceRequirements({
limits: { cpu: "500m", memory: "256Mi" },
requests: { cpu: "100m", memory: "128Mi" },
}),
livenessProbe: new Probe({
httpGet: { path: "/healthz", port: 8080 },
initialDelaySeconds: 10,
}),
}),
],
},
},
},
});

Some K8s resources (ConfigMap, Secret, Namespace, ServiceAccount) don’t have a spec field. Their data goes directly on the manifest:

import { ConfigMap, Secret } from "@intentius/chant-lexicon-k8s";
export const config = new ConfigMap({
metadata: { name: "app-config" },
data: { DATABASE_URL: "postgres://localhost:5432/mydb" },
});
export const secret = new Secret({
metadata: { name: "app-secret" },
stringData: { API_KEY: "changeme" },
});

Use defaultLabels() and defaultAnnotations() to inject metadata into all resources:

import { defaultLabels } from "@intentius/chant-lexicon-k8s";
export const labels = defaultLabels({
"app.kubernetes.io/managed-by": "chant",
"app.kubernetes.io/part-of": "my-system",
});

Explicit labels on individual resources take precedence over defaults.

Tip: Avoid hardcoding metadata.namespace — the WK8001 lint rule will flag it. Use a config variable or pass namespace at deploy time instead.