Skip to main content

Typed CustomResources with Provider Extensions

15 min

Pulumi can manage Kubernetes CustomResources directly, but they are untyped. Every CustomResourceDefinition (CRD) has its own schema, so the provider cannot know the shape of spec in advance.

Adding your CRDs as an extension of the kubernetes provider solves this. The provider reads the CRD's OpenAPI schema, generates a typed SDK for it, and serves the resulting resources itself. You get IDE autocompletion and compile-time type checking without installing a separate code generation tool, and the extension's resources are managed by the same provider instance as the rest of your Kubernetes resources.

This is the recommended approach for typed custom resources. If you are using crd2pulumi today, this tutorial also covers migrating to provider extensions.

What you'll learn
  • How to add Kubernetes CRDs as an extension of the kubernetes provider
  • How to generate a typed SDK from a CRD manifest with pulumi package add
  • How to use the generated extension resources across languages
  • How to migrate an existing crd2pulumi project to provider extensions
Prerequisites

Pulumi can manage Kubernetes CustomResources directly, but they are untyped. Every CustomResourceDefinition (CRD) has its own schema, so the provider cannot know the shape of spec in advance.

Adding your CRDs as an extension of the kubernetes provider solves this. The provider reads the CRD’s OpenAPI schema, generates a typed SDK for it, and serves the resulting resources itself. You get IDE autocompletion and compile-time type checking without installing a separate code generation tool, and the extension’s resources are managed by the same provider instance as the rest of your Kubernetes resources.

This is the recommended approach for typed custom resources. If you are using crd2pulumi today, see Migrating from crd2pulumi below.

Usage#

Place a CRD manifest in your program. The examples below use the Gateway API CRDs.

Terminal window
pulumi package add kubernetes --extension "name=gateway-networking crd-manifest=gateway-api-crds.yaml"

This generates an SDK under sdks/gateway-networking and records the package in Pulumi.yaml, so subsequent pulumi up runs reconstruct the same schema without re-reading the manifest.

The generated SDK draws shared types such as ObjectMeta from the base kubernetes package, so your project also needs the pulumi-kubernetes SDK as a dependency.

The supported parameters are:

ParameterRequiredDescription
crd-manifestYesPath to a YAML or JSON file containing one or more CustomResourceDefinitions. Repeat the key to supply several files.
nameNoName of the generated package. Defaults to the first manifest’s file name without its extension, falling back to crds.
versionNoVersion of the generated package. A CRD bundle has no inherent version, so any value works as long as it stays stable across runs. Defaults to 1.0.0.

A single manifest may contain multiple CRDs, and documents that are not CustomResourceDefinitions are skipped. To supply several manifests, repeat the crd-manifest key inside the same quoted string:

Terminal window
pulumi package add kubernetes --extension "name=gateway-networking crd-manifest=gateway-api-crds.yaml crd-manifest=extra-crds.yaml"

Using the generated SDK#

Extension resources are tokenized under the extension’s package name, in the form <name>:<group>/<version>:<Kind>. In the generated SDKs the module name is the group’s first segment, so gateway.networking.k8s.io/v1 becomes the gateway.v1 module.

import * as gatewayNetworking from "@pulumi/gateway-networking";
const gatewayClass = new gatewayNetworking.gateway.v1.GatewayClass("example", {
metadata: {
name: "example-class",
},
spec: {
controllerName: "example.com/gateway-controller",
},
});

Migrating from crd2pulumi#

The provider registers aliases for the crd2pulumi-style kubernetes:-namespaced tokens, so existing resources are adopted rather than replaced.

Generate the extension package from the same CRD manifests you passed to crd2pulumi:

Terminal window
pulumi package add kubernetes --extension "name=gateway-networking crd-manifest=gateway-api-crds.yaml"

Then update your imports. Resource names, property names, and nesting are unchanged, so your call sites stay as they are.

// Before
import * as crds from "./crds/nodejs";
const gatewayClass = new crds.gateway.v1.GatewayClass("example", { /* ... */ });
// After
import * as gatewayNetworking from "@pulumi/gateway-networking";
const gatewayClass = new gatewayNetworking.gateway.v1.GatewayClass("example", { /* ... */ });

Run pulumi preview and confirm the plan reports no replacements, then delete the checked-in crd2pulumi output and remove the tool from your build.

Related

The infrastructure as code platform for any cloud.