or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-resources.mdhelm-integration.mdindex.mdkustomize-integration.mdnetworking-resources.mdprovider-configuration.mdrbac-resources.mdstorage-resources.mdworkload-resources.mdyaml-deployment.md

helm-integration.mddocs/

0

# Helm Integration

1

2

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.

3

4

## Package Import

5

6

```typescript { .api }

7

import { helm } from "@pulumi/kubernetes";

8

import * as k8s from "@pulumi/kubernetes";

9

10

// Direct Helm imports

11

import { Chart } from "@pulumi/kubernetes/helm/v4";

12

import { Release } from "@pulumi/kubernetes/helm/v3";

13

```

14

15

## Chart (helm/v4) - Recommended

16

17

Chart represents a Helm chart deployment as a Pulumi ComponentResource. This is the recommended approach for new deployments.

18

19

```typescript { .api }

20

class Chart extends pulumi.ComponentResource {

21

constructor(name: string, args: ChartArgs, opts?: pulumi.ComponentResourceOptions)

22

23

// Method to get specific resources from the chart

24

public getResource(groupVersionKind: string, name: string, namespace?: string): pulumi.CustomResource

25

public getResourceProperty(groupVersionKind: string, name: string, property: string, namespace?: string): pulumi.Output<any>

26

}

27

28

interface ChartArgs {

29

// Chart source options

30

chart: pulumi.Input<string>; // Chart name or path (required)

31

version?: pulumi.Input<string>; // Chart version

32

repositoryOpts?: pulumi.Input<RepositoryOpts>; // Repository configuration

33

34

// Values and configuration

35

values?: pulumi.Input<{[key: string]: any}>; // Chart values

36

valueYamlFiles?: pulumi.Input<pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>[]>; // YAML value files

37

38

// Deployment options

39

name?: pulumi.Input<string>; // Release name

40

namespace?: pulumi.Input<string>; // Target namespace

41

42

// Advanced options

43

skipCrds?: pulumi.Input<boolean>; // Skip CRD installation

44

skipAwait?: pulumi.Input<boolean>; // Skip waiting for resources to become ready

45

dependencyUpdate?: pulumi.Input<boolean>; // Update dependencies before deployment

46

devel?: pulumi.Input<boolean>; // Use development versions

47

48

// Security options

49

verify?: pulumi.Input<boolean>; // Verify chart integrity

50

keyring?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // Public keys for verification

51

52

// Resource management

53

resourcePrefix?: pulumi.Input<string>; // Prefix for auto-generated resource names

54

postRenderer?: pulumi.Input<PostRenderer>; // Post-renderer specification

55

}

56

57

interface RepositoryOpts {

58

repo?: pulumi.Input<string>; // Repository URL

59

username?: pulumi.Input<string>; // Username for private repositories

60

password?: pulumi.Input<string>; // Password for private repositories

61

caFile?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // CA file asset

62

certFile?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // Certificate file asset

63

keyFile?: pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive>; // Key file asset

64

}

65

```

66

67

### Chart Usage Examples

68

69

