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

kustomize-integration.mddocs/

0

# Kustomize Integration

1

2

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.

3

4

## Package Import

5

6

```typescript { .api }

7

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

8

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

9

10

// Direct Kustomize imports

11

import { Directory } from "@pulumi/kubernetes/kustomize/v2";

12

```

13

14

## Directory (kustomize/v2)

15

16

Directory deploys resources from a Kustomize directory configuration, applying all transformations and overlays defined in the Kustomize setup.

17

18

```typescript { .api }

19

class Directory extends pulumi.ComponentResource {

20

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

21

22

// Resource access methods (inherited from base collection resource)

23

public getResource<T extends pulumi.CustomResource>(

24

group: string,

25

version: string,

26

kind: string,

27

name: string,

28

namespace?: string

29

): T

30

31

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

32

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

33

}

34

35

interface DirectoryArgs {

36

// Directory specification

37

directory: pulumi.Input<string>; // Path to kustomization directory

38

39

// Namespace options

40

namespace?: pulumi.Input<string>; // Override namespace for all resources

41

42

// Resource options

43

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

44

45

// Transformation options

46

transformations?: pulumi.ResourceTransformation[]; // Additional Pulumi transformations

47

48

// Deployment options

49

skipAwait?: pulumi.Input<boolean>; // Skip waiting for resource readiness

50

}

51

```

52

53

### Directory Usage Examples

54

55

```typescript { .api }

56

// Deploy from basic kustomize directory

57

const baseApp = new k8s.kustomize.v2.Directory("base-app", {

58

directory: "./kustomize/base",

59

});

60

61

// Deploy from overlay directory

62

const prodApp = new k8s.kustomize.v2.Directory("prod-app", {

63

directory: "./kustomize/overlays/production",

64

namespace: "production", // Override kustomize namespace

65

});

66

67

// Deploy with resource prefix

68

const stagingApp = new k8s.kustomize.v2.Directory("staging-app", {

69

directory: "./kustomize/overlays/staging",

70

resourcePrefix: "staging-",

71

});

72

73

// Deploy with Pulumi transformations

74

const secureApp = new k8s.kustomize.v2.Directory("secure-app", {

75

directory: "./kustomize/overlays/production",

76

transformations: [

77

// Add security labels

78

(args: any) => {

79

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

80

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

81

...props,

82

metadata: {

83

...props.metadata,

84

labels: {

85

...props.metadata?.labels,

86

"security.kubernetes.io/policy": "restricted",

87

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

88

},

89

},

90

}));

91

}

92

return { props: args.props, opts: args.opts };

93

},

94

// Enforce resource limits

95

(args: any) => {

96

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

97

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

98

...props,

99

spec: {

100

...props.spec,

101

template: {

102

...props.spec.template,

103

spec: {

104

...props.spec.template.spec,

105

securityContext: {

106

...props.spec.template.spec.securityContext,

107

runAsNonRoot: true,

108

runAsUser: 1000,

109

fsGroup: 2000,

110

},

111

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

112

...container,

113

securityContext: {

114

...container.securityContext,

115

allowPrivilegeEscalation: false,

116

readOnlyRootFilesystem: true,

117

capabilities: {

118

drop: ["ALL"],

119

},

120

},

121

resources: {

122

requests: {

123

cpu: "100m",

124

memory: "128Mi",

125

...container.resources?.requests,

126

},

127

limits: {

128

cpu: "500m",

129

memory: "512Mi",

130

...container.resources?.limits,

131

},

132

},

133

})),

134

},

135

},

136

},

137

}));

138

}

139

return { props: args.props, opts: args.opts };

140

},

141

],

142

});

143

144

// Deploy with skip await for faster deployment

145

const fastApp = new k8s.kustomize.v2.Directory("fast-app", {

146

directory: "./kustomize/overlays/development",

147

skipAwait: true, // Don't wait for resources to become ready

148

});

149

```

150

151

## Kustomize Directory Structure Examples

152

153

### Basic Application Structure

154

155

```

156

kustomize/

157

├── base/

158

│ ├── kustomization.yaml

159

│ ├── deployment.yaml

160

│ ├── service.yaml

161

│ └── configmap.yaml

162

└── overlays/

163

├── development/

164

│ ├── kustomization.yaml

165

│ ├── deployment-patch.yaml

166

│ └── ingress.yaml

167

├── staging/

168

│ ├── kustomization.yaml

169

│ ├── deployment-patch.yaml

170

│ ├── hpa.yaml

171

│ └── ingress.yaml

172

└── production/

173

├── kustomization.yaml

174

├── deployment-patch.yaml

175

├── hpa.yaml

176

├── pdb.yaml

177

└── ingress.yaml

178

```

