Kubernetes with Pulumi

Pulumi provides a cloud native programming model for Kubernetes deployments and orchestration: from on-premises to AWS EKS, Microsoft AKS, and Google GKE.

Any code, any cloud, any language.

import * as kx from "@pulumi/kubernetesx";

const pb = new kx.PodBuilder({
    containers: [{
        image: "nginx",
        ports: { http: 80 }
    }]
});

const deployment = new kx.Deployment("nginx", {
    spec: pb.asDeploymentSpec({ replicas: 3 })
});

const service = deployment.createService({
    type: kx.types.ServiceType.LoadBalancer
});

export const serviceIP = service.ip;

What is Kubernetes?

Kubernetes is a system for automating the deployment, scaling, and management of containerized applications.

As an open-source system, it is becoming widely deployed in on-premises data centers, self-hosted on cloud infrastructure, or as a cloud managed service, such as Google GKE, Azure AKS, and Amazon EKS.

Kubernetes Everywhere

Pulumi's Cloud Native SDK makes it easy to target any Kubernetes environment to provision a cluster, configure and deploy applications, and update them as required.

Pulumi uses real code which makes it easy, and efficient, for the development inner loop, at the same time as unlocking more complicated, real-world DevOps scenarios.

Pulumi works with Minikube, on-premises and cloud-hosted custom Kubernetes clusters, and the managed services from Google (GKE), Azure (AKS), and Amazon (EKS).

  • MiniKube
  • Kubernetes
  • AWS
  • Azure
  • GCP

Define Kubernetes apps

In this example, we use TypeScript to define a trivial app - an nginx image - and deploy 1 replica. Using a real language to define your app enables great IDE support — compile time checking for instance.

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

const appLabels = { app: "nginx" };

const deployment = new k8s.apps.v1.Deployment("nginx", {
    spec: {
        replicas: 1,
        selector: { matchLabels: appLabels },
        template: {
            metadata: { labels: appLabels },
            spec: {
                containers: [{
                    name: "nginx", image: "nginx"
                }]
            }
        }
    }
});

Improve expressiveness, reduce boilerplate

Using real languages means being able to recognize patterns, and abstract them to reusable componenents. In this example we take a typical Deployment and Service pattern to create a ServiceDeployment class, simplifying the implementation of the canonical Guestbook app.

GET STARTED
import * as k8sjs from "./k8sjs";

let redisMaster = new k8sjs.ServiceDeployment("redis-master", {
    image: "k8s.gcr.io/redis:e2e",
    ports: [ 6379 ]
});

let redisSlave = new k8sjs.ServiceDeployment("redis-slave", {
    image: "gcr.io/google_samples/gb-redisslave:v1",
    ports: [ 6379 ]
});

let frontend = new k8sjs.ServiceDeployment("frontend", {
    replicas: 3,
    image: "gcr.io/google-samples/gb-frontend:v4",
    ports: [ 80 ],
    loadBalancer: true,
});

export let frontendIp = frontend.ipAddress;

Injecting sidecars using abstraction

Abstraction also allows us to do powerful work to simplify more complex configuration. An example of this is the sidecar microservices pattern where a container runs alongside other containers to add some functional value — logging, proxying etc. In this case we define a simple EnvoyDeployment class that adds an Envoy sidecar to our Kubernetes app.

GET STARTED
export class EnvoyDeployment extends k8s.apps.v1.Deployment {
    constructor(name: string, args: k8stypes.apps.v1.Deployment, opts?: pulumi.CustomResourceOptions) {
        const pod = args.spec.template.spec;

        // Add an Envoy sidecar container.
        pod.containers = pod.containers || [];
        pod.containers.push({
            name: "envoy",
            // `lyft/envoy` does not tag releases. Use a SHA.
            image: "lyft/envoy:4640fc028d65a6e2ee18858ebefcaeed24dffa81",
            command: ["/usr/local/bin/envoy"],
            args: [
                "--concurrency 4",
                "--config-path /etc/envoy/envoy.json",
                "--mode serve"
            ],
            ports: [{ containerPort: 80, protocol: "TCP" }],
            resources: {
                limits: { cpu: "1000m", memory: "512Mi" },
                requests: { cpu: "100m", memory: "64Mi" }
            },
            volumeMounts: [{
                name: "envoy-conf", mountPath: "/etc/envoy"
            }]
        });

        // Add a Volume for Envoy's config, as a ConfigMap.
        pod.volumes = pod.volumes || [];
        pod.volumes.push({
            name: "envoy-conf", configMap: { name: "envoy" },
        });

        super(name, args, opts);
    }
}

