1. Docs
  2. Pulumi IaC
  3. Clouds
  4. Kubernetes
  5. Guides
  6. Apps

Kubernetes Apps

The following are examples of how to create and use various types of Kubernetes resources, and typical apps and workloads.

The full code for the AWS apps stack is on GitHub.

The full code for the Azure apps stack is on GitHub.

The full code for the Google Cloud apps stack is on GitHub.

The full code for the apps is on GitHub.

Overview

Check out how to:

Build and Deploy a Container

Build a Docker container image, push it to the registry, and deploy it to Kubernetes.

The full code for this app stack is on GitHub.

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

// Create a repository.
const repo = new awsx.ecr.Repository("my-repo", {
    forceDelete: true,
});

// Build a Docker image from a local Dockerfile context in the
// './node-app' directory, and push it to the registry.
const customImage = "node-app";
const appImage = new awsx.ecr.Image("image", {
    repositoryUrl: repo.url,
    path: `./${customImage}`,
});

// Create a k8s provider.
const provider = new k8s.Provider("provider", {
    kubeconfig: config.kubeconfig,
    namespace: config.appsNamespaceName,
});

// Create a Deployment of the built container.
const appLabels = { app: customImage };
const appDeployment = new k8s.apps.v1.Deployment("app", {
    spec: {
        selector: { matchLabels: appLabels },
        replicas: 1,
        template: {
            metadata: { labels: appLabels },
            spec: {
                containers: [{
                    name: customImage,
                    image: appImage.imageUri,
                    ports: [{name: "http", containerPort: 80}],
                }],
            }
        },
    }
}, { provider: provider });
Copy
import * as awsx from "@pulumi/awsx";
import * as k8s from "@pulumi/kubernetes";
import * as kx from "@pulumi/kubernetesx";

// Create a repository.
const repo = new awsx.ecr.Repository("my-repo", {
    forceDelete: true,
});

// Build a Docker image from a local Dockerfile context in the
// './node-app' directory, and push it to the registry.
const customImage = "node-app";
const appImage = repo.buildAndPushImage(`./${customImage}`);

// Create a k8s provider.
const provider = new k8s.Provider("provider", {
    kubeconfig: config.kubeconfig,
    namespace: config.appsNamespaceName,
});

// Define the Pod for the Deployment.
const pb = new kx.PodBuilder({
    containers: [{
        image: appImage.imageUri,
        ports: { "http": 80 },
    }],
});

// Create a Deployment of the Pod defined by the PodBuilder.
const appDeploymentKx = new kx.Deployment("app-kx", {
    spec: pb.asDeploymentSpec(),
}, { provider: provider });
Copy

The full code for this app stack is on GitHub.

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

// Create an Azure Resource Group
const resourceGroup = new azure.core.ResourceGroup("samples");

// Create a registry in ACR.
const registry = new azure.containerservice.Registry("myregistry", {
    resourceGroupName: resourceGroup.name,
    sku: "Basic",
    adminEnabled: true,
});

// Build a Docker image from a local Dockerfile context in the
// './node-app' directory, and push it to the registry.
const customImage = "node-app";
const appImage = new docker.Image(customImage, {
    imageName: pulumi.interpolate`${registry.loginServer}/${customImage}:v1.0.0`,
    build: {
        context: `./${customImage}`,
    },
    registry: {
        server: registry.loginServer,
        username: registry.adminUsername,
        password: registry.adminPassword,
    },
});

// Create a k8s provider.
const provider = new k8s.Provider("provider", {
    kubeconfig: config.kubeconfig,
    namespace: config.appsNamespaceName,
});

// Create a Deployment of the built container.
const appLabels = { app: customImage };
const appDeployment = new k8s.apps.v1.Deployment("app", {
    spec: {
        selector: { matchLabels: appLabels },
        replicas: 1,
        template: {
            metadata: { labels: appLabels },
            spec: {
                containers: [{
                    name: customImage,
                    image: appImage.imageUri,
                    ports: [{name: "http", containerPort: 80}],
                }],
            }
        },
    }
}, { provider: provider });
Copy
import * as azure from "@pulumi/azure";
import * as k8s from "@pulumi/kubernetes";
import * as kx from "@pulumi/kubernetesx";
import * as docker from "@pulumi/docker";
import * as pulumi from "@pulumi/pulumi";