179

180

### Base Kustomization Example

181

182

```yaml

183

# kustomize/base/kustomization.yaml

184

apiVersion: kustomize.config.k8s.io/v1beta1

185

kind: Kustomization

186

187

resources:

188

- deployment.yaml

189

- service.yaml

190

- configmap.yaml

191

192

commonLabels:

193

app.kubernetes.io/name: myapp

194

app.kubernetes.io/component: backend

195

196

commonAnnotations:

197

app.kubernetes.io/version: "1.0.0"

198

199

images:

200

- name: myapp

201

newTag: latest

202

203

configMapGenerator:

204

- name: app-config

205

literals:

206

- PORT=8080

207

- LOG_LEVEL=info

208

```

209

210

### Overlay Kustomization Example

211

212

```yaml

213

# kustomize/overlays/production/kustomization.yaml

214

apiVersion: kustomize.config.k8s.io/v1beta1

215

kind: Kustomization

216

217

namespace: production

218

219

bases:

220

- ../../base

221

222

resources:

223

- hpa.yaml

224

- pdb.yaml

225

- ingress.yaml

226

227

patchesStrategicMerge:

228

- deployment-patch.yaml

229

230

images:

231

- name: myapp

232

newTag: v1.2.3

233

234

replicas:

235

- name: myapp-deployment

236

count: 5

237

238

configMapGenerator:

239

- name: app-config

240

behavior: merge

241

literals:

242

- LOG_LEVEL=warn

243

- REPLICAS=5

244

- ENVIRONMENT=production

245

246

secretGenerator:

247

- name: app-secrets

248

literals:

249

- DATABASE_PASSWORD=prod-password

250

- API_KEY=prod-api-key

251

```

252

253

## Complete Application Examples

254

255

### Multi-Environment Deployment

256

257

```typescript { .api }

258

// Development environment

259

const devApp = new k8s.kustomize.v2.Directory("dev-app", {

260

directory: "./kustomize/overlays/development",

261

transformations: [

262

// Development-specific transformations

263

(args: any) => {

264

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

265

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

266

...props,

267

metadata: {

268

...props.metadata,

269

labels: {

270

...props.metadata?.labels,

271

environment: "development",

272

"cost-center": "engineering",

273

},

274

},

275

}));

276

}

277

return { props: args.props, opts: args.opts };

278

},

279

],

280

});

281

282

// Staging environment

283

const stagingApp = new k8s.kustomize.v2.Directory("staging-app", {

284

directory: "./kustomize/overlays/staging",

285

transformations: [

286

// Staging-specific transformations

287

(args: any) => {

288

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

289

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

290

...props,

291

metadata: {

292

...props.metadata,

293

labels: {

294

...props.metadata?.labels,

295

environment: "staging",

296

"cost-center": "qa",

297

},

298

annotations: {

299

...props.metadata?.annotations,

300

"deployment.kubernetes.io/revision": "staging",

301

},

302

},

303

}));

304

}

305

return { props: args.props, opts: args.opts };

306

},

307

],

308

});

309

310

// Production environment

311

const prodApp = new k8s.kustomize.v2.Directory("prod-app", {

312

directory: "./kustomize/overlays/production",

313

transformations: [

314

// Production-specific transformations

315

(args: any) => {

316

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

317

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

318

...props,

319

metadata: {

320

...props.metadata,

321

labels: {

322

...props.metadata?.labels,

323

environment: "production",

324

"cost-center": "production",

325

"backup.kubernetes.io/enabled": "true",

326

},

327

annotations: {

328

...props.metadata?.annotations,

329

"deployment.kubernetes.io/revision": "production",

330

"monitoring.coreos.com/enabled": "true",

331

},

332

},

333

}));

334

}

335

return { props: args.props, opts: args.opts };

336

},

337

// Production security hardening

338

(args: any) => {

339

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

340

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

341

...props,

342

spec: {

343

...props.spec,

344

template: {

345

...props.spec.template,

346

spec: {

347

...props.spec.template.spec,

348

securityContext: {

349

runAsNonRoot: true,

350

runAsUser: 1000,

351

fsGroup: 2000,

352

},

353

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

354

...container,

355

securityContext: {

356

allowPrivilegeEscalation: false,

357

readOnlyRootFilesystem: true,

358

capabilities: { drop: ["ALL"] },

359

},

360

})),

361

},

362

},

363

},

364

}));

365

}

366

return { props: args.props, opts: args.opts };

367

},

368

],

369

});

370

371

// Access resources from deployments

372

const prodDeployment = prodApp.getResource("apps/v1", "Deployment", "myapp-deployment");

373

const prodService = prodApp.getResource("v1", "Service", "myapp-service");

374

375

// Export important endpoints

376

export const productionEndpoint = prodService.status.loadBalancer.ingress[0].hostname;

377

export const deploymentReplicas = prodDeployment.spec.replicas;

378

```