Use existing YAML and Helm Charts

Pulumi can also process YAML and Helm Charts, adding them to Pulumi programs which unlocks multi-cloud and advanced delivery scenarios. These examples use YAML and Helm to deploy the Kubernetes Guestbook app and Wordpress.

GET STARTED
// Use YAML.
import * as k8s from "@pulumi/kubernetes";

const guestbook = new k8s.yaml.ConfigGroup(
    "guestbook", { files: "guestbook/*.yaml" });

export const frontendIp =
    guestbook.getResource("v1/Service", "frontend").
    spec.apply(spec => spec.clusterIP);

// Use Helm.
import * as k8s from "@pulumi/kubernetes";

const wordpress = new k8s.helm.v2.Chart("wordpress", {
    repo: "stable",
    version: "2.1.3",
    chart: "wordpress"
});

export const frontendIp = wordpress
    .getResource("v1/Service", "wpdev-wordpress")
    .status.apply(status => status.loadBalancer.ingress[0].ip);

Declare managed services alongside Kubernetes

Pulumi can be used to combine services. For instance, a Kubernetes cluster and an associated database (such as RDS). In this example, we provision and use an AWS S3 bucket from a Kubernetes service.

GET STARTED
import * as k8s from "@pulumi/kubernetes";
import * as aws from "@pulumi/aws";

const appName = "nginx";

// nginx config stored in an S3 bucket.
const config = new aws.s3.Bucket(`${appName}-config`);

// nginx container, replicated 1 time.
const appLabels = { app: appName };
const nginx = new k8s.apps.v1beta1.Deployment(appName, {
    spec: {
        selector: { matchLabels: appLabels },
        replicas: 1,
        template: {
            metadata: { labels: appLabels },
            spec: {
                initContainers: [
                    nginxConfigPuller(config.bucketDomainName)
                ],
                containers: [{
                    name: appName, image: "nginx:1.15-alpine"
                }]
            }
        }
    }
});

Provision Kubernetes clusters in any cloud

Kubernetes can be used in many environments — local dev, in the data center, self-hosted in the cloud, and as a managed cloud service. Pulumi supports all of those options. In this example, we show how to deploy a GKE cluster with configurable settings, which can then be used to deploy apps to.

GET STARTED
import * as gcp from "@pulumi/gcp";
import { nodeCount, nodeMachineType, password, username } from "./config";

const engineVersion = gcp.container.getEngineVersions().then(v => v.latestMasterVersion);
export const k8sCluster = new gcp.container.Cluster("gke-cluster", {
    initialNodeCount: nodeCount,
    minMasterVersion: engineVersion,
    nodeVersion: engineVersion,
    masterAuth: { username, password },
    nodeConfig: {
        machineType: nodeMachineType,
        oauthScopes: [
            "https://www.googleapis.com/auth/compute",
            "https://www.googleapis.com/auth/devstorage.read_only",
            "https://www.googleapis.com/auth/logging.write",
            "https://www.googleapis.com/auth/monitoring"
        ],
    },
});

How Pulumi Works

1
Create

  • Code in real languages
  • Share and reuse patterns
  • Use your favorite IDE and tools

2
Deploy

  • Preview changes
  • Run pulumi up to deploy
  • Integrate with CI/CD

3
Manage

  • Audit all changes
  • Manage complex environments
  • Implement policies and controls

Get Started with Pulumi

Use Pulumi's open source SDK to create, deploy, and manage infrastructure on any cloud.

Learn how top engineering teams are using Pulumi to manage and provision Kubernetes clusters in any cloud.

As the largest eCommerce platform in Latin America, our infrastructure has to be highly stable, well documented and agile. With Pulumi, we're able to develop new infrastructure, change existing infrastructure and more with greater speed and reliability than we've ever had before.

Harrison Heck
Head of DevOps, Linio

Need help with Kubernetes?

More from Pulumi

Migrate to Pulumi

In this video, Pulumi CTO, Luke Hoban, discusses how to begin to migrate to Pulumi from existing tools such as CloudFormation and Terraform.

Learn more
Video thumbnail diagram

Serverless, Containers, and Infrastructure

In this blog post, we show how productive Pulumi can be at combining different aspects of cloud architecture for truly cloud native programming.

Learn more