← Back to Blog
·10 min read

Kubernetes & KRM: Infrastructure as a consistent API

KubernetesKRMGitOpsPlatform Engineering

What is the Kubernetes Resource Model?

The Kubernetes Resource Model (KRM) is the underlying design principle that makes Kubernetes extensible and consistent. Every object in Kubernetes – a Pod, a Deployment, a NetworkPolicy, a custom CRD – follows the same structure: apiVersion, kind, metadata, and spec/status.

This is not a coincidence. It is a deliberate API contract. And once you internalize it, you start seeing Kubernetes not as a container scheduler, but as a universal control plane for declarative resource management.

The anatomy of a KRM object

Every Kubernetes resource, whether built-in or custom, follows the same schema:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    ...

The key insight: spec describes the desired state, status reflects the observed state. Controllers continuously reconcile the two. This reconciliation loop is the engine behind everything in Kubernetes.

Why this matters beyond Pods and Deployments

Most teams start using Kubernetes to run containers. Over time, they discover that Kubernetes is also managing:

  • **Certificates** (cert-manager CRDs)
  • **DNS records** (external-dns)
  • **Cloud load balancers** (service type LoadBalancer, cloud-specific CRDs)
  • **Database users** (crossplane providers)
  • **Secrets** synced from external vaults (External Secrets Operator)

All of these follow KRM. The same "kubectl apply", the same GitOps pipeline, the same RBAC model. This consistency is enormously valuable in complex environments.

KRM Functions: Configuration as Code

The KRM Functions specification (originally from the kpt project, now also used by Kustomize and other tools) defines a standard for transforming and validating Kubernetes resources programmatically.

A KRM function is a container or binary that:

1. Reads a stream of Kubernetes resources as input (via stdin or a resource list)

2. Transforms or validates them

3. Outputs the modified resource list

Practical example: label injection

Instead of manually adding labels to every manifest, a KRM function can inject them automatically during the build pipeline:

yaml
apiVersion: fn.kpt.dev/v1alpha1
kind: ApplySetters
metadata:
  name: inject-common-labels
spec:
  fieldSpecs:
    - path: metadata/labels/team
      create: true
      value: platform

This runs in your CI pipeline, before anything reaches the cluster. The result is version-controlled, auditable, reproducible.

KRM in GitOps pipelines

A solid GitOps setup with KRM thinking looks like this:

1. Source of truth: Git repository with raw manifests or Helm/Kustomize bases.

2. Hydration layer: KRM functions run in CI to produce the final, fully-rendered manifests. Secrets are injected here from a vault, labels and annotations are standardized, validation runs.

3. Sync layer: A GitOps controller (Flux or ArgoCD) applies the hydrated manifests to the cluster. It only reads, never writes business logic.

4. Reconciliation: Kubernetes controllers continuously enforce the declared state.

This separation of concerns avoids the common pitfall of mixing templating, validation, and deployment logic in a single step.

Custom Resource Definitions: extending the model

CRDs allow you to introduce your own resource types that behave exactly like built-in Kubernetes resources. Combined with an operator (a controller that watches your CRD), you can model nearly any infrastructure concern:

  • A "DatabaseCluster" resource that provisions RDS instances via a cloud provider API
  • A "TenantNamespace" resource that creates a namespace with predefined RBAC, quotas, and network policies in one step
  • A "BackupPolicy" resource that configures recurring volume snapshots

The operator pattern is the natural extension of KRM: describe what you want, let a controller figure out how to get there.

What teams get wrong

Treating Kubernetes YAML as configuration files. They are API calls. The difference matters: you don't edit API calls by hand in production, you manage them in Git and apply them through a pipeline.

Storing rendered manifests in Git. Commit the source (Helm values, Kustomize overlays), not the output. The rendered form should be reproducible at any point from the source.

Skipping schema validation. KRM has a schema. Tools like kubeconform or kyverno can validate your manifests before they reach the cluster. Catching a missing required field in CI is much cheaper than a failed rollout at 2am.

CRD sprawl without ownership. Every operator you install adds CRDs to your cluster. Without a clear ownership model, you end up with dozens of CRDs nobody fully understands. Document what manages what.

Practical recommendations

  • Learn the KRM contract deeply: apiVersion/kind/metadata/spec/status and what each field means.
  • Use kustomize or kpt for managing configuration transformations rather than raw Helm templating for everything.
  • Validate manifests in CI with kubeconform against the correct Kubernetes version schema.
  • For platform teams: model internal abstractions as CRDs with operators rather than Helm charts with complex templating.
  • Keep hydration (rendering) separate from deployment (applying) in your pipelines.

Conclusion

The Kubernetes Resource Model is the foundation that makes Kubernetes composable, extensible, and auditable. Most teams use it without fully naming it. Understanding KRM explicitly – as an API contract and as a design pattern – changes how you build platforms, structure pipelines, and extend Kubernetes for your specific needs.

Once you see your infrastructure as a collection of KRM objects managed by reconciling controllers, GitOps stops being a deployment strategy and becomes the only sensible way to operate.

Questions about Kubernetes architecture or platform engineering in your environment? Get in touch.

Questions or feedback regarding this article?

Send Message