// Create an Azure Resource Group
const resourceGroup = new azure.core.ResourceGroup("samples");

// Create a registry in ACR.
const registry = new azure.containerservice.Registry("myregistry", {
    resourceGroupName: resourceGroup.name,
    sku: "Basic",
    adminEnabled: true,
});

// Build a Docker image from a local Dockerfile context in the
// './node-app' directory, and push it to the registry.
const customImage = "node-app";
const appImage = new docker.Image(customImage, {
    imageName: pulumi.interpolate`${registry.loginServer}/${customImage}:v1.0.0`,
    build: {
        context: `./${customImage}`,
    },
    registry: {
        server: registry.loginServer,
        username: registry.adminUsername,
        password: registry.adminPassword,
    },
});

// Create a k8s provider.
const provider = new k8s.Provider("provider", {
    kubeconfig: config.kubeconfig,
    namespace: config.appsNamespaceName,
});

// Define the Pod for the Deployment.
const pb = new kx.PodBuilder({
    containers: [{
        image: appImage.imageUri,
        ports: { "http": 80 },
    }],
});

// Create a Deployment of the Pod defined by the PodBuilder.
const appDeploymentKx = new kx.Deployment("app-kx", {
    spec: pb.asDeploymentSpec(),
}, { provider: provider });
Copy

The full code for this app stack is on GitHub.

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

// Get the Google Cloud project registry repository.
const registry = gcp.container.getRegistryRepositoryOutput();

// Get the repository URL
const repositoryUrl = registry.repositoryUrl;

// Build a Docker image from a local Dockerfile context in the
// './node-app' directory, and push it to the registry.
const customImage = "node-app";
const appImage = new docker.Image(customImage, {
    imageName: pulumi.interpolate`${repositoryUrl}/${customImage}:v1.0.0`,
    build: {
        context: `./${customImage}`,
    },
});

// Create a k8s provider.
const provider = new k8s.Provider("provider", {
    kubeconfig: config.kubeconfig,
    namespace: config.appsNamespaceName,
});

// Create a Deployment of the built container.
const appLabels = { app: customImage };
const appDeployment = new k8s.apps.v1.Deployment("app", {
    spec: {
        selector: { matchLabels: appLabels },
        replicas: 1,
        template: {
            metadata: { labels: appLabels },
            spec: {
                containers: [{
                    name: customImage,
                    image: appImage.imageUri,
                    ports: [{name: "http", containerPort: 80}],
                }],
            }
        },
    }
}, { provider: provider });
Copy
import * as docker from "@pulumi/docker";
import * as gcp from "@pulumi/gcp";
import * as k8s from "@pulumi/kubernetes";
import * as kx from "@pulumi/kubernetesx";
import * as pulumi from "@pulumi/pulumi";

// Get the Google Cloud project registry repository.
const registry = gcp.container.getRegistryRepositoryOutput();

// Get the repository URL
const repositoryUrl = registry.repositoryUrl;

// Build a Docker image from a local Dockerfile context in the
// './node-app' directory, and push it to the registry.
const customImage = "node-app";
const appImage = new docker.Image(customImage, {
    imageName: pulumi.interpolate`${repositoryUrl}/${customImage}:v1.0.0`,
    build: {
        context: `./${customImage}`,
    },
});

// Create a k8s provider.
const provider = new k8s.Provider("provider", {
    kubeconfig: config.kubeconfig,
    namespace: config.appsNamespaceName,
});

// Define the Pod for the Deployment.
const pb = new kx.PodBuilder({
    containers: [{
        image: appImage.imageUri,
        ports: { "http": 80 },
    }],
});

// Create a Deployment of the Pod defined by the PodBuilder.
const appDeploymentKx = new kx.Deployment("app-kx", {
    spec: pb.asDeploymentSpec(),
}, { provider: provider });
Copy

Deploy a Pod with a Sidecar

The full code for this app stack is on GitHub.

Create a NGINX Pod with a Debian sidecar that prints to a file in a shared volume of the Pod.

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