```typescript { .api }

70

// Deploy NGINX Ingress Controller from Bitnami repository

71

const nginxIngress = new k8s.helm.v4.Chart("nginx-ingress", {

72

chart: "nginx-ingress-controller",

73

version: "9.3.12",

74

repositoryOpts: {

75

repo: "https://charts.bitnami.com/bitnami",

76

},

77

namespace: "ingress-nginx",

78

createNamespace: true,

79

values: {

80

replicaCount: 2,

81

service: {

82

type: "LoadBalancer",

83

annotations: {

84

"service.beta.kubernetes.io/aws-load-balancer-type": "nlb",

85

},

86

},

87

metrics: {

88

enabled: true,

89

serviceMonitor: {

90

enabled: true,

91

},

92

},

93

resources: {

94

requests: {

95

cpu: "100m",

96

memory: "128Mi",

97

},

98

limits: {

99

cpu: "500m",

100

memory: "512Mi",

101

},

102

},

103

},

104

});

105

106

// Deploy PostgreSQL from local chart

107

const postgresql = new k8s.helm.v4.Chart("postgresql", {

108

path: "./charts/postgresql",

109

namespace: "database",

110

createNamespace: true,

111

values: {

112

auth: {

113

postgresPassword: "secure-password",

114

database: "myapp",

115

},

116

persistence: {

117

enabled: true,

118

storageClass: "fast-ssd",

119

size: "20Gi",

120

},

121

metrics: {

122

enabled: true,

123

},

124

},

125

dependencyUpdate: true,

126

});

127

128

// Deploy with multiple values files

129

const monitoring = new k8s.helm.v4.Chart("prometheus", {

130

chart: "kube-prometheus-stack",

131

version: "45.7.1",

132

repositoryOpts: {

133

repo: "https://prometheus-community.github.io/helm-charts",

134

},

135

namespace: "monitoring",

136

createNamespace: true,

137

valuesFiles: [

138

"./helm-values/prometheus-base.yaml",

139

"./helm-values/prometheus-prod.yaml",

140

],

141

values: {

142

// Override specific values

143

grafana: {

144

adminPassword: "admin-secret",

145

persistence: {

146

enabled: true,

147

size: "10Gi",

148

},

149

},

150

prometheus: {

151

prometheusSpec: {

152

retention: "30d",

153

storageSpec: {

154

volumeClaimTemplate: {

155

spec: {

156

storageClassName: "fast-ssd",

157

accessModes: ["ReadWriteOnce"],

158

resources: {

159

requests: {

160

storage: "50Gi",

161

},

162

},

163

},

164

},

165

},

166

},

167

},

168

},

169

timeout: 600, // 10 minutes

170

atomic: true,

171

});

172

173

// Deploy with resource transformations

174

const app = new k8s.helm.v4.Chart("my-app", {

175

chart: "my-app",

176

repositoryOpts: {

177

repo: "https://charts.example.com",

178

},

179

values: {

180

image: {

181

tag: "v1.2.3",

182

},

183

},

184

transformations: [

185

// Add common labels to all resources

186

(args: any) => {

187

if (args.type.startsWith("kubernetes:")) {

188

args.props = pulumi.output(args.props).apply((props: any) => ({

189

...props,

190

metadata: {

191

...props.metadata,

192

labels: {

193

...props.metadata?.labels,

194

"app.kubernetes.io/managed-by": "pulumi",

195

"environment": "production",

196

},

197

},

198

}));

199

}

200

return {

201

props: args.props,

202

opts: args.opts,

203

};

204

},

205

// Modify resource requirements

206

(args: any) => {

207

if (args.type === "kubernetes:apps/v1:Deployment") {

208

args.props = pulumi.output(args.props).apply((props: any) => ({

209

...props,

210

spec: {

211

...props.spec,

212

template: {

213

...props.spec.template,

214

spec: {

215

...props.spec.template.spec,

216

containers: props.spec.template.spec.containers?.map((container: any) => ({

217

...container,

218

resources: {

219

requests: {

220

cpu: "100m",

221

memory: "128Mi",

222

},

223

limits: {

224

cpu: "500m",

225

memory: "512Mi",

226

},

227

},

228

})),

229

},

230

},

231

},

232

}));

233

}

234

return {

235

props: args.props,

236

opts: args.opts,

237

};

238

},

239

],

240

});

241

242

// Private repository with authentication

243

const privateChart = new k8s.helm.v4.Chart("private-app", {

244

chart: "private-app",

245

version: "1.0.0",

246

repositoryOpts: {

247

repo: "https://private-charts.company.com",

248

username: "chart-user",

249

password: "chart-password",

250

},

251

namespace: "production",

252

values: {

253

image: {

254

pullSecrets: ["private-registry-secret"],

255

},

256

},

257

});

258

```

259

260

### Accessing Chart Resources

261

262

