A comprehensive Pulumi resource provider for creating and managing Kubernetes resources and workloads in a running cluster
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The Kustomize integration enables you to deploy applications using Kustomize directory configurations while gaining full Pulumi lifecycle management, resource transformations, and infrastructure-as-code capabilities.
import { kustomize } from "@pulumi/kubernetes";
import * as k8s from "@pulumi/kubernetes";
// Direct Kustomize imports
import { Directory } from "@pulumi/kubernetes/kustomize/v2";Directory deploys resources from a Kustomize directory configuration, applying all transformations and overlays defined in the Kustomize setup.
class Directory extends pulumi.ComponentResource {
constructor(name: string, args: DirectoryArgs, opts?: pulumi.ComponentResourceOptions)
// Resource access methods (inherited from base collection resource)
public getResource<T extends pulumi.CustomResource>(
group: string,
version: string,
kind: string,
name: string,
namespace?: string
): T
public getResource(groupVersionKind: string, name: string, namespace?: string): pulumi.CustomResource
public getResourceProperty(groupVersionKind: string, name: string, property: string, namespace?: string): pulumi.Output<any>
}
interface DirectoryArgs {
// Directory specification
directory: pulumi.Input<string>; // Path to kustomization directory
// Namespace options
namespace?: pulumi.Input<string>; // Override namespace for all resources
// Resource options
resourcePrefix?: pulumi.Input<string>; // Prefix for resource names
// Transformation options
transformations?: pulumi.ResourceTransformation[]; // Additional Pulumi transformations
// Deployment options
skipAwait?: pulumi.Input<boolean>; // Skip waiting for resource readiness
}// Deploy from basic kustomize directory
const baseApp = new k8s.kustomize.v2.Directory("base-app", {
directory: "./kustomize/base",
});
// Deploy from overlay directory
const prodApp = new k8s.kustomize.v2.Directory("prod-app", {
directory: "./kustomize/overlays/production",
namespace: "production", // Override kustomize namespace
});
// Deploy with resource prefix
const stagingApp = new k8s.kustomize.v2.Directory("staging-app", {
directory: "./kustomize/overlays/staging",
resourcePrefix: "staging-",
});
// Deploy with Pulumi transformations
const secureApp = new k8s.kustomize.v2.Directory("secure-app", {
directory: "./kustomize/overlays/production",
transformations: [
// Add security labels
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
"security.kubernetes.io/policy": "restricted",
"app.kubernetes.io/managed-by": "pulumi",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
// Enforce resource limits
(args: any) => {
if (args.type === "kubernetes:apps/v1:Deployment") {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
spec: {
...props.spec,
template: {
...props.spec.template,
spec: {
...props.spec.template.spec,
securityContext: {
...props.spec.template.spec.securityContext,
runAsNonRoot: true,
runAsUser: 1000,
fsGroup: 2000,
},
containers: props.spec.template.spec.containers?.map((container: any) => ({
...container,
securityContext: {
...container.securityContext,
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: {
drop: ["ALL"],
},
},
resources: {
requests: {
cpu: "100m",
memory: "128Mi",
...container.resources?.requests,
},
limits: {
cpu: "500m",
memory: "512Mi",
...container.resources?.limits,
},
},
})),
},
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
});
// Deploy with skip await for faster deployment
const fastApp = new k8s.kustomize.v2.Directory("fast-app", {
directory: "./kustomize/overlays/development",
skipAwait: true, // Don't wait for resources to become ready
});kustomize/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── development/
│ ├── kustomization.yaml
│ ├── deployment-patch.yaml
│ └── ingress.yaml
├── staging/
│ ├── kustomization.yaml
│ ├── deployment-patch.yaml
│ ├── hpa.yaml
│ └── ingress.yaml
└── production/
├── kustomization.yaml
├── deployment-patch.yaml
├── hpa.yaml
├── pdb.yaml
└── ingress.yaml# kustomize/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app.kubernetes.io/name: myapp
app.kubernetes.io/component: backend
commonAnnotations:
app.kubernetes.io/version: "1.0.0"
images:
- name: myapp
newTag: latest
configMapGenerator:
- name: app-config
literals:
- PORT=8080
- LOG_LEVEL=info# kustomize/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
bases:
- ../../base
resources:
- hpa.yaml
- pdb.yaml
- ingress.yaml
patchesStrategicMerge:
- deployment-patch.yaml
images:
- name: myapp
newTag: v1.2.3
replicas:
- name: myapp-deployment
count: 5
configMapGenerator:
- name: app-config
behavior: merge
literals:
- LOG_LEVEL=warn
- REPLICAS=5
- ENVIRONMENT=production
secretGenerator:
- name: app-secrets
literals:
- DATABASE_PASSWORD=prod-password
- API_KEY=prod-api-key// Development environment
const devApp = new k8s.kustomize.v2.Directory("dev-app", {
directory: "./kustomize/overlays/development",
transformations: [
// Development-specific transformations
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
environment: "development",
"cost-center": "engineering",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
});
// Staging environment
const stagingApp = new k8s.kustomize.v2.Directory("staging-app", {
directory: "./kustomize/overlays/staging",
transformations: [
// Staging-specific transformations
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
environment: "staging",
"cost-center": "qa",
},
annotations: {
...props.metadata?.annotations,
"deployment.kubernetes.io/revision": "staging",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
});
// Production environment
const prodApp = new k8s.kustomize.v2.Directory("prod-app", {
directory: "./kustomize/overlays/production",
transformations: [
// Production-specific transformations
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
environment: "production",
"cost-center": "production",
"backup.kubernetes.io/enabled": "true",
},
annotations: {
...props.metadata?.annotations,
"deployment.kubernetes.io/revision": "production",
"monitoring.coreos.com/enabled": "true",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
// Production security hardening
(args: any) => {
if (args.type === "kubernetes:apps/v1:Deployment") {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
spec: {
...props.spec,
template: {
...props.spec.template,
spec: {
...props.spec.template.spec,
securityContext: {
runAsNonRoot: true,
runAsUser: 1000,
fsGroup: 2000,
},
containers: props.spec.template.spec.containers?.map((container: any) => ({
...container,
securityContext: {
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: { drop: ["ALL"] },
},
})),
},
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
});
// Access resources from deployments
const prodDeployment = prodApp.getResource("apps/v1", "Deployment", "myapp-deployment");
const prodService = prodApp.getResource("v1", "Service", "myapp-service");
// Export important endpoints
export const productionEndpoint = prodService.status.loadBalancer.ingress[0].hostname;
export const deploymentReplicas = prodDeployment.spec.replicas;// Deploy each microservice from its own kustomize overlay
const userService = new k8s.kustomize.v2.Directory("user-service", {
directory: "./kustomize/services/user-service/overlays/production",
namespace: "services",
transformations: [
// Service-specific transformations
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
"service.kubernetes.io/name": "user-service",
"service.kubernetes.io/version": "v2.1.0",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
});
const orderService = new k8s.kustomize.v2.Directory("order-service", {
directory: "./kustomize/services/order-service/overlays/production",
namespace: "services",
transformations: [
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
"service.kubernetes.io/name": "order-service",
"service.kubernetes.io/version": "v1.5.2",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
}, {
dependsOn: [userService], // Order service depends on user service
});
const paymentService = new k8s.kustomize.v2.Directory("payment-service", {
directory: "./kustomize/services/payment-service/overlays/production",
namespace: "services",
transformations: [
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
"service.kubernetes.io/name": "payment-service",
"service.kubernetes.io/version": "v3.0.1",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
}, {
dependsOn: [userService, orderService],
});
// Deploy shared infrastructure
const sharedInfra = new k8s.kustomize.v2.Directory("shared-infrastructure", {
directory: "./kustomize/infrastructure/production",
namespace: "infrastructure",
});
// Deploy API gateway that depends on all services
const apiGateway = new k8s.kustomize.v2.Directory("api-gateway", {
directory: "./kustomize/gateway/overlays/production",
namespace: "gateway",
}, {
dependsOn: [userService, orderService, paymentService],
});// Function to deploy from different Git branches/tags
const deployFromGit = (environment: string, gitRef: string) => {
return new k8s.kustomize.v2.Directory(`app-${environment}`, {
directory: `./kustomize/overlays/${environment}`,
transformations: [
// Add Git metadata
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
annotations: {
...props.metadata?.annotations,
"gitops.kubernetes.io/revision": gitRef,
"gitops.kubernetes.io/environment": environment,
"deployment.kubernetes.io/timestamp": new Date().toISOString(),
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
});
};
// Deploy based on Git context
const gitBranch = process.env.GIT_BRANCH || "main";
const gitCommit = process.env.GIT_COMMIT || "unknown";
const environment = pulumi.getStack();
const gitOpsDeployment = deployFromGit(environment, `${gitBranch}@${gitCommit}`);
// Export deployment metadata
export const deploymentInfo = {
environment: environment,
gitBranch: gitBranch,
gitCommit: gitCommit,
deploymentTime: new Date().toISOString(),
};// Multi-cluster deployment with region-specific configurations
const deployToRegion = (region: string, clusterEndpoint: string) => {
return new k8s.kustomize.v2.Directory(`app-${region}`, {
directory: "./kustomize/overlays/multi-region",
transformations: [
// Region-specific labels and configurations
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
"topology.kubernetes.io/region": region,
"deployment.kubernetes.io/cluster": clusterEndpoint,
},
},
}));
}
return { props: args.props, opts: args.opts };
},
// Regional service configurations
(args: any) => {
if (args.type === "v1/Service" && args.props.spec?.type === "LoadBalancer") {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
annotations: {
...props.metadata?.annotations,
"service.beta.kubernetes.io/aws-load-balancer-type":
region.startsWith("us-") ? "nlb" : "classic",
"service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled": "true",
},
},
}));
}
return { props: args.props, opts: args.opts };
},
],
});
};
// Deploy to multiple regions
const regions = [
{ name: "us-east-1", endpoint: "cluster-us-east-1.example.com" },
{ name: "us-west-2", endpoint: "cluster-us-west-2.example.com" },
{ name: "eu-west-1", endpoint: "cluster-eu-west-1.example.com" },
];
const regionalDeployments = regions.map(region =>
deployToRegion(region.name, region.endpoint)
);// Deploy application with kustomize
const app = new k8s.kustomize.v2.Directory("main-app", {
directory: "./kustomize/overlays/production",
});
// Access specific resources from the kustomize deployment
const deployment = app.getResource("apps/v1", "Deployment", "myapp");
const service = app.getResource("v1", "Service", "myapp-service");
const ingress = app.getResource("networking.k8s.io/v1", "Ingress", "myapp-ingress");
const hpa = app.getResource("autoscaling/v2", "HorizontalPodAutoscaler", "myapp-hpa");
// Get resource properties for integration with other services
const serviceClusterIP = app.getResourceProperty("v1/Service", "myapp-service", "spec.clusterIP");
const ingressStatus = app.getResourceProperty("networking.k8s.io/v1/Ingress", "myapp-ingress", "status");
// Create additional resources that depend on kustomize deployment
const monitoring = new k8s.core.v1.Service("monitoring-service", {
metadata: {
name: "app-monitoring",
namespace: "monitoring",
},
spec: {
selector: {
app: "myapp", // Matches labels from kustomize deployment
},
ports: [{
port: 9090,
targetPort: 9090,
name: "metrics",
}],
},
}, {
dependsOn: [app],
});
// Export important values
export const applicationEndpoint = ingress.status.loadBalancer.ingress[0].hostname;
export const internalServiceIP = serviceClusterIP;
export const currentReplicas = deployment.status.readyReplicas;
export const hpaStatus = hpa.status;The Kustomize integration provides a powerful way to manage complex Kubernetes applications while leveraging existing Kustomize configurations and gaining the benefits of Pulumi's infrastructure-as-code capabilities and resource management features.
Install with Tessl CLI
npx tessl i tessl/npm-pulumi--kubernetes