/kube2pulumi

Upgrade your Kubernetes YAML to a modern language

Primary LanguageGoApache License 2.0Apache-2.0

kube2pulumi

Convert Kubernetes YAML to Pulumi programs in Go, TypeScript, Python, C# and Java. Improve your Kubernetes development experience by taking advantage of strong types, compilation errors, full IDE support for features like autocomplete. Declare and manage the infrastructure in any cloud in the same program that manages your Kubernetes resources.

Live Demo

Check out the kube2pulumi web app to see kube2pulumi in action in your browser.

Prerequisites

  1. Pulumi CLI
  2. Install the Pulumi Kubernetes plugin:
$ pulumi plugin install resource kubernetes v3.0.0

Building and Installation

If you wish to use kube2pulumi without developing the tool itself, you can use one of the binary releases hosted on GitHub.

Homebrew

kube2pulumi can be installed on Mac from the Pulumi Homebrew tap.

brew install pulumi/tap/kube2pulumi

kube2pulumi uses Go modules to manage dependencies. If you want to develop kube2pulumi itself, you'll need to have Go installed in order to build. Once this prerequisite is installed, run the following to build the kube2pulumi binary and install it into $GOPATH/bin:

$ go build -o $GOPATH/bin/kube2pulumi -ldflags="-X github.com/pulumi/kube2pulumi/pkg/version.Version=1.0.0" cmd/kube2pulumi/main.go

The ldflags argument is necessary to dynamically set the kube2pulumi version at build time. However, the version itself can be anything, so you don't have to set it to dev.

Go should automatically handle pulling the dependencies for you. If $GOPATH/bin is not on your path, you may want to move the kube2pulumi binary from $GOPATH/bin into a directory that is on your path.

Usage

In order to use kube2pulumi to convert Kubernetes YAML to Pulumi and then deploy it, you'll first need to install the Pulumi CLI.

Once the Pulumi CLI has been installed, you'll need to install the Kubernetes plugin:

$ pulumi plugin install resource kubernetes v2.4.2

Now, navigate to the same directory as the the YAML you'd like to convert and create a new Pulumi stack in your favorite language:

// For a Go project
$ pulumi new kubernetes-go -f

// For a TypeScript project
$ pulumi new kubernetes-typescript -f

// For a Python project
$ pulumi new kubernetes-python -f

// For a C# project
$ pulumi new kubernetes-csharp -f

// For a Java project
$ pulumi new kubernetes-java -f

Then run kube2pulumi which will write a file in the directory that contains the Pulumi project you just created:

// For a Go project
$ kube2pulumi go 

// For a TypeScript project
$ kube2pulumi typescript

// For a Python project
$ kube2pulumi python

// For a C# project
$ kube2pulumi csharp

// For a Java project
$ kube2pulumi java

This will generate a Pulumi program that when run with pulumi update will deploy the Kubernetes resources originally described by your YAML. Note that before deployment you will need to configure Kubernetes so the Pulumi CLI can connect to a Kubernetes cluster. If you have previously configured the kubectl CLI, kubectl, Pulumi will respect and use your configuration settings.

Example

Let's convert a simple YAML file describing a pod with a single container running nginx:

apiVersion: v1
kind: Pod
metadata:
  namespace: foo
  name: bar
spec:
  containers:
    - name: nginx
      image: nginx:1.14-alpine
      resources:
        limits:
          memory: 20Mi
          cpu: 0.2

Go

kube2pulumi go -f ./pod.yaml
package main