```typescript { .api }

263

// Access specific resources from deployed chart

264

const nginxDeployment = nginxIngress.getResource("apps/v1/Deployment", "nginx-ingress-controller");

265

const nginxService = nginxIngress.getResource("v1/Service", "nginx-ingress-controller");

266

267

// Get specific properties from resources

268

const serviceIP = nginxIngress.getResourceProperty("v1/Service", "nginx-ingress-controller", "status");

269

270

// Export important values

271

export const ingressControllerIP = nginxService.status.loadBalancer.ingress[0].ip;

272

export const prometheusURL = monitoring.getResourceProperty("v1/Service", "prometheus-server", "spec").apply(spec =>

273

`http://${spec.clusterIP}:${spec.ports[0].port}`

274

);

275

```

276

277

## Release (helm/v3)

278

279

Release represents a Helm release using Helm v3 APIs. This provides compatibility with existing Helm workflows.

280

281

```typescript { .api }

282

class Release extends pulumi.CustomResource {

283

constructor(name: string, args: ReleaseArgs, opts?: pulumi.ResourceOptions)

284

285

public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): Release

286

287

// Output properties

288

public readonly status!: pulumi.Output<string>;

289

public readonly version!: pulumi.Output<number>;

290

public readonly namespace!: pulumi.Output<string>;

291

public readonly values!: pulumi.Output<{[key: string]: any}>;

292

public readonly chart!: pulumi.Output<string>;

293

public readonly manifest!: pulumi.Output<string>;

294

}

295

296

interface ReleaseArgs {

297

// Chart source

298

chart?: pulumi.Input<string>; // Chart name or path

299

version?: pulumi.Input<string>; // Chart version

300

repositoryOpts?: pulumi.Input<RepositoryOpts>; // Repository configuration

301

302

// Release configuration

303

name?: pulumi.Input<string>; // Release name (defaults to resource name)

304

namespace?: pulumi.Input<string>; // Target namespace

305

createNamespace?: pulumi.Input<boolean>; // Create namespace if needed

306

307

// Values

308

values?: pulumi.Input<{[key: string]: any}>; // Release values

309

valuesFiles?: pulumi.Input<string[]>; // Values files

310

311

// Deployment options

312

timeout?: pulumi.Input<number>; // Timeout in seconds

313

atomic?: pulumi.Input<boolean>; // Atomic deployment

314

cleanupOnFail?: pulumi.Input<boolean>; // Cleanup on failure

315

dependencyUpdate?: pulumi.Input<boolean>; // Update dependencies

316

description?: pulumi.Input<string>; // Release description

317

devel?: pulumi.Input<boolean>; // Use development versions

318

disableOpenapiValidation?: pulumi.Input<boolean>; // Skip OpenAPI validation

319

disableWebhooks?: pulumi.Input<boolean>; // Disable admission webhooks

320

forceUpdate?: pulumi.Input<boolean>; // Force update

321

lint?: pulumi.Input<boolean>; // Lint chart before deployment

322

maxHistory?: pulumi.Input<number>; // Maximum revision history

323

recreatePods?: pulumi.Input<boolean>; // Recreate pods

324

renderSubchartNotes?: pulumi.Input<boolean>; // Render subchart notes

325

replace?: pulumi.Input<boolean>; // Replace existing release

326

resetValues?: pulumi.Input<boolean>; // Reset values to defaults

327

reuseValues?: pulumi.Input<boolean>; // Reuse previous release values

328

skipCrds?: pulumi.Input<boolean>; // Skip CRDs

329

skipTests?: pulumi.Input<boolean>; // Skip tests

330

verify?: pulumi.Input<boolean>; // Verify chart

331

waitForJobs?: pulumi.Input<boolean>; // Wait for jobs to complete

332

}

333

```

334

335

### Release Usage Examples

336

337

```typescript { .api }

338

// Basic release deployment

339

const nginxRelease = new k8s.helm.v3.Release("nginx", {

340

chart: "nginx",

341

repositoryOpts: {

342

repo: "https://charts.bitnami.com/bitnami",

343

},

344

version: "13.2.12",

345

namespace: "web",

346

createNamespace: true,

347

values: {

348

replicaCount: 3,

349

service: {

350

type: "LoadBalancer",

351

},

352

},

353

});