379

380

### Microservices Application with Kustomize

381

382

```typescript { .api }

383

// Deploy each microservice from its own kustomize overlay

384

const userService = new k8s.kustomize.v2.Directory("user-service", {

385

directory: "./kustomize/services/user-service/overlays/production",

386

namespace: "services",

387

transformations: [

388

// Service-specific transformations

389

(args: any) => {

390

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

391

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

392

...props,

393

metadata: {

394

...props.metadata,

395

labels: {

396

...props.metadata?.labels,

397

"service.kubernetes.io/name": "user-service",

398

"service.kubernetes.io/version": "v2.1.0",

399

},

400

},

401

}));

402

}

403

return { props: args.props, opts: args.opts };

404

},

405

],

406

});

407

408

const orderService = new k8s.kustomize.v2.Directory("order-service", {

409

directory: "./kustomize/services/order-service/overlays/production",

410

namespace: "services",

411

transformations: [

412

(args: any) => {

413

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

414

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

415

...props,

416

metadata: {

417

...props.metadata,

418

labels: {

419

...props.metadata?.labels,

420

"service.kubernetes.io/name": "order-service",

421

"service.kubernetes.io/version": "v1.5.2",

422

},

423

},

424

}));

425

}

426

return { props: args.props, opts: args.opts };

427

},

428

],

429

}, {

430

dependsOn: [userService], // Order service depends on user service

431

});

432

433

const paymentService = new k8s.kustomize.v2.Directory("payment-service", {

434

directory: "./kustomize/services/payment-service/overlays/production",

435

namespace: "services",

436

transformations: [

437

(args: any) => {

438

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

439

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

440

...props,

441

metadata: {

442

...props.metadata,

443

labels: {

444

...props.metadata?.labels,

445

"service.kubernetes.io/name": "payment-service",

446

"service.kubernetes.io/version": "v3.0.1",

447

},

448

},

449

}));

450

}

451

return { props: args.props, opts: args.opts };

452

},

453

],

454

}, {

455

dependsOn: [userService, orderService],

456

});

457

458

// Deploy shared infrastructure

459

const sharedInfra = new k8s.kustomize.v2.Directory("shared-infrastructure", {

460

directory: "./kustomize/infrastructure/production",

461

namespace: "infrastructure",

462

});

463

464

// Deploy API gateway that depends on all services

465

const apiGateway = new k8s.kustomize.v2.Directory("api-gateway", {

466

directory: "./kustomize/gateway/overlays/production",

467

namespace: "gateway",

468

}, {

469

dependsOn: [userService, orderService, paymentService],

470

});

471

```

472

473

### GitOps Integration

474

475

```typescript { .api }

476

// Function to deploy from different Git branches/tags

477

const deployFromGit = (environment: string, gitRef: string) => {

478

return new k8s.kustomize.v2.Directory(`app-${environment}`, {

479

directory: `./kustomize/overlays/${environment}`,

480

transformations: [

481

// Add Git metadata

482

(args: any) => {

483

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

484

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

485

...props,

486

metadata: {

487

...props.metadata,

488

annotations: {

489

...props.metadata?.annotations,

490

"gitops.kubernetes.io/revision": gitRef,

491

"gitops.kubernetes.io/environment": environment,

492

"deployment.kubernetes.io/timestamp": new Date().toISOString(),

493

},

494

},

495

}));

496

}

497

return { props: args.props, opts: args.opts };

498

},

499

],

500

});

501

};

502

503

// Deploy based on Git context

504

const gitBranch = process.env.GIT_BRANCH || "main";

505

const gitCommit = process.env.GIT_COMMIT || "unknown";

506

const environment = pulumi.getStack();

507

508

const gitOpsDeployment = deployFromGit(environment, `${gitBranch}@${gitCommit}`);

509

510

// Export deployment metadata

511

export const deploymentInfo = {

512

environment: environment,

513

gitBranch: gitBranch,

514

gitCommit: gitCommit,

515

deploymentTime: new Date().toISOString(),

516

};

517

```

518

519

### Advanced Kustomize Patterns

520

521

