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 Helm integration provides powerful capabilities for deploying Helm charts as Pulumi resources without requiring Tiller. This enables declarative management of complex applications with transformation capabilities and full Pulumi lifecycle management.
import { helm } from "@pulumi/kubernetes";
import * as k8s from "@pulumi/kubernetes";
// Direct Helm imports
import { Chart } from "@pulumi/kubernetes/helm/v4";
import { Release } from "@pulumi/kubernetes/helm/v3";Chart represents a Helm chart deployment as a Pulumi ComponentResource. This is the recommended approach for new deployments.
class Chart extends pulumi.ComponentResource {
constructor(name: string, args: ChartArgs, opts?: pulumi.ComponentResourceOptions)
// Method to get specific resources from the chart
public getResource(groupVersionKind: string, name: string, namespace?: string): pulumi.CustomResource
public getResourceProperty(groupVersionKind: string, name: string, property: string, namespace?: string): pulumi.Output<any>
}
interface ChartArgs {
// Chart source options
chart: pulumi.Input<string>; // Chart name or path (required)
version?: pulumi.Input<string>; // Chart version
repositoryOpts?: pulumi.Input<RepositoryOpts>; // Repository configuration
// Values and configuration
values?: pulumi.Input<{[key: string]: any}>; // Chart values
valueYamlFiles?: pulumi.Input<pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>[]>; // YAML value files
// Deployment options
name?: pulumi.Input<string>; // Release name
namespace?: pulumi.Input<string>; // Target namespace
// Advanced options
skipCrds?: pulumi.Input<boolean>; // Skip CRD installation
skipAwait?: pulumi.Input<boolean>; // Skip waiting for resources to become ready
dependencyUpdate?: pulumi.Input<boolean>; // Update dependencies before deployment
devel?: pulumi.Input<boolean>; // Use development versions
// Security options
verify?: pulumi.Input<boolean>; // Verify chart integrity
keyring?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // Public keys for verification
// Resource management
resourcePrefix?: pulumi.Input<string>; // Prefix for auto-generated resource names
postRenderer?: pulumi.Input<PostRenderer>; // Post-renderer specification
}
interface RepositoryOpts {
repo?: pulumi.Input<string>; // Repository URL
username?: pulumi.Input<string>; // Username for private repositories
password?: pulumi.Input<string>; // Password for private repositories
caFile?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // CA file asset
certFile?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // Certificate file asset
keyFile?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // Key file asset
}// Deploy NGINX Ingress Controller from Bitnami repository
const nginxIngress = new k8s.helm.v4.Chart("nginx-ingress", {
chart: "nginx-ingress-controller",
version: "9.3.12",
repositoryOpts: {
repo: "https://charts.bitnami.com/bitnami",
},
namespace: "ingress-nginx",
createNamespace: true,
values: {
replicaCount: 2,
service: {
type: "LoadBalancer",
annotations: {
"service.beta.kubernetes.io/aws-load-balancer-type": "nlb",
},
},
metrics: {
enabled: true,
serviceMonitor: {
enabled: true,
},
},
resources: {
requests: {
cpu: "100m",
memory: "128Mi",
},
limits: {
cpu: "500m",
memory: "512Mi",
},
},
},
});
// Deploy PostgreSQL from local chart
const postgresql = new k8s.helm.v4.Chart("postgresql", {
path: "./charts/postgresql",
namespace: "database",
createNamespace: true,
values: {
auth: {
postgresPassword: "secure-password",
database: "myapp",
},
persistence: {
enabled: true,
storageClass: "fast-ssd",
size: "20Gi",
},
metrics: {
enabled: true,
},
},
dependencyUpdate: true,
});
// Deploy with multiple values files
const monitoring = new k8s.helm.v4.Chart("prometheus", {
chart: "kube-prometheus-stack",
version: "45.7.1",
repositoryOpts: {
repo: "https://prometheus-community.github.io/helm-charts",
},
namespace: "monitoring",
createNamespace: true,
valuesFiles: [
"./helm-values/prometheus-base.yaml",
"./helm-values/prometheus-prod.yaml",
],
values: {
// Override specific values
grafana: {
adminPassword: "admin-secret",
persistence: {
enabled: true,
size: "10Gi",
},
},
prometheus: {
prometheusSpec: {
retention: "30d",
storageSpec: {
volumeClaimTemplate: {
spec: {
storageClassName: "fast-ssd",
accessModes: ["ReadWriteOnce"],
resources: {
requests: {
storage: "50Gi",
},
},
},
},
},
},
},
},
timeout: 600, // 10 minutes
atomic: true,
});
// Deploy with resource transformations
const app = new k8s.helm.v4.Chart("my-app", {
chart: "my-app",
repositoryOpts: {
repo: "https://charts.example.com",
},
values: {
image: {
tag: "v1.2.3",
},
},
transformations: [
// Add common labels to all resources
(args: any) => {
if (args.type.startsWith("kubernetes:")) {
args.props = pulumi.output(args.props).apply((props: any) => ({
...props,
metadata: {
...props.metadata,
labels: {
...props.metadata?.labels,
"app.kubernetes.io/managed-by": "pulumi",
"environment": "production",
},
},
}));
}
return {
props: args.props,
opts: args.opts,
};
},
// Modify resource requirements
(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,
containers: props.spec.template.spec.containers?.map((container: any) => ({
...container,
resources: {
requests: {
cpu: "100m",
memory: "128Mi",
},
limits: {
cpu: "500m",
memory: "512Mi",
},
},
})),
},
},
},
}));
}
return {
props: args.props,
opts: args.opts,
};
},
],
});
// Private repository with authentication
const privateChart = new k8s.helm.v4.Chart("private-app", {
chart: "private-app",
version: "1.0.0",
repositoryOpts: {
repo: "https://private-charts.company.com",
username: "chart-user",
password: "chart-password",
},
namespace: "production",
values: {
image: {
pullSecrets: ["private-registry-secret"],
},
},
});// Access specific resources from deployed chart
const nginxDeployment = nginxIngress.getResource("apps/v1/Deployment", "nginx-ingress-controller");
const nginxService = nginxIngress.getResource("v1/Service", "nginx-ingress-controller");
// Get specific properties from resources
const serviceIP = nginxIngress.getResourceProperty("v1/Service", "nginx-ingress-controller", "status");
// Export important values
export const ingressControllerIP = nginxService.status.loadBalancer.ingress[0].ip;
export const prometheusURL = monitoring.getResourceProperty("v1/Service", "prometheus-server", "spec").apply(spec =>
`http://${spec.clusterIP}:${spec.ports[0].port}`
);Release represents a Helm release using Helm v3 APIs. This provides compatibility with existing Helm workflows.
class Release extends pulumi.CustomResource {
constructor(name: string, args: ReleaseArgs, opts?: pulumi.ResourceOptions)
public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): Release
// Output properties
public readonly status!: pulumi.Output<string>;
public readonly version!: pulumi.Output<number>;
public readonly namespace!: pulumi.Output<string>;
public readonly values!: pulumi.Output<{[key: string]: any}>;
public readonly chart!: pulumi.Output<string>;
public readonly manifest!: pulumi.Output<string>;
}
interface ReleaseArgs {
// Chart source
chart?: pulumi.Input<string>; // Chart name or path
version?: pulumi.Input<string>; // Chart version
repositoryOpts?: pulumi.Input<RepositoryOpts>; // Repository configuration
// Release configuration
name?: pulumi.Input<string>; // Release name (defaults to resource name)
namespace?: pulumi.Input<string>; // Target namespace
createNamespace?: pulumi.Input<boolean>; // Create namespace if needed
// Values
values?: pulumi.Input<{[key: string]: any}>; // Release values
valuesFiles?: pulumi.Input<string[]>; // Values files
// Deployment options
timeout?: pulumi.Input<number>; // Timeout in seconds
atomic?: pulumi.Input<boolean>; // Atomic deployment
cleanupOnFail?: pulumi.Input<boolean>; // Cleanup on failure
dependencyUpdate?: pulumi.Input<boolean>; // Update dependencies
description?: pulumi.Input<string>; // Release description
devel?: pulumi.Input<boolean>; // Use development versions
disableOpenapiValidation?: pulumi.Input<boolean>; // Skip OpenAPI validation
disableWebhooks?: pulumi.Input<boolean>; // Disable admission webhooks
forceUpdate?: pulumi.Input<boolean>; // Force update
lint?: pulumi.Input<boolean>; // Lint chart before deployment
maxHistory?: pulumi.Input<number>; // Maximum revision history
recreatePods?: pulumi.Input<boolean>; // Recreate pods
renderSubchartNotes?: pulumi.Input<boolean>; // Render subchart notes
replace?: pulumi.Input<boolean>; // Replace existing release
resetValues?: pulumi.Input<boolean>; // Reset values to defaults
reuseValues?: pulumi.Input<boolean>; // Reuse previous release values
skipCrds?: pulumi.Input<boolean>; // Skip CRDs
skipTests?: pulumi.Input<boolean>; // Skip tests
verify?: pulumi.Input<boolean>; // Verify chart
waitForJobs?: pulumi.Input<boolean>; // Wait for jobs to complete
}// Basic release deployment
const nginxRelease = new k8s.helm.v3.Release("nginx", {
chart: "nginx",
repositoryOpts: {
repo: "https://charts.bitnami.com/bitnami",
},
version: "13.2.12",
namespace: "web",
createNamespace: true,
values: {
replicaCount: 3,
service: {
type: "LoadBalancer",
},
},
});
// Release with comprehensive configuration
const redisRelease = new k8s.helm.v3.Release("redis-cluster", {
chart: "redis",
repositoryOpts: {
repo: "https://charts.bitnami.com/bitnami",
},
version: "17.3.7",
namespace: "cache",
createNamespace: true,
values: {
architecture: "replication",
auth: {
enabled: true,
password: "redis-password",
},
master: {
persistence: {
enabled: true,
size: "8Gi",
storageClass: "fast-ssd",
},
},
replica: {
replicaCount: 2,
persistence: {
enabled: true,
size: "8Gi",
storageClass: "fast-ssd",
},
},
metrics: {
enabled: true,
serviceMonitor: {
enabled: true,
},
},
},
timeout: 600,
atomic: true,
cleanupOnFail: true,
dependencyUpdate: true,
maxHistory: 5,
waitForJobs: true,
});
// Release from local chart
const customAppRelease = new k8s.helm.v3.Release("custom-app", {
chart: "./charts/custom-app",
namespace: "applications",
createNamespace: true,
valuesFiles: [
"./values/base.yaml",
"./values/production.yaml",
],
values: {
image: {
tag: "v2.1.0",
},
ingress: {
enabled: true,
hosts: ["app.example.com"],
tls: [{
secretName: "app-tls",
hosts: ["app.example.com"],
}],
},
},
dependencyUpdate: true,
lint: true,
});// Database layer
const database = new k8s.helm.v4.Chart("database", {
chart: "postgresql",
repositoryOpts: {
repo: "https://charts.bitnami.com/bitnami",
},
namespace: "data",
createNamespace: true,
values: {
auth: {
database: "appdb",
},
persistence: {
size: "20Gi",
storageClass: "database-ssd",
},
},
});
// Cache layer
const cache = new k8s.helm.v4.Chart("redis", {
chart: "redis",
repositoryOpts: {
repo: "https://charts.bitnami.com/bitnami",
},
namespace: "cache",
createNamespace: true,
values: {
architecture: "standalone",
master: {
persistence: {
size: "5Gi",
},
},
},
});
// Application layer (depends on database and cache)
const application = new k8s.helm.v4.Chart("app", {
chart: "./charts/myapp",
namespace: "application",
createNamespace: true,
values: {
database: {
host: database.getResourceProperty("v1/Service", "postgresql", "metadata").name,
port: 5432,
},
redis: {
host: cache.getResourceProperty("v1/Service", "redis-master", "metadata").name,
port: 6379,
},
},
}, {
dependsOn: [database, cache],
});// Deploy operator first
const operator = new k8s.helm.v4.Chart("my-operator", {
chart: "my-operator",
repositoryOpts: {
repo: "https://charts.example.com",
},
namespace: "operators",
createNamespace: true,
values: {
image: {
tag: "v1.0.0",
},
resources: {
limits: {
cpu: "200m",
memory: "256Mi",
},
},
},
timeout: 300,
});
// Deploy application using custom resources
const customResourceApp = new k8s.helm.v4.Chart("custom-app", {
chart: "custom-app",
repositoryOpts: {
repo: "https://charts.example.com",
},
namespace: "applications",
createNamespace: true,
values: {
customResource: {
enabled: true,
spec: {
replicas: 3,
version: "v2.0.0",
},
},
},
}, {
dependsOn: [operator],
});// Base configuration
const baseValues = {
replicaCount: 1,
image: {
repository: "myapp",
tag: "latest",
pullPolicy: "Always",
},
service: {
type: "ClusterIP",
port: 80,
},
resources: {
requests: {
cpu: "100m",
memory: "128Mi",
},
},
};
// Development environment
const devValues = {
...baseValues,
replicaCount: 1,
image: {
...baseValues.image,
tag: "dev",
},
ingress: {
enabled: true,
hosts: ["dev-app.example.com"],
},
};
// Production environment
const prodValues = {
...baseValues,
replicaCount: 3,
image: {
...baseValues.image,
tag: "v1.0.0",
pullPolicy: "IfNotPresent",
},
service: {
...baseValues.service,
type: "LoadBalancer",
},
resources: {
requests: {
cpu: "200m",
memory: "256Mi",
},
limits: {
cpu: "500m",
memory: "512Mi",
},
},
ingress: {
enabled: true,
hosts: ["app.example.com"],
tls: [{
secretName: "app-tls",
hosts: ["app.example.com"],
}],
},
autoscaling: {
enabled: true,
minReplicas: 3,
maxReplicas: 10,
targetCPUUtilizationPercentage: 70,
},
};
// Deploy based on environment
const environment = pulumi.getStack();
const values = environment === "production" ? prodValues : devValues;
const app = new k8s.helm.v4.Chart("myapp", {
chart: "myapp",
repositoryOpts: {
repo: "https://charts.example.com",
},
namespace: `myapp-${environment}`,
createNamespace: true,
values: values,
});helm.v4.Chart over helm.v3.Release for new deploymentsThe Helm integration provides powerful capabilities for managing complex Kubernetes applications while maintaining the benefits of Pulumi's infrastructure-as-code approach, enabling reliable and repeatable deployments across environments.
Install with Tessl CLI
npx tessl i tessl/npm-pulumi--kubernetes