// Create an example Pod with a Sidecar.
const pod = new k8s.core.v1.Pod("example", {
    spec: {
        restartPolicy: "Never",
        volumes: [
            {name: "shared-data", emptyDir: {}},
        ],
        containers: [
            {
                name: "nginx",
                image: "nginx",
                resources: {requests: {cpu: "50m", memory: "50Mi"}},
                volumeMounts: [
                    { name: "shared-data", mountPath: "/usr/share/nginx/html"},
                ],
            },
            {
                name: "debian-container",
                image: "debian",
                resources: {requests: {cpu: "50m", memory: "50Mi"}},
                volumeMounts: [
                    { name: "shared-data", mountPath: "/pod-data"},
                ],
                command: [ "/bin/bash"],
                args: ["-c", "echo Hello from the Debian container > /pod-data/index.html ; sleep infinity"],
            }
        ],
    }
}, { provider: provider });
Copy

Print out the contents of the shared file from the nginx container in the Pod.

$ kubectl exec -it example-<SUFFIX> -n `pulumi output stack appsNamespaceName` -c nginx -- cat /usr/share/nginx/html/index.html
Copy

Deploy a Helm Chart

Deploy the Helm chart into the app-svcs namespace created in Configure Cluster Defaults, and publicly expose it to the Internet using a load balanced Service.

Note: NGINX requires a privileged PSP given its use of allowPrivilegeEscalation: true.

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

// Deploy the NGINX ingress controller using the Helm chart.
const nginx = new k8s.helm.v3.Chart("nginx",
    {
        namespace: config.appSvcsNamespaceName,
        chart: "nginx-ingress",
        version: "1.24.4",
        fetchOpts: {repo: "https://charts.helm.sh/stable/"},
        values: {controller: {publishService: {enabled: true}}},
        transformations: [
            (obj: any) => {
                // Do transformations on the YAML to set the namespace
                if (obj.metadata) {
                    obj.metadata.namespace = config.appSvcsNamespaceName;
                }
            },
        ],
    },
    {providers: {kubernetes: provider}},
);
Copy

Deploy Wordpress

Create a Deployment of Wordpress.

The full code for this app stack is on GitHub.

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

const wordpress = new k8s.apps.v1.Deployment("wordpress", {
    spec: {
        selector: { matchLabels: { app: "wordpress", release: "example" } },
        strategy: { type: "RollingUpdate" },
        replicas: 1,
        template: {
            metadata: { labels: { app: "wordpress", release: "example" } },
            spec: {
                hostAliases: [ { ip: "127.0.0.1", hostnames: [ "status.localhost"] } ],
                containers: [
                    {
                        name: "wordpress",
                        image: "docker.io/bitnami/wordpress:5.2.4-debian-9-r0",
                        imagePullPolicy: "IfNotPresent",
                        env: [
                            { name: "MARIADB_HOST", value: "mariadb" },
                            { name: "WORDPRESS_DATABASE_NAME", value: "bitnami_wordpress" },
                            { name: "WORDPRESS_DATABASE_USER", value: "bn_wordpress" },
                            {
                                name: "WORDPRESS_DATABASE_PASSWORD",
                                valueFrom: {
                                    secretKeyRef: {
                                        name: mariadbSecret.metadata.name,
                                        key: "mariadb-password"
                                    }
                                }
                            },
                            ...
                        ],
                        ports: [
                            { name: "http", containerPort: 80 },
                            { name: "https", containerPort: 443 }
                        ],
                        volumeMounts: [
                            {
                                mountPath: "/bitnami/wordpress",
                                name: "wordpress-data",
                                subPath: "wordpress"
                            }
                        ],
                        resources: { requests: { cpu: "300m", memory: "512Mi" } }
                        ...
                    }
                ],
                ...
            }
        }
    }
}, { provider: provider });
Copy

Create a Deployment with a Secret

Create a Deployment NGINX that uses a Secret.

The full code for this app stack is on GitHub.

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

// Create a Secret with the database credentials.
const databaseSecret = new k8s.core.v1.Secret("db-secret", {
    stringData: {
        "database-username": config.databaseUsername,
        "database-password": config.databasePassword,
    }
}, { provider: provider });