```typescript { .api }

522

// Multi-cluster deployment with region-specific configurations

523

const deployToRegion = (region: string, clusterEndpoint: string) => {

524

return new k8s.kustomize.v2.Directory(`app-${region}`, {

525

directory: "./kustomize/overlays/multi-region",

526

transformations: [

527

// Region-specific labels and configurations

528

(args: any) => {

529

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

530

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

531

...props,

532

metadata: {

533

...props.metadata,

534

labels: {

535

...props.metadata?.labels,

536

"topology.kubernetes.io/region": region,

537

"deployment.kubernetes.io/cluster": clusterEndpoint,

538

},

539

},

540

}));

541

}

542

return { props: args.props, opts: args.opts };

543

},

544

// Regional service configurations

545

(args: any) => {

546

if (args.type === "v1/Service" && args.props.spec?.type === "LoadBalancer") {

547

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

548

...props,

549

metadata: {

550

...props.metadata,

551

annotations: {

552

...props.metadata?.annotations,

553

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

554

region.startsWith("us-") ? "nlb" : "classic",

555

"service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled": "true",

556

},

557

},

558

}));

559

}

560

return { props: args.props, opts: args.opts };

561

},

562

],

563

});

564

};

565

566

// Deploy to multiple regions

567

const regions = [

568

{ name: "us-east-1", endpoint: "cluster-us-east-1.example.com" },

569

{ name: "us-west-2", endpoint: "cluster-us-west-2.example.com" },

570

{ name: "eu-west-1", endpoint: "cluster-eu-west-1.example.com" },

571

];

572

573

const regionalDeployments = regions.map(region =>

574

deployToRegion(region.name, region.endpoint)

575

);

576

```

577

578

### Resource Access and Integration

579

580

```typescript { .api }

581

// Deploy application with kustomize

582

const app = new k8s.kustomize.v2.Directory("main-app", {

583

directory: "./kustomize/overlays/production",

584

});

585

586

// Access specific resources from the kustomize deployment

587

const deployment = app.getResource("apps/v1", "Deployment", "myapp");

588

const service = app.getResource("v1", "Service", "myapp-service");

589

const ingress = app.getResource("networking.k8s.io/v1", "Ingress", "myapp-ingress");

590

const hpa = app.getResource("autoscaling/v2", "HorizontalPodAutoscaler", "myapp-hpa");

591

592

// Get resource properties for integration with other services

593

const serviceClusterIP = app.getResourceProperty("v1/Service", "myapp-service", "spec.clusterIP");

594

const ingressStatus = app.getResourceProperty("networking.k8s.io/v1/Ingress", "myapp-ingress", "status");

595

596

// Create additional resources that depend on kustomize deployment

597

const monitoring = new k8s.core.v1.Service("monitoring-service", {

598

metadata: {

599

name: "app-monitoring",

600

namespace: "monitoring",

601

},

602

spec: {

603

selector: {

604

app: "myapp", // Matches labels from kustomize deployment

605

},

606

ports: [{

607

port: 9090,

608

targetPort: 9090,

609

name: "metrics",

610

}],

611

},

612

}, {

613

dependsOn: [app],

614

});

615

616

// Export important values

617

export const applicationEndpoint = ingress.status.loadBalancer.ingress[0].hostname;

618

export const internalServiceIP = serviceClusterIP;

619

export const currentReplicas = deployment.status.readyReplicas;

620

export const hpaStatus = hpa.status;

621

```

622

623

## Best Practices

624

625

### Kustomize Structure Best Practices

626

627

1. **Base and Overlays**: Use clear separation between base configurations and environment-specific overlays

628

2. **Common Resources**: Keep shared resources in the base and environment-specific resources in overlays

629

3. **Naming Conventions**: Use consistent naming conventions across all kustomize files

630

4. **Documentation**: Document the purpose and structure of each kustomization

631

5. **Testing**: Test kustomize configurations locally before deploying

632

633

### Integration Best Practices

634

635

1. **Resource Access**: Use the resource access methods for inter-resource dependencies

636

2. **Transformations**: Use Pulumi transformations for concerns not handled by Kustomize

637

3. **Dependencies**: Use Pulumi dependencies to ensure proper deployment order

638

4. **Environment Management**: Use separate overlays for different environments

639

5. **Version Control**: Keep kustomize configurations in version control alongside Pulumi code

640

641

### Security and Operations Best Practices

642

643

1. **Secret Management**: Use Pulumi secrets for sensitive data rather than Kustomize secretGenerator

644

2. **Resource Limits**: Ensure all containers have resource requests and limits

645

3. **Security Context**: Apply appropriate security contexts and policies

646

4. **Monitoring**: Include monitoring and observability configurations

647

5. **Backup Strategy**: Implement backup strategies for persistent data

648

649

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.