354

355

// Release with comprehensive configuration

356

const redisRelease = new k8s.helm.v3.Release("redis-cluster", {

357

chart: "redis",

358

repositoryOpts: {

359

repo: "https://charts.bitnami.com/bitnami",

360

},

361

version: "17.3.7",

362

namespace: "cache",

363

createNamespace: true,

364

values: {

365

architecture: "replication",

366

auth: {

367

enabled: true,

368

password: "redis-password",

369

},

370

master: {

371

persistence: {

372

enabled: true,

373

size: "8Gi",

374

storageClass: "fast-ssd",

375

},

376

},

377

replica: {

378

replicaCount: 2,

379

persistence: {

380

enabled: true,

381

size: "8Gi",

382

storageClass: "fast-ssd",

383

},

384

},

385

metrics: {

386

enabled: true,

387

serviceMonitor: {

388

enabled: true,

389

},

390

},

391

},

392

timeout: 600,

393

atomic: true,

394

cleanupOnFail: true,

395

dependencyUpdate: true,

396

maxHistory: 5,

397

waitForJobs: true,

398

});

399

400

// Release from local chart

401

const customAppRelease = new k8s.helm.v3.Release("custom-app", {

402

chart: "./charts/custom-app",

403

namespace: "applications",

404

createNamespace: true,

405

valuesFiles: [

406

"./values/base.yaml",

407

"./values/production.yaml",

408

],

409

values: {

410

image: {

411

tag: "v2.1.0",

412

},

413

ingress: {

414

enabled: true,

415

hosts: ["app.example.com"],

416

tls: [{

417

secretName: "app-tls",

418

hosts: ["app.example.com"],

419

}],

420

},

421

},

422

dependencyUpdate: true,

423

lint: true,

424

});

425

```

426

427

## Advanced Helm Patterns

428

429

### Multi-Chart Application

430

431

```typescript { .api }

432

// Database layer

433

const database = new k8s.helm.v4.Chart("database", {

434

chart: "postgresql",

435

repositoryOpts: {

436

repo: "https://charts.bitnami.com/bitnami",

437

},

438

namespace: "data",

439

createNamespace: true,

440

values: {

441

auth: {

442

database: "appdb",

443

},

444

persistence: {

445

size: "20Gi",

446

storageClass: "database-ssd",

447

},

448

},

449

});

450

451

// Cache layer

452

const cache = new k8s.helm.v4.Chart("redis", {

453

chart: "redis",

454

repositoryOpts: {

455

repo: "https://charts.bitnami.com/bitnami",

456

},

457

namespace: "cache",

458

createNamespace: true,

459

values: {

460

architecture: "standalone",

461

master: {

462

persistence: {

463

size: "5Gi",

464

},

465

},

466

},

467

});

468

469

// Application layer (depends on database and cache)

470

const application = new k8s.helm.v4.Chart("app", {

471

chart: "./charts/myapp",

472

namespace: "application",

473

createNamespace: true,

474

values: {

475

database: {

476

host: database.getResourceProperty("v1/Service", "postgresql", "metadata").name,

477

port: 5432,

478

},

479

redis: {

480

host: cache.getResourceProperty("v1/Service", "redis-master", "metadata").name,

481

port: 6379,

482

},

483

},

484

}, {

485

dependsOn: [database, cache],

486

});

487

```

488

489

### Chart with Custom Resources

490

491

```typescript { .api }

492

// Deploy operator first

493

const operator = new k8s.helm.v4.Chart("my-operator", {

494

chart: "my-operator",

495

repositoryOpts: {

496

repo: "https://charts.example.com",

497

},

498

namespace: "operators",

499

createNamespace: true,

500

values: {

501

image: {

502

tag: "v1.0.0",

503

},

504

resources: {

505

limits: {

506

cpu: "200m",

507

memory: "256Mi",

508

},

509

},

510

},

511

timeout: 300,

512

});

