0
# YAML Deployment
1
2
The YAML deployment capabilities enable you to deploy Kubernetes resources from existing YAML manifests while gaining full Pulumi integration, resource management, and transformation capabilities.
3
4
## Package Import
5
6
```typescript { .api }
7
import { yaml } from "@pulumi/kubernetes";
8
import * as k8s from "@pulumi/kubernetes";
9
10
// Direct YAML imports
11
import { ConfigFile, ConfigGroup } from "@pulumi/kubernetes/yaml/v2";
12
```
13
14
## CollectionComponentResource Base Class
15
16
Base class that provides strongly-typed resource lookup for YAML-based collections.
17
18
```typescript { .api }
19
abstract class CollectionComponentResource extends pulumi.ComponentResource {
20
// Strongly-typed resource lookup method
21
public getResource<T extends pulumi.CustomResource>(
22
group: string,
23
version: string,
24
kind: string,
25
name: string,
26
namespace?: string
27
): T
28
29
// Get resource by GroupVersionKind string
30
public getResource(groupVersionKind: string, name: string, namespace?: string): pulumi.CustomResource
31
32
// Get specific property from resource
33
public getResourceProperty(groupVersionKind: string, name: string, property: string, namespace?: string): pulumi.Output<any>
34
}
35
```
36
37
## ConfigFile (yaml/v2)
38
39
ConfigFile deploys resources from a single YAML manifest file with full Pulumi lifecycle management.
40
41
```typescript { .api }
42
class ConfigFile extends CollectionComponentResource {
43
constructor(name: string, args: ConfigFileArgs, opts?: pulumi.ComponentResourceOptions)
44
45
// Resource access methods inherited from CollectionComponentResource
46
}
47
48
interface ConfigFileArgs {
49
// File specification
50
file: pulumi.Input<string>; // Path to YAML file (required)
51
52
// Resource configuration
53
resourcePrefix?: pulumi.Input<string>; // Prefix for resource names
54
55
// Deployment options
56
skipAwait?: pulumi.Input<boolean>; // Skip waiting for resource readiness
57
}
58
```
59
60
### ConfigFile Usage Examples
61
62
```typescript { .api }
63
// Deploy from single YAML file
64
const nginxManifest = new k8s.yaml.v2.ConfigFile("nginx-manifest", {
65
file: "./manifests/nginx-deployment.yaml",
66
});
67
68
// Deploy from multiple YAML files
69
const appManifests = new k8s.yaml.v2.ConfigFile("app-manifests", {
70
files: [
71
"./manifests/deployment.yaml",
72
"./manifests/service.yaml",
73
"./manifests/ingress.yaml",
74
],
75
});
76
77
// Deploy with namespace override
78
const devApp = new k8s.yaml.v2.ConfigFile("dev-app", {
79
file: "./manifests/app.yaml",
80
namespace: "development", // Override namespace in YAML
81
});
82
83
// Deploy with resource name prefix
84
const prefixedApp = new k8s.yaml.v2.ConfigFile("prefixed-app", {
85
file: "./manifests/app.yaml",
86
resourcePrefix: "staging-", // Prefix all resource names
87
});
88
89
// Deploy with await disabled for faster deployment
90
const fastApp = new k8s.yaml.v2.ConfigFile("fast-app", {
91
file: "./manifests/app.yaml",
92
skipAwait: true, // Don't wait for resources to become ready
93
});
94
```
95
96
### Accessing Resources from ConfigFile
97
98
```typescript { .api }
99
// Get specific resources from the deployed manifest
100
const deployment = appManifests.getResource("apps/v1", "Deployment", "nginx-deployment");
101
const service = appManifests.getResource("v1", "Service", "nginx-service");
102
103
// Using generic method with type assertion
104
const ingress = appManifests.getResource("networking.k8s.io/v1/Ingress", "nginx-ingress");
105
106
// Get resource properties
107
const serviceIP = appManifests.getResourceProperty("v1/Service", "nginx-service", "status");
108
const deploymentReplicas = appManifests.getResourceProperty("apps/v1/Deployment", "nginx-deployment", "spec.replicas");
109
110
// Export important values
111
export const loadBalancerIP = service.status.loadBalancer.ingress[0].ip;
112
export const ingressHostname = ingress.status.loadBalancer.ingress[0].hostname;
113
```
114
115
## ConfigGroup (yaml/v2)
116
117
ConfigGroup deploys resources from multiple YAML files or directories with pattern matching capabilities.
118
119
```typescript { .api }
120
class ConfigGroup extends CollectionComponentResource {
121
constructor(name: string, args: ConfigGroupArgs, opts?: pulumi.ComponentResourceOptions)
122
123
// Resource access methods inherited from CollectionComponentResource
124
}
125
126
interface ConfigGroupArgs {
127
// File specification
128
files?: pulumi.Input<pulumi.Input<string>[]>; // Array of file paths (supports glob patterns)
129
130
// Content specification
131
yaml?: pulumi.Input<string>; // YAML content string
132
objs?: pulumi.Input<any[]>; // Array of Kubernetes objects
133
134
// Resource configuration
135
resourcePrefix?: pulumi.Input<string>; // Prefix for resource names
136
137
// Deployment options
138
skipAwait?: pulumi.Input<boolean>; // Skip waiting for resource readiness
139
}
140
```
141
142
### ConfigGroup Usage Examples
143
144
```typescript { .api }
145
// Deploy all YAML files from directory using glob pattern
146
const allManifests = new k8s.yaml.v2.ConfigGroup("all-manifests", {
147
files: ["./manifests/**/*.yaml"],
148
namespace: "applications",
149
});
150
151
// Deploy specific files
152
const coreServices = new k8s.yaml.v2.ConfigGroup("core-services", {
153
files: [
154
"./manifests/database/*.yaml",
155
"./manifests/cache/redis.yaml",
156
"./manifests/monitoring/prometheus.yaml",
157
],
158
namespace: "infrastructure",
159
});
160
161
// Deploy from YAML content strings
162
const inlineManifests = new k8s.yaml.v2.ConfigGroup("inline-manifests", {
163
yaml: [
164
`
165
apiVersion: v1
166
kind: ConfigMap
167
metadata:
168
name: app-config
169
data:
170
database.url: "postgresql://db:5432/app"
171
redis.host: "redis:6379"
172
`,
173
`
174
apiVersion: apps/v1
175
kind: Deployment
176
metadata:
177
name: app
178
spec:
179
replicas: 3
180
selector:
181
matchLabels:
182
app: myapp
183
template:
184
metadata:
185
labels:
186
app: myapp
187
spec:
188
containers:
189
- name: app
190
image: myapp:v1.0
191
ports:
192
- containerPort: 8080
193
`,
194
],
195
});
196
197
// Deploy from Kubernetes objects
198
const objectManifests = new k8s.yaml.v2.ConfigGroup("object-manifests", {
199
objs: [
200
{
201
apiVersion: "v1",
202
kind: "Namespace",
203
metadata: {
204
name: "my-application",
205
labels: {
206
environment: "production",
207
},
208
},
209
},
210
{
211
apiVersion: "v1",
212
kind: "Secret",
213
metadata: {
214
name: "app-secrets",
215
namespace: "my-application",
216
},
217
type: "Opaque",
218
stringData: {
219
username: "admin",
220
password: "secret-password",
221
},
222
},
223
],
224
});
225
226
// Environment-specific deployment
227
const envManifests = new k8s.yaml.v2.ConfigGroup("env-manifests", {
228
files: [
229
"./manifests/base/*.yaml",
230
`./manifests/overlays/${pulumi.getStack()}/*.yaml`,
231
],
232
namespace: `app-${pulumi.getStack()}`,
233
resourcePrefix: `${pulumi.getStack()}-`,
234
});
235
```
236
237
### Advanced ConfigGroup Patterns
238
239
```typescript { .api }
240
// Multi-environment deployment with transformations
241
const createEnvironmentDeployment = (environment: string) => {
242
return new k8s.yaml.v2.ConfigGroup(`app-${environment}`, {
243
files: [
244
"./manifests/base/*.yaml",
245
`./manifests/overlays/${environment}/*.yaml`,
246
],
247
namespace: `app-${environment}`,
248
transformations: [
249
// Environment-specific labels
250
(args: any) => {
251
if (args.type.startsWith("kubernetes:")) {
252
args.props = pulumi.output(args.props).apply((props: any) => ({
253
...props,
254
metadata: {
255
...props.metadata,
256
labels: {
257
...props.metadata?.labels,
258
environment: environment,
259
"deployment.kubernetes.io/revision": "1",
260
},
261
},
262
}));
263
}
264
return { props: args.props, opts: args.opts };
265
},
266
// Environment-specific resource scaling
267
(args: any) => {
268
if (args.type === "kubernetes:apps/v1:Deployment") {
269
const replicas = environment === "production" ? 3 : 1;
270
args.props = pulumi.output(args.props).apply((props: any) => ({
271
...props,
272
spec: {
273
...props.spec,
274
replicas: replicas,
275
},
276
}));
277
}
278
return { props: args.props, opts: args.opts };
279
},
280
],
281
});
282
};
283
284
// Deploy to multiple environments
285
const devDeployment = createEnvironmentDeployment("development");
286
const stagingDeployment = createEnvironmentDeployment("staging");
287
const prodDeployment = createEnvironmentDeployment("production");
288
```
289
290
## Complete Application Examples
291
292
### Microservices Application
293
294
```typescript { .api }
295
// Deploy database layer
296
const databaseLayer = new k8s.yaml.v2.ConfigGroup("database", {
297
files: ["./manifests/database/*.yaml"],
298
namespace: "data",
299
transformations: [
300
(args: any) => {
301
// Add persistence annotations
302
if (args.type === "kubernetes:apps/v1:StatefulSet") {
303
args.props = pulumi.output(args.props).apply((props: any) => ({
304
...props,
305
metadata: {
306
...props.metadata,
307
annotations: {
308
...props.metadata?.annotations,
309
"backup.kubernetes.io/enabled": "true",
310
},
311
},
312
}));
313
}
314
return { props: args.props, opts: args.opts };
315
},
316
],
317
});
318
319
// Deploy application services
320
const appServices = new k8s.yaml.v2.ConfigGroup("app-services", {
321
files: [
322
"./manifests/services/user-service/*.yaml",
323
"./manifests/services/order-service/*.yaml",
324
"./manifests/services/payment-service/*.yaml",
325
],
326
namespace: "applications",
327
transformations: [
328
(args: any) => {
329
// Add service mesh annotations
330
if (args.type === "kubernetes:apps/v1:Deployment") {
331
args.props = pulumi.output(args.props).apply((props: any) => ({
332
...props,
333
spec: {
334
...props.spec,
335
template: {
336
...props.spec.template,
337
metadata: {
338
...props.spec.template.metadata,
339
annotations: {
340
...props.spec.template.metadata?.annotations,
341
"sidecar.istio.io/inject": "true",
342
"prometheus.io/scrape": "true",
343
"prometheus.io/port": "9090",
344
},
345
},
346
},
347
},
348
}));
349
}
350
return { props: args.props, opts: args.opts };
351
},
352
],
353
}, {
354
dependsOn: [databaseLayer],
355
});
356
357
// Deploy gateway and ingress
358
const gateway = new k8s.yaml.v2.ConfigFile("api-gateway", {
359
files: [
360
"./manifests/gateway/gateway.yaml",
361
"./manifests/gateway/virtualservice.yaml",
362
],
363
namespace: "istio-system",
364
}, {
365
dependsOn: [appServices],
366
});
367
368
// Access deployed resources
369
const userService = appServices.getResource("v1", "Service", "user-service", "applications");
370
const orderDeployment = appServices.getResource("apps/v1", "Deployment", "order-service", "applications");
371
372
// Export service endpoints
373
export const userServiceEndpoint = userService.spec.clusterIP;
374
export const gatewayURL = gateway.getResourceProperty("networking.istio.io/v1beta1/Gateway", "api-gateway", "status");
375
```
376
377
### CI/CD Pipeline Integration
378
379
```typescript { .api }
380
// Deploy from CI/CD generated manifests
381
const cicdDeployment = new k8s.yaml.v2.ConfigGroup("cicd-deployment", {
382
files: [`./build/manifests/${pulumi.getStack()}/*.yaml`],
383
namespace: `app-${pulumi.getStack()}`,
384
transformations: [
385
// Add CI/CD metadata
386
(args: any) => {
387
if (args.type.startsWith("kubernetes:")) {
388
args.props = pulumi.output(args.props).apply((props: any) => ({
389
...props,
390
metadata: {
391
...props.metadata,
392
annotations: {
393
...props.metadata?.annotations,
394
"deployment.kubernetes.io/revision": process.env.BUILD_NUMBER || "unknown",
395
"git.commit": process.env.GIT_COMMIT || "unknown",
396
"ci.pipeline": process.env.CI_PIPELINE_ID || "unknown",
397
},
398
labels: {
399
...props.metadata?.labels,
400
"app.kubernetes.io/version": process.env.APP_VERSION || "latest",
401
},
402
},
403
}));
404
}
405
return { props: args.props, opts: args.opts };
406
},
407
// Environment-specific resource adjustments
408
(args: any) => {
409
const stack = pulumi.getStack();
410
if (args.type === "kubernetes:apps/v1:Deployment") {
411
args.props = pulumi.output(args.props).apply((props: any) => ({
412
...props,
413
spec: {
414
...props.spec,
415
replicas: stack === "production" ? 5 : 2,
416
template: {
417
...props.spec.template,
418
spec: {
419
...props.spec.template.spec,
420
containers: props.spec.template.spec.containers?.map((container: any) => ({
421
...container,
422
resources: {
423
requests: {
424
cpu: stack === "production" ? "200m" : "100m",
425
memory: stack === "production" ? "256Mi" : "128Mi",
426
},
427
limits: {
428
cpu: stack === "production" ? "1" : "500m",
429
memory: stack === "production" ? "1Gi" : "512Mi",
430
},
431
},
432
})),
433
},
434
},
435
},
436
}));
437
}
438
return { props: args.props, opts: args.opts };
439
},
440
],
441
});
442
```
443
444
### Multi-Cluster Deployment
445
446
```typescript { .api }
447
// Deploy to multiple clusters with different configurations
448
const deployToCluster = (clusterName: string, region: string) => {
449
return new k8s.yaml.v2.ConfigGroup(`app-${clusterName}`, {
450
files: ["./manifests/app/*.yaml"],
451
namespace: "applications",
452
transformations: [
453
// Cluster-specific labels and annotations
454
(args: any) => {
455
if (args.type.startsWith("kubernetes:")) {
456
args.props = pulumi.output(args.props).apply((props: any) => ({
457
...props,
458
metadata: {
459
...props.metadata,
460
labels: {
461
...props.metadata?.labels,
462
"cluster": clusterName,
463
"region": region,
464
},
465
annotations: {
466
...props.metadata?.annotations,
467
"deployment.cluster": clusterName,
468
},
469
},
470
}));
471
}
472
return { props: args.props, opts: args.opts };
473
},
474
// Regional configuration
475
(args: any) => {
476
if (args.type === "v1/Service" && args.props.spec?.type === "LoadBalancer") {
477
args.props = pulumi.output(args.props).apply((props: any) => ({
478
...props,
479
metadata: {
480
...props.metadata,
481
annotations: {
482
...props.metadata?.annotations,
483
"service.beta.kubernetes.io/aws-load-balancer-type":
484
region.startsWith("us-") ? "nlb" : "classic",
485
},
486
},
487
}));
488
}
489
return { props: args.props, opts: args.opts };
490
},
491
],
492
});
493
};
494
495
// Deploy to multiple clusters
496
const usEast1Deployment = deployToCluster("us-east-1", "us-east-1");
497
const usWest2Deployment = deployToCluster("us-west-2", "us-west-2");
498
const euWest1Deployment = deployToCluster("eu-west-1", "eu-west-1");
499
```
500
501
## Best Practices
502
503
### YAML Management Best Practices
504
505
1. **File Organization**: Organize YAML files by component, environment, or namespace
506
2. **Glob Patterns**: Use glob patterns for flexible file selection
507
3. **Resource Naming**: Use consistent naming conventions across manifests
508
4. **Namespace Management**: Use namespace overrides rather than hardcoding namespaces
509
5. **Transformations**: Use transformations for cross-cutting concerns
510
511
### Deployment Best Practices
512
513
1. **Environment Separation**: Use different directories or overlays for different environments
514
2. **Resource Dependencies**: Use Pulumi dependencies to ensure proper deployment order
515
3. **Resource Access**: Use the resource access methods for inter-resource references
516
4. **Error Handling**: Implement proper error handling and rollback strategies
517
5. **Monitoring**: Monitor deployed resources and implement health checks
518
519
### Security Best Practices
520
521
1. **Secret Management**: Use Pulumi secrets for sensitive data rather than plain YAML
522
2. **RBAC Integration**: Apply appropriate RBAC configurations
523
3. **Network Policies**: Include network policies in your manifests
524
4. **Resource Limits**: Always specify resource requests and limits
525
5. **Image Security**: Use specific image tags and trusted registries
526
527
The YAML deployment capabilities provide a bridge between traditional Kubernetes manifests and modern infrastructure-as-code practices, enabling gradual migration while gaining the benefits of Pulumi's resource management and transformation capabilities.