// Create a Deployment that uses the database credentials as environment variables.
const appName = "nginx";
const appLabels = { app: appName };
const nginx = new k8s.apps.v1.Deployment(appName, {
    metadata: { labels: appLabels },
    spec: {
        selector: {
            matchLabels: appLabels,
        },
        replicas: 1,
        template: {
            metadata: { labels: appLabels },
            spec: {
                containers: [
                    {
                        image: "nginx",
                        name: "nginx",
                        env: [
                            {
                                name: "DATABASE_USERNAME",
                                valueFrom: {
                                    secretKeyRef: {
                                        name: databaseSecret.metadata.name,
                                        key: "database-username"
                                    }
                                }
                            },
                            {
                                name: "DATABASE_PASSWORD",
                                valueFrom: {
                                    secretKeyRef: {
                                        name: databaseSecret.metadata.name,
                                        key: "database-password"
                                    }
                                }
                            }
                        ]
                    },
                ],
            },
        },
    },
}, { provider: provider });
Copy
import * as kx from "@pulumi/kubernetesx";

// Create a KX Secret with the database credentials.
const databaseSecretKx = new kx.Secret("db-secret", {
    stringData: {
        "database-username": config.databaseUsername,
        "database-password": config.databasePassword,
    }
}, { provider: provider });

// Create a KX PodBuilder for the demo app.
const nginxPB = new kx.PodBuilder({
    containers: [{
        image: "nginx",
        env: {
            "DATABASE_USERNAME": databaseSecretKx.asEnvValue("database-username"),
            "DATABASE_PASSWORD": databaseSecretKx.asEnvValue("database-password"),
        }
    }]
});

// Create a KX Deployment from the KX PodBuilder by transforming it into a DeploymentSpec.
// The deployment use database credentials as environment variables.
const nginxDeployment = new kx.Deployment(appName, {
    spec: nginxPB.asDeploymentSpec({replicas: 1})
}, { provider: provider });
Copy

Perform a ConfigMap Rollout on a Deployment

For a complete example, check out our Kubernetes Graceful App Rollout tutorial for more details on how to update a Deployment automatically when it’s ConfigMap changes.

Deploy a Job

Deploy a Job of a Perl program.

The full code for this app stack is on GitHub.

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

// Create an example Job.
const exampleJob = new k8s.batch.v1.Job("example-job", {
    spec: {
        template: {
            spec: {
                containers: [
                    {
                        name: "pi",
                        image: "perl",
                        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"],
                    }
                ],
                restartPolicy: "Never"
            }
        },
    }
}, { provider: provider });
Copy
import * as kx from "@pulumi/kubernetesx";

// Create the PodBuilder for the Job.
const pb = new kx.PodBuilder({
    containers: [{
        name: "pi",
        image: "perl",
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"],
    }],
    restartPolicy: "Never",
});

// Create a Job using the Pod defined by the PodBuilder.
const exampleJobKx = new kx.Job("example-job-kx", {
    spec: pb.asJobSpec(),
}, { provider: provider });
Copy

Deploy a DaemonSet

Deploy a DaemonSet of NGINX across all nodes in the cluster.

The full code for this app stack is on GitHub.

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

// Create a DaemonSet that deploys nginx to each worker node.
const appName = "nginx";
const appLabels = { app: appName };
const nginx = new k8s.apps.v1.DaemonSet(appName, {
    metadata: { labels: appLabels },
    spec: {
        selector: {
            matchLabels: appLabels,
        },
        template: {
            metadata: { labels: appLabels },
            spec: {
                containers: [
                    {
                        image: "nginx",
                        name: "nginx",
                    },
                ],
            },
        },
    },
}, { provider: provider });
Copy

Coming Soon.

Deploy a CronJob

Deploy a CronJob of a command that runs every minute.

The full code for this app stack is on GitHub.

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

// Create an example CronJob.
const exampleCronJob = new k8s.batch.v1beta1.CronJob("example-cronjob", {
    spec: {
        schedule: "*/1 * * * *",
        jobTemplate: {
            spec: {
                template: {
                    spec: {
                        containers: [
                            {
                                name: "hello",
                                image: "busybox",
                                args: ["/bin/sh",  "-c", "date; echo Hello from the Kubernetes cluster"],
                            }
                        ],
                        restartPolicy: "OnFailure"
                    }
                }
            }
        },
    }
}, { provider: provider });
Copy

