The kubernetes:apps/v1:Deployment resource, part of the Pulumi Kubernetes provider, defines a Kubernetes Deployment that manages replicated pods, ensuring the desired replica count and handling rolling updates. This guide focuses on two capabilities: pod replication with label-based selection, and resource naming strategies.
A Deployment doesn’t stand alone. It requires a Kubernetes cluster with configured kubeconfig and access to container registries for pulling images. The examples are intentionally small and won’t run standalone without cluster access. Combine them with your own cluster configuration, namespaces, and service definitions.
When you create a Deployment with Pulumi, it waits until the resource reaches a Ready state before completing. This means the Deployment controller has begun updating, a ReplicaSet exists matching the current revision, and the status shows an Available condition. For generation > 1, Pulumi also checks for a Progressing condition with NewReplicaSetAvailable reason. If readiness doesn’t occur within 10 minutes, the operation times out (configurable via customTimeouts).
Deploy replicated pods with label-based selection
Most Kubernetes workloads begin with a Deployment that manages multiple replicas of a pod, ensuring instances run continuously and recover from failures.
import * as pulumi from "@pulumi/pulumi";
import * as kubernetes from "@pulumi/kubernetes";
const deployment = new kubernetes.apps.v1.Deployment("deployment", {
metadata: {
labels: {
app: "nginx",
},
},
spec: {
replicas: 3,
selector: {
matchLabels: {
app: "nginx",
},
},
template: {
metadata: {
labels: {
app: "nginx",
},
},
spec: {
containers: [{
image: "nginx:1.14.2",
name: "nginx",
ports: [{
containerPort: 80,
}],
}],
},
},
},
});
import pulumi
import pulumi_kubernetes as kubernetes
deployment = kubernetes.apps.v1.Deployment("deployment",
metadata=kubernetes.meta.v1.ObjectMetaArgs(
labels={
"app": "nginx",
},
),
spec=kubernetes.apps.v1.DeploymentSpecArgs(
replicas=3,
selector=kubernetes.meta.v1.LabelSelectorArgs(
match_labels={
"app": "nginx",
},
),
template=kubernetes.core.v1.PodTemplateSpecArgs(
metadata=kubernetes.meta.v1.ObjectMetaArgs(
labels={
"app": "nginx",
},
),
spec=kubernetes.core.v1.PodSpecArgs(
containers=[kubernetes.core.v1.ContainerArgs(
image="nginx:1.14.2",
name="nginx",
ports=[kubernetes.core.v1.ContainerPortArgs(
container_port=80,
)],
)],
),
),
))
package main
import (
appsv1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apps/v1"
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsv1.NewDeployment(ctx, "deployment", &appsv1.DeploymentArgs{
Metadata: &metav1.ObjectMetaArgs{
Labels: pulumi.StringMap{
"app": pulumi.String("nginx"),
},
},
Spec: &appsv1.DeploymentSpecArgs{
Replicas: pulumi.Int(3),
Selector: &metav1.LabelSelectorArgs{
MatchLabels: pulumi.StringMap{
"app": pulumi.String("nginx"),
},
},
Template: &corev1.PodTemplateSpecArgs{
Metadata: &metav1.ObjectMetaArgs{
Labels: pulumi.StringMap{
"app": pulumi.String("nginx"),
},
},
Spec: &corev1.PodSpecArgs{
Containers: corev1.ContainerArray{
&corev1.ContainerArgs{
Image: pulumi.String("nginx:1.14.2"),
Name: pulumi.String("nginx"),
Ports: corev1.ContainerPortArray{
&corev1.ContainerPortArgs{
ContainerPort: pulumi.Int(80),
},
},
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Kubernetes = Pulumi.Kubernetes;
return await Deployment.RunAsync(() =>
{
var deployment = new Kubernetes.Apps.V1.Deployment("deployment", new()
{
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Labels =
{
{ "app", "nginx" },
},
},
Spec = new Kubernetes.Types.Inputs.Apps.V1.DeploymentSpecArgs
{
Replicas = 3,
Selector = new Kubernetes.Types.Inputs.Meta.V1.LabelSelectorArgs
{
MatchLabels =
{
{ "app", "nginx" },
},
},
Template = new Kubernetes.Types.Inputs.Core.V1.PodTemplateSpecArgs
{
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Labels =
{
{ "app", "nginx" },
},
},
Spec = new Kubernetes.Types.Inputs.Core.V1.PodSpecArgs
{
Containers = new[]
{
new Kubernetes.Types.Inputs.Core.V1.ContainerArgs
{
Image = "nginx:1.14.2",
Name = "nginx",
Ports = new[]
{
new Kubernetes.Types.Inputs.Core.V1.ContainerPortArgs
{
ContainerPortValue = 80,
},
},
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.kubernetes.apps_v1.Deployment;
import com.pulumi.kubernetes.apps_v1.DeploymentArgs;
import com.pulumi.kubernetes.meta_v1.inputs.ObjectMetaArgs;
import com.pulumi.kubernetes.apps_v1.inputs.DeploymentSpecArgs;
import com.pulumi.kubernetes.meta_v1.inputs.LabelSelectorArgs;
import com.pulumi.kubernetes.core_v1.inputs.PodTemplateSpecArgs;
import com.pulumi.kubernetes.core_v1.inputs.PodSpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var deployment = new Deployment("deployment", DeploymentArgs.builder()
.metadata(ObjectMetaArgs.builder()
.labels(Map.of("app", "nginx"))
.build())
.spec(DeploymentSpecArgs.builder()
.replicas(3)
.selector(LabelSelectorArgs.builder()
.matchLabels(Map.of("app", "nginx"))
.build())
.template(PodTemplateSpecArgs.builder()
.metadata(ObjectMetaArgs.builder()
.labels(Map.of("app", "nginx"))
.build())
.spec(PodSpecArgs.builder()
.containers(ContainerArgs.builder()
.image("nginx:1.14.2")
.name("nginx")
.ports(ContainerPortArgs.builder()
.containerPort(80)
.build())
.build())
.build())
.build())
.build())
.build());
}
}
description: Create a Deployment with auto-naming
name: yaml-example
resources:
deployment:
properties:
metadata:
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
name: nginx
ports:
- containerPort: 80
type: kubernetes:apps/v1:Deployment
runtime: yaml
The replicas property sets the desired pod count; the Deployment controller maintains this number continuously. The selector.matchLabels property tells the Deployment which pods it owns (matching the labels in template.metadata.labels). The template.spec.containers array defines the container image and exposed ports. Kubernetes continuously reconciles actual state toward this desired state.
Specify an explicit deployment name
When you need predictable resource names for external references or CI/CD pipelines, override Pulumi’s automatic naming with metadata.name.
import * as pulumi from "@pulumi/pulumi";
import * as kubernetes from "@pulumi/kubernetes";
const deployment = new kubernetes.apps.v1.Deployment("deployment", {
metadata: {
labels: {
app: "nginx",
},
name: "nginx-deployment",
},
spec: {
replicas: 3,
selector: {
matchLabels: {
app: "nginx",
},
},
template: {
metadata: {
labels: {
app: "nginx",
},
},
spec: {
containers: [{
image: "nginx:1.14.2",
name: "nginx",
ports: [{
containerPort: 80,
}],
}],
},
},
},
});
import pulumi
import pulumi_kubernetes as kubernetes
deployment = kubernetes.apps.v1.Deployment("deployment",
metadata=kubernetes.meta.v1.ObjectMetaArgs(
labels={
"app": "nginx",
},
name="nginx-deployment",
),
spec=kubernetes.apps.v1.DeploymentSpecArgs(
replicas=3,
selector=kubernetes.meta.v1.LabelSelectorArgs(
match_labels={
"app": "nginx",
},
),
template=kubernetes.core.v1.PodTemplateSpecArgs(
metadata=kubernetes.meta.v1.ObjectMetaArgs(
labels={
"app": "nginx",
},
),
spec=kubernetes.core.v1.PodSpecArgs(
containers=[kubernetes.core.v1.ContainerArgs(
image="nginx:1.14.2",
name="nginx",
ports=[kubernetes.core.v1.ContainerPortArgs(
container_port=80,
)],
)],
),
),
))
package main
import (
appsv1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apps/v1"
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsv1.NewDeployment(ctx, "deployment", &appsv1.DeploymentArgs{
Metadata: &metav1.ObjectMetaArgs{
Labels: pulumi.StringMap{
"app": pulumi.String("nginx"),
},
Name: pulumi.String("nginx-deployment"),
},
Spec: &appsv1.DeploymentSpecArgs{
Replicas: pulumi.Int(3),
Selector: &metav1.LabelSelectorArgs{
MatchLabels: pulumi.StringMap{
"app": pulumi.String("nginx"),
},
},
Template: &corev1.PodTemplateSpecArgs{
Metadata: &metav1.ObjectMetaArgs{
Labels: pulumi.StringMap{
"app": pulumi.String("nginx"),
},
},
Spec: &corev1.PodSpecArgs{
Containers: corev1.ContainerArray{
&corev1.ContainerArgs{
Image: pulumi.String("nginx:1.14.2"),
Name: pulumi.String("nginx"),
Ports: corev1.ContainerPortArray{
&corev1.ContainerPortArgs{
ContainerPort: pulumi.Int(80),
},
},
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Kubernetes = Pulumi.Kubernetes;
return await Deployment.RunAsync(() =>
{
var deployment = new Kubernetes.Apps.V1.Deployment("deployment", new()
{
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Labels =
{
{ "app", "nginx" },
},
Name = "nginx-deployment",
},
Spec = new Kubernetes.Types.Inputs.Apps.V1.DeploymentSpecArgs
{
Replicas = 3,
Selector = new Kubernetes.Types.Inputs.Meta.V1.LabelSelectorArgs
{
MatchLabels =
{
{ "app", "nginx" },
},
},
Template = new Kubernetes.Types.Inputs.Core.V1.PodTemplateSpecArgs
{
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Labels =
{
{ "app", "nginx" },
},
},
Spec = new Kubernetes.Types.Inputs.Core.V1.PodSpecArgs
{
Containers = new[]
{
new Kubernetes.Types.Inputs.Core.V1.ContainerArgs
{
Image = "nginx:1.14.2",
Name = "nginx",
Ports = new[]
{
new Kubernetes.Types.Inputs.Core.V1.ContainerPortArgs
{
ContainerPortValue = 80,
},
},
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.kubernetes.apps_v1.Deployment;
import com.pulumi.kubernetes.apps_v1.DeploymentArgs;
import com.pulumi.kubernetes.meta_v1.inputs.ObjectMetaArgs;
import com.pulumi.kubernetes.apps_v1.inputs.DeploymentSpecArgs;
import com.pulumi.kubernetes.meta_v1.inputs.LabelSelectorArgs;
import com.pulumi.kubernetes.core_v1.inputs.PodTemplateSpecArgs;
import com.pulumi.kubernetes.core_v1.inputs.PodSpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var deployment = new Deployment("deployment", DeploymentArgs.builder()
.metadata(ObjectMetaArgs.builder()
.labels(Map.of("app", "nginx"))
.name("nginx-deployment")
.build())
.spec(DeploymentSpecArgs.builder()
.replicas(3)
.selector(LabelSelectorArgs.builder()
.matchLabels(Map.of("app", "nginx"))
.build())
.template(PodTemplateSpecArgs.builder()
.metadata(ObjectMetaArgs.builder()
.labels(Map.of("app", "nginx"))
.build())
.spec(PodSpecArgs.builder()
.containers(ContainerArgs.builder()
.image("nginx:1.14.2")
.name("nginx")
.ports(ContainerPortArgs.builder()
.containerPort(80)
.build())
.build())
.build())
.build())
.build())
.build());
}
}
description: Create a Deployment with a user-specified name
name: yaml-example
resources:
deployment:
properties:
metadata:
labels:
app: nginx
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
name: nginx
ports:
- containerPort: 80
type: kubernetes:apps/v1:Deployment
runtime: yaml
By default, Pulumi generates unique names for Kubernetes resources. Setting metadata.name to “nginx-deployment” creates a Deployment with that exact name in the cluster, making it easier to reference from kubectl, monitoring tools, or other automation. The rest of the configuration (replicas, selector, template) works identically to auto-named deployments.
Beyond These Examples
These snippets focus on specific Deployment-level features: replica management and pod templates, label-based pod selection, and automatic vs explicit resource naming. They’re intentionally minimal rather than full application deployments.
The examples assume pre-existing infrastructure such as a Kubernetes cluster with configured kubeconfig and container registry access for pulling images. They focus on configuring the Deployment rather than provisioning cluster infrastructure or defining Services.
To keep things focused, common Deployment patterns are omitted, including:
- Resource limits and requests (resources block)
- Health checks (livenessProbe, readinessProbe)
- Rolling update strategy (strategy.type, maxSurge, maxUnavailable)
- Environment variables and ConfigMap/Secret mounts
- Namespace and annotation configuration
These omissions are intentional: the goal is to illustrate how Deployment replication and selection are wired, not provide drop-in application modules. See the Deployment resource reference for all available configuration options.
Frequently Asked Questions
Readiness & Timeouts
customTimeouts option on the resource.status.conditions field has an ‘Available’ condition with status ‘True’, (4) For generation > 1, status.conditions has a ‘Progressing’ condition with status ‘True’ and reason ‘NewReplicaSetAvailable’.status.conditions shows ‘Available’ as ‘True’, and for updates (generation > 1), check that ‘Progressing’ is ‘True’ with reason ‘NewReplicaSetAvailable’.Label Selectors & Pod Templates
spec.selector.matchLabels must match spec.template.metadata.labels for the Deployment to correctly manage its pods. All examples show identical labels in both locations.selector.matchLabels and template.metadata.labels.Naming & Configuration
metadata.name for auto-generated names. To use a specific name, set metadata.name explicitly (e.g., ’nginx-deployment’).replicas: 3, but the appropriate number depends on your application’s availability and load requirements. Set spec.replicas to your desired count.Ready to get started?
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Create free account