import (
	corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/core/v1"
	metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/meta/v1"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := corev1.NewPod(ctx, "fooBarPod", &corev1.PodArgs{
			ApiVersion: pulumi.String("v1"),
			Kind:       pulumi.String("Pod"),
			Metadata: &metav1.ObjectMetaArgs{
				Namespace: pulumi.String("foo"),
				Name:      pulumi.String("bar"),
			},
			Spec: &corev1.PodSpecArgs{
				Containers: corev1.ContainerArray{
					&corev1.ContainerArgs{
						Name:  pulumi.String("nginx"),
						Image: pulumi.String("nginx:1.14-alpine"),
						Resources: &corev1.ResourceRequirementsArgs{
							Limits: pulumi.StringMap{
								"memory": pulumi.String("20Mi"),
								"cpu":    pulumi.String("0.2"),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}

TypeScript

kube2pulumi typescript -f ./pod.yaml
import * as pulumi from "@pulumi/pulumi";
import * as kubernetes from "@pulumi/kubernetes";

const fooBarPod = new kubernetes.core.v1.Pod("fooBarPod", {
    apiVersion: "v1",
    kind: "Pod",
    metadata: {
        namespace: "foo",
        name: "bar",
    },
    spec: {
        containers: [{
            name: "nginx",
            image: "nginx:1.14-alpine",
            resources: {
                limits: {
                    memory: "20Mi",
                    cpu: 0.2,
                },
            },
        }],
    },
});

Python

kube2pulumi python -f ./pod.yaml
import pulumi
import pulumi_kubernetes as kubernetes

foo_bar_pod = kubernetes.core.v1.Pod("fooBarPod",
    api_version="v1",
    kind="Pod",
    metadata={
        "namespace": "foo",
        "name": "bar",
    },
    spec={
        "containers": [{
            "name": "nginx",
            "image": "nginx:1.14-alpine",
            "resources": {
                "limits": {
                    "memory": "20Mi",
                    "cpu": "0.2",
                },
            },
        }],
    })

C#

kube2pulumi csharp -f ./pod.yaml
using Pulumi;
using Kubernetes = Pulumi.Kubernetes;

class MyStack : Stack
{
    public MyStack()
    {
        var fooBarPod = new Kubernetes.Core.V1.Pod("fooBarPod", new Kubernetes.Types.Inputs.Core.V1.PodArgs
        {
            ApiVersion = "v1",
            Kind = "Pod",
            Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
            {
                Namespace = "foo",
                Name = "bar",
            },
            Spec = new Kubernetes.Types.Inputs.Core.V1.PodSpecArgs
            {
                Containers = 
                {
                    new Kubernetes.Types.Inputs.Core.V1.ContainerArgs
                    {
                        Name = "nginx",
                        Image = "nginx:1.14-alpine",
                        Resources = new Kubernetes.Types.Inputs.Core.V1.ResourceRequirementsArgs
                        {
                            Limits = 
                            {
                                { "memory", "20Mi" },
                                { "cpu", "0.2" },
                            },
                        },
                    },
                },
            },
        });
    }

}

Java

kube2pulumi java -f ./pod.yaml
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.kubernetes.core_v1.Pod;
import com.pulumi.kubernetes.core_v1.PodArgs;
import com.pulumi.kubernetes.meta_v1.inputs.ObjectMetaArgs;
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 fooBarPod = new Pod("fooBarPod", PodArgs.builder()
                .apiVersion("v1")
                .kind("Pod")
                .metadata(ObjectMetaArgs.builder()
                        .namespace("foo")
                        .name("bar")
                        .build())
                .spec(PodSpecArgs.builder()
                        .containers(ContainerArgs.builder()
                                .name("nginx")
                                .image("nginx:1.14-alpine")
                                .resources(ResourceRequirementsArgs.builder()
                                        .limits(Map.ofEntries(
                                                Map.entry("memory", "20Mi"),
                                                Map.entry("cpu", 0.2)
                                        ))
                                        .build())
                                .build())
                        .build())
                .build());

    }
}

Limitations

kube2pulumi currently does not handle the conversion of CustomResourceDefinitions or CustomResources. However, our new tool crd2pulumi, creates strongly-typed args for a Resource based on your CRD! If using CRD/CR's make sure to check out the following tool!

  1. crd2pulumi README