Coming soon.

Deploy a StatefulSet

Deploy a StatefulSet of MariaDB.

The full code for this app stack is on GitHub.

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

// Deploy MariaDB as a StatefulSet.
const mariadb = new k8s.apps.v1.StatefulSet("mariadb", {
    spec: {
        selector: {
            matchLabels: {
                app: "mariadb",
                release: "example",
                component: "master"
            }
        },
        serviceName: "mariadb",
        replicas: 1,
        updateStrategy: {
            type: "RollingUpdate"
        },
        template: {
            metadata: {
                labels: {
                    app: "mariadb",
                    release: "example",
                    component: "master"
                }
            },
            spec: {
                serviceAccountName: "default",
                securityContext: {
                    fsGroup: 1001,
                    runAsUser: 1001
                },
                affinity: {
                    podAntiAffinity: {
                        preferredDuringSchedulingIgnoredDuringExecution: [
                            {
                                weight: 1,
                                podAffinityTerm: {
                                    topologyKey: "kubernetes.io/hostname",
                                    labelSelector: {
                                        matchLabels: {
                                            app: "mariadb",
                                            release: "example"
                                        }
                                    }
                                }
                            }
                        ]
                    }
                },
                containers: [
                    {
                        name: "mariadb",
                        image: "docker.io/bitnami/mariadb:10.3.18-debian-9-r36",
                        imagePullPolicy: "IfNotPresent",
                        env: [
                            {
                                name: "MARIADB_ROOT_PASSWORD",
                                valueFrom: {
                                    secretKeyRef: {
                                        name: mariadbSecret.metadata.name,
                                        key: "mariadb-root-password"
                                    }
                                }
                            },
                            { name: "MARIADB_USER", value: "bn_wordpress" },
                            {
                                name: "MARIADB_PASSWORD",
                                valueFrom: {
                                    secretKeyRef: {
                                        name: mariadbSecret.metadata.name,
                                        key: "mariadb-password"
                                    }
                                }
                            },
                            { name: "MARIADB_DATABASE", value: "bitnami_wordpress" }
                        ],
                        ports: [
                            { name: "mysql", containerPort: 3306 }
                        ],
                        livenessProbe: {
                            exec: {
                                command: ["sh", "-c", "exec mysqladmin status -uroot -p$MARIADB_ROOT_PASSWORD"],
                            },
                            initialDelaySeconds: 120,
                            periodSeconds: 10,
                            timeoutSeconds: 1,
                            successThreshold: 1,
                            failureThreshold: 3
                        },
                        readinessProbe: {
                            exec: {
                                command: ["sh", "-c", "exec mysqladmin status -uroot -p$MARIADB_ROOT_PASSWORD"]
                            },
                            initialDelaySeconds: 30,
                            periodSeconds: 10,
                            timeoutSeconds: 1,
                            successThreshold: 1,
                            failureThreshold: 3
                        },
                        volumeMounts: [
                            {
                                name: "data",
                                mountPath: "/bitnami/mariadb"
                            },
                            {
                                name: "config",
                                mountPath: "/opt/bitnami/mariadb/conf/my.cnf",
                                subPath: "my.cnf"
                            }
                        ]
                    }
                ],
                volumes: [
                    {
                        name: "config",
                        configMap: {
                            name: mariadbCM.metadata.name
                        }
                    }
                ]
            },
        },
        volumeClaimTemplates: [
            {
                metadata: {
                    name: "data",
                    labels: {
                        app: "mariadb",
                        component: "master",
                        release: "example",
                    }
                },
                spec: {
                    accessModes: [
                        "ReadWriteOnce"
                    ],
                    resources: {
                        requests: {
                            storage: "8Gi"
                        }
                    }
                }
            }
        ]
    }
}, { provider: provider });
Copy

Coming soon.

Learn More

To learn more about how to work with Kubernetes and Pulumi, check out the Kubernetes Tutorials for details.

Was this page helpful?

PulumiUP May 6, 2025. Register Now.