The kubernetes:kustomize:Directory resource, part of the Pulumi Kubernetes provider, deploys a collection of Kubernetes resources defined by a kustomization directory. A newer version is available as kubernetes.kustomize/v2.Directory. This guide focuses on three capabilities: local directory deployment, remote Git repository sources, and runtime resource transformations.
Kustomize directories require a Kubernetes cluster, valid kustomization.yaml files, and the kustomize binary. The examples are intentionally small. Combine them with your own cluster configuration and resource definitions.
Deploy resources from a local kustomization directory
Most deployments start with a local directory containing a kustomization.yaml file and the manifests it references.
import * as k8s from "@pulumi/kubernetes";
const helloWorld = new k8s.kustomize.Directory("helloWorldLocal", {
directory: "./helloWorld",
});
from pulumi_kubernetes.kustomize import Directory
hello_world = Directory(
"hello-world-local",
directory="./helloWorld",
)
package main
import (
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/kustomize"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := kustomize.NewDirectory(ctx, "helloWorldLocal",
kustomize.DirectoryArgs{
Directory: pulumi.String("./helloWorld"),
},
)
if err != nil {
return err
}
return nil
})
}
using System.Threading.Tasks;
using Pulumi;
using Pulumi.Kubernetes.Kustomize;
class KustomizeStack : Stack
{
public KustomizeStack()
{
var helloWorld = new Directory("helloWorldLocal", new DirectoryArgs
{
Directory = "./helloWorld",
});
}
}
The directory property points to a local path containing your kustomization.yaml. Pulumi runs kustomize to process the directory, then applies the resulting manifests to your cluster. This works well during development when resources live alongside your Pulumi code.
Deploy resources from a remote Git repository
Teams often store kustomizations in Git to share configurations or reference upstream examples.
import * as k8s from "@pulumi/kubernetes";
const helloWorld = new k8s.kustomize.Directory("helloWorldRemote", {
directory: "https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld",
});
from pulumi_kubernetes.kustomize import Directory
hello_world = Directory(
"hello-world-remote",
directory="https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld",
)
package main
import (
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/kustomize"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := kustomize.NewDirectory(ctx, "helloWorldRemote",
kustomize.DirectoryArgs{
Directory: pulumi.String("https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld"),
},
)
if err != nil {
return err
}
return nil
})
}
using System.Threading.Tasks;
using Pulumi;
using Pulumi.Kubernetes.Kustomize;
class KustomizeStack : Stack
{
public KustomizeStack()
{
var helloWorld = new Directory("helloWorldRemote", new DirectoryArgs
{
Directory = "https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld",
});
}
}
The directory property accepts Git URLs with tree references. Pulumi fetches the repository, processes the kustomization at that path, and applies the resources. The example pins to a specific version (v3.3.1) rather than tracking a branch.
Modify resources with transformation functions
Applications often need to adjust manifests before deployment, such as changing service types or setting resource aliases.
import * as k8s from "@pulumi/kubernetes";
const helloWorld = new k8s.kustomize.Directory("helloWorldRemote", {
directory: "https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld",
transformations: [
// Make every service private to the cluster, i.e., turn all services into ClusterIP instead of LoadBalancer.
(obj: any, opts: pulumi.CustomResourceOptions) => {
if (obj.kind === "Service" && obj.apiVersion === "v1") {
if (obj.spec && obj.spec.type && obj.spec.type === "LoadBalancer") {
obj.spec.type = "ClusterIP";
}
}
},
// Set a resource alias for a previous name.
(obj: any, opts: pulumi.CustomResourceOptions) => {
if (obj.kind === "Deployment") {
opts.aliases = [{ name: "oldName" }]
}
},
// Omit a resource from the Chart by transforming the specified resource definition to an empty List.
(obj: any, opts: pulumi.CustomResourceOptions) => {
if (obj.kind === "Pod" && obj.metadata.name === "test") {
obj.apiVersion = "v1"
obj.kind = "List"
}
},
],
});
from pulumi_kubernetes.helm.v3 import Chart, ChartOpts, FetchOpts
# Make every service private to the cluster, i.e., turn all services into ClusterIP instead of LoadBalancer.
def make_service_private(obj, opts):
if obj["kind"] == "Service" and obj["apiVersion"] == "v1":
try:
t = obj["spec"]["type"]
if t == "LoadBalancer":
obj["spec"]["type"] = "ClusterIP"
except KeyError:
pass
# Set a resource alias for a previous name.
def alias(obj, opts):
if obj["kind"] == "Deployment":
opts.aliases = ["oldName"]
# Omit a resource from the Chart by transforming the specified resource definition to an empty List.
def omit_resource(obj, opts):
if obj["kind"] == "Pod" and obj["metadata"]["name"] == "test":
obj["apiVersion"] = "v1"
obj["kind"] = "List"
hello_world = Directory(
"hello-world-remote",
directory="https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld",
transformations=[make_service_private, alias, omit_resource],
)
package main
import (
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/kustomize"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/yaml"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := kustomize.NewDirectory(ctx, "helloWorldRemote",
kustomize.DirectoryArgs{
Directory: pulumi.String("https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld"),
Transformations: []yaml.Transformation{
// Make every service private to the cluster, i.e., turn all services into ClusterIP
// instead of LoadBalancer.
func(state map[string]interface{}, opts ...pulumi.ResourceOption) {
if state["kind"] == "Service" {
spec := state["spec"].(map[string]interface{})
spec["type"] = "ClusterIP"
}
},
// Set a resource alias for a previous name.
func(state map[string]interface{}, opts ...pulumi.ResourceOption) {
if state["kind"] == "Deployment" {
aliases := pulumi.Aliases([]pulumi.Alias{
{
Name: pulumi.String("oldName"),
},
})
opts = append(opts, aliases)
}
},
// Omit a resource from the Chart by transforming the specified resource definition
// to an empty List.
func(state map[string]interface{}, opts ...pulumi.ResourceOption) {
name := state["metadata"].(map[string]interface{})["name"]
if state["kind"] == "Pod" && name == "test" {
state["apiVersion"] = "core/v1"
state["kind"] = "List"
}
},
},
},
)
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Pulumi;
using Pulumi.Kubernetes.Kustomize;
class KustomizeStack : Stack
{
public KustomizeStack()
{
var helloWorld = new Directory("helloWorldRemote", new DirectoryArgs
{
Directory = "https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld",
Transformations =
{
LoadBalancerToClusterIP,
ResourceAlias,
OmitTestPod,
}
});
// Make every service private to the cluster, i.e., turn all services into ClusterIP instead of LoadBalancer.
ImmutableDictionary<string, object> LoadBalancerToClusterIP(ImmutableDictionary<string, object> obj, CustomResourceOptions opts)
{
if ((string)obj["kind"] == "Service" && (string)obj["apiVersion"] == "v1")
{
var spec = (ImmutableDictionary<string, object>)obj["spec"];
if (spec != null && (string)spec["type"] == "LoadBalancer")
{
return obj.SetItem("spec", spec.SetItem("type", "ClusterIP"));
}
}
return obj;
}
// Set a resource alias for a previous name.
ImmutableDictionary<string, object> ResourceAlias(ImmutableDictionary<string, object> obj, CustomResourceOptions opts)
{
if ((string)obj["kind"] == "Deployment")
{
opts.Aliases.Add(new Alias { Name = "oldName" });
}
return obj;
}
// Omit a resource from the Chart by transforming the specified resource definition to an empty List.
ImmutableDictionary<string, object> OmitTestPod(ImmutableDictionary<string, object> obj, CustomResourceOptions opts)
{
var metadata = (ImmutableDictionary<string, object>)obj["metadata"];
if ((string)obj["kind"] == "Pod" && (string)metadata["name"] == "test")
{
return new Dictionary<string, object>
{
["apiVersion"] = "v1",
["kind"] = "List",
["items"] = new Dictionary<string, object>(),
}.ToImmutableDictionary();
}
return obj;
}
}
}
The transformations property accepts an array of functions that receive each resource definition before it’s created. Each function can inspect the resource’s kind and apiVersion, then modify properties or set Pulumi options. The example shows three common patterns: changing service types, setting aliases for migrations, and omitting specific resources.
Beyond these examples
These snippets focus on specific Directory features: local and remote directory sources, and runtime resource transformations. They’re intentionally minimal rather than full application deployments.
The examples assume pre-existing infrastructure such as a Kubernetes cluster with configured kubeconfig, and kustomization.yaml files in referenced directories. They focus on deploying kustomizations rather than creating the underlying cluster or manifests.
To keep things focused, common Directory patterns are omitted, including:
- Resource name prefixing (resourcePrefix)
- Namespace targeting and isolation
- Dependency ordering between resources
- Output access to created resources
These omissions are intentional: the goal is to illustrate how each Directory feature is wired, not provide drop-in deployment modules. See the Kustomize Directory resource reference for all available configuration options.
Let's deploy Kubernetes Resources with Kustomize Directories
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Version & Migration
kubernetes.kustomize/v2.Directory. Consider using v2 for new projects.Directory Sources
directory property accepts both local paths (like ./helloWorld) and Git repository URLs (like https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld).https://github.com/kubernetes-sigs/kustomize/tree/v3.3.1/examples/helloWorld.Resource Customization
apiVersion to "v1" and kind to "List". The example shows omitting a Pod named “test” this way.resourcePrefix property. For example, resourcePrefix="foo" will produce resource names like “foo-resourceName”.