513

514

// Deploy application using custom resources

515

const customResourceApp = new k8s.helm.v4.Chart("custom-app", {

516

chart: "custom-app",

517

repositoryOpts: {

518

repo: "https://charts.example.com",

519

},

520

namespace: "applications",

521

createNamespace: true,

522

values: {

523

customResource: {

524

enabled: true,

525

spec: {

526

replicas: 3,

527

version: "v2.0.0",

528

},

529

},

530

},

531

}, {

532

dependsOn: [operator],

533

});

534

```

535

536

### Environment-Specific Configurations

537

538

```typescript { .api }

539

// Base configuration

540

const baseValues = {

541

replicaCount: 1,

542

image: {

543

repository: "myapp",

544

tag: "latest",

545

pullPolicy: "Always",

546

},

547

service: {

548

type: "ClusterIP",

549

port: 80,

550

},

551

resources: {

552

requests: {

553

cpu: "100m",

554

memory: "128Mi",

555

},

556

},

557

};

558

559

// Development environment

560

const devValues = {

561

...baseValues,

562

replicaCount: 1,

563

image: {

564

...baseValues.image,

565

tag: "dev",

566

},

567

ingress: {

568

enabled: true,

569

hosts: ["dev-app.example.com"],

570

},

571

};

572

573

// Production environment

574

const prodValues = {

575

...baseValues,

576

replicaCount: 3,

577

image: {

578

...baseValues.image,

579

tag: "v1.0.0",

580

pullPolicy: "IfNotPresent",

581

},

582

service: {

583

...baseValues.service,

584

type: "LoadBalancer",

585

},

586

resources: {

587

requests: {

588

cpu: "200m",

589

memory: "256Mi",

590

},

591

limits: {

592

cpu: "500m",

593

memory: "512Mi",

594

},

595

},

596

ingress: {

597

enabled: true,

598

hosts: ["app.example.com"],

599

tls: [{

600

secretName: "app-tls",

601

hosts: ["app.example.com"],

602

}],

603

},

604

autoscaling: {

605

enabled: true,

606

minReplicas: 3,

607

maxReplicas: 10,

608

targetCPUUtilizationPercentage: 70,

609

},

610

};

611

612

// Deploy based on environment

613

const environment = pulumi.getStack();

614

const values = environment === "production" ? prodValues : devValues;

615

616

const app = new k8s.helm.v4.Chart("myapp", {

617

chart: "myapp",

618

repositoryOpts: {

619

repo: "https://charts.example.com",

620

},

621

namespace: `myapp-${environment}`,

622

createNamespace: true,

623

values: values,

624

});

625

```

626

627

## Best Practices

628

629

### Chart Management Best Practices

630

631

1. **Use Chart v4**: Prefer `helm.v4.Chart` over `helm.v3.Release` for new deployments

632

2. **Version Pinning**: Always specify chart versions for production deployments

633

3. **Values Organization**: Use separate values files for different environments

634

4. **Resource Limits**: Always set resource requests and limits

635

5. **Transformations**: Use transformations for cross-cutting concerns like labels and annotations

636

637

### Security Best Practices

638

639

1. **Private Repositories**: Use credentials for private chart repositories

640

2. **Values Encryption**: Encrypt sensitive values using Pulumi secrets

641

3. **RBAC**: Ensure proper service account and RBAC configurations

642

4. **Image Security**: Use specific image tags and trusted registries

643

5. **Network Policies**: Apply network policies to restrict traffic

644

645

### Operations Best Practices

646

647

1. **Atomic Deployments**: Use atomic deployments for production

648

2. **Timeouts**: Set appropriate timeouts for chart deployments

649

3. **Dependencies**: Properly manage chart dependencies and update them

650

4. **Monitoring**: Monitor chart deployments and resource health

651

5. **Rollback Strategy**: Plan for rollback scenarios and test rollback procedures

652

653

The 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.