diff --git a/kubernetes-cs-guestbook/Guestbook.csproj b/kubernetes-cs-guestbook/Guestbook.csproj
new file mode 100644
index 000000000..2db3916df
--- /dev/null
+++ b/kubernetes-cs-guestbook/Guestbook.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp3.0
+
+
+
+
+
+
+
diff --git a/kubernetes-cs-guestbook/Program.cs b/kubernetes-cs-guestbook/Program.cs
new file mode 100644
index 000000000..2b7a8d030
--- /dev/null
+++ b/kubernetes-cs-guestbook/Program.cs
@@ -0,0 +1,270 @@
+// Copyright 2016-2019, Pulumi Corporation. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Pulumi;
+using Pulumi.Kubernetes.Core.V1;
+using Pulumi.Kubernetes.Types.Inputs.Core.V1;
+using Pulumi.Kubernetes.Types.Inputs.Apps.V1;
+using Pulumi.Kubernetes.Types.Inputs.Meta.V1;
+using Pulumi.Kubernetes.Types.Inputs.ApiExtensions.V1Beta1;
+
+class Program
+{
+ static Task Main(string[] args)
+ {
+ return Deployment.RunAsync(() =>
+ {
+ // Minikube does not implement services of type `LoadBalancer`; require the user to
+ // specify if we're running on minikube, and if so, create only services of type
+ // ClusterIP.
+ var config = new Config();
+ var isMiniKube = config.GetBoolean("isMiniKube") ?? false;
+
+ //
+ // REDIS MASTER.
+ //
+
+ var redisMasterLabels = new InputMap{
+ { "app", "redis-master" },
+ };
+
+ var redisMasterDeployment = new Pulumi.Kubernetes.Apps.V1.Deployment("redis-master", new DeploymentArgs
+ {
+ Spec = new DeploymentSpecArgs
+ {
+ Selector = new LabelSelectorArgs
+ {
+ MatchLabels = redisMasterLabels,
+ },
+ Template = new PodTemplateSpecArgs
+ {
+ Metadata = new ObjectMetaArgs
+ {
+ Labels = redisMasterLabels,
+ },
+ Spec = new PodSpecArgs
+ {
+ Containers =
+ {
+ new ContainerArgs
+ {
+ Name = "master",
+ Image = "k8s.gcr.io/redis:e2e",
+ Resources = new ResourceRequirementsArgs
+ {
+ Requests =
+ {
+ { "cpu", "100m" },
+ { "memory", "100Mi" },
+ },
+ },
+ Ports =
+ {
+ new ContainerPortArgs { ContainerPortValue = 6379 }
+ },
+ },
+ },
+ },
+ },
+ },
+ });
+
+ var redisMasterService = new Pulumi.Kubernetes.Core.V1.Service("redis-master", new ServiceArgs
+ {
+ Metadata = new ObjectMetaArgs
+ {
+ Labels = redisMasterDeployment.Metadata.Apply(metadata => metadata.Labels),
+ },
+ Spec = new ServiceSpecArgs
+ {
+ Ports =
+ {
+ new ServicePortArgs
+ {
+ Port = 6379,
+ TargetPort = 6379,
+ },
+ },
+ Selector = redisMasterDeployment.Spec.Apply(spec => spec.Template.Metadata.Labels),
+ }
+ });
+
+ //
+ // REDIS REPLICA.
+ //
+
+ var redisReplicaLabels = new InputMap{
+ { "app", "redis-replica" },
+ };
+
+ var redisReplicaDeployment = new Pulumi.Kubernetes.Apps.V1.Deployment("redis-replica", new DeploymentArgs
+ {
+ Spec = new DeploymentSpecArgs
+ {
+ Selector = new LabelSelectorArgs
+ {
+ MatchLabels = redisReplicaLabels,
+ },
+ Template = new PodTemplateSpecArgs
+ {
+ Metadata = new ObjectMetaArgs
+ {
+ Labels = redisReplicaLabels,
+ },
+ Spec = new PodSpecArgs
+ {
+ Containers =
+ {
+ new ContainerArgs
+ {
+ Name = "replica",
+ Image = "gcr.io/google_samples/gb-redisslave:v1",
+ Resources = new ResourceRequirementsArgs
+ {
+ Requests =
+ {
+ { "cpu", "100m" },
+ { "memory", "100Mi" },
+ },
+ },
+ // If your cluster config does not include a dns service, then to instead access an environment
+ // variable to find the master service's host, change `value: "dns"` to read `value: "env"`.
+ Env =
+ {
+ new EnvVarArgs
+ {
+ Name = "GET_HOSTS_FROM",
+ Value = "dns"
+ },
+ },
+ Ports =
+ {
+ new ContainerPortArgs { ContainerPortValue = 6379 }
+ },
+ },
+ },
+ },
+ },
+ },
+ });
+
+ var redisReplicaService = new Pulumi.Kubernetes.Core.V1.Service("redis-replica", new ServiceArgs
+ {
+ Metadata = new ObjectMetaArgs
+ {
+ Labels = redisReplicaDeployment.Metadata.Apply(metadata => metadata.Labels),
+ },
+ Spec = new ServiceSpecArgs
+ {
+ Ports =
+ {
+ new ServicePortArgs
+ {
+ Port = 6379,
+ TargetPort = 6379,
+ },
+ },
+ Selector = redisReplicaDeployment.Spec.Apply(spec => spec.Template.Metadata.Labels),
+ }
+ });
+
+ //
+ // FRONTEND
+ //
+
+ var frontendLabels = new InputMap{
+ { "app", "frontend" },
+ };
+
+ var frontendDeployment = new Pulumi.Kubernetes.Apps.V1.Deployment("frontend", new DeploymentArgs
+ {
+ Spec = new DeploymentSpecArgs
+ {
+ Selector = new LabelSelectorArgs
+ {
+ MatchLabels = frontendLabels,
+ },
+ Replicas = 3,
+ Template = new PodTemplateSpecArgs
+ {
+ Metadata = new ObjectMetaArgs
+ {
+ Labels = frontendLabels,
+ },
+ Spec = new PodSpecArgs
+ {
+ Containers =
+ {
+ new ContainerArgs
+ {
+ Name = "php-redis",
+ Image = "gcr.io/google-samples/gb-frontend:v4",
+ Resources = new ResourceRequirementsArgs
+ {
+ Requests = {
+ { "cpu", "100m" },
+ { "memory", "100Mi" },
+ },
+ },
+ // If your cluster config does not include a dns service, then to instead access an environment
+ // variable to find the master service's host, change `value: "dns"` to read `value: "env"`.
+ Env =
+ {
+ new EnvVarArgs
+ {
+ Name = "GET_HOSTS_FROM",
+ Value = "dns", /* Value = "env"*/
+ },
+ },
+ Ports =
+ {
+ new ContainerPortArgs { ContainerPortValue = 80 }
+ },
+ },
+ },
+ },
+ },
+ },
+ });
+
+ var frontendService = new Pulumi.Kubernetes.Core.V1.Service("frontend", new ServiceArgs
+ {
+ Metadata = new ObjectMetaArgs
+ {
+ Labels = frontendDeployment.Metadata.Apply(metadata => metadata.Labels),
+ },
+ Spec = new ServiceSpecArgs
+ {
+ Type = isMiniKube ? "ClusterIP" : "LoadBalancer",
+ Ports =
+ {
+ new ServicePortArgs
+ {
+ Port = 80,
+ TargetPort = 80,
+ },
+ },
+ Selector = frontendDeployment.Spec.Apply(spec => spec.Template.Metadata.Labels),
+ }
+ });
+
+ Output frontendIP;
+ if (isMiniKube)
+ {
+ frontendIP = frontendService.Spec.Apply(spec => spec.ClusterIP);
+ }
+ else
+ {
+ frontendIP = frontendService.Status.Apply(status => status.LoadBalancer.Ingress[0].Hostname);
+ }
+
+ return new Dictionary{
+ { "frontendIp", frontendIP },
+ };
+
+ });
+ }
+}
diff --git a/kubernetes-cs-guestbook/Pulumi.yaml b/kubernetes-cs-guestbook/Pulumi.yaml
new file mode 100644
index 000000000..255bc7929
--- /dev/null
+++ b/kubernetes-cs-guestbook/Pulumi.yaml
@@ -0,0 +1,8 @@
+name: guestbook-csharp
+runtime: dotnet
+description: Kubernetes Guestbook example based on https://kubernetes.io/docs/tutorials/stateless-application/guestbook/
+template:
+ config:
+ isMinikube:
+ description: Whether you are deploying to minikube
+ default: true
diff --git a/kubernetes-cs-guestbook/README.md b/kubernetes-cs-guestbook/README.md
new file mode 100644
index 000000000..b7867720b
--- /dev/null
+++ b/kubernetes-cs-guestbook/README.md
@@ -0,0 +1,66 @@
+[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new)
+
+# Kubernetes Guestbook (Simple Variant)
+
+A version of the [Kubernetes Guestbook](https://kubernetes.io/docs/tutorials/stateless-application/guestbook/)
+application using Pulumi.
+
+## Running the App
+
+Follow the steps in [Pulumi Installation](https://www.pulumi.com/docs/get-started/install/) and [Kubernetes Setup](https://www.pulumi.com/docs/intro/cloud-providers/kubernetes/setup/) to get Pulumi working with Kubernetes.
+
+Create a new stack:
+
+```sh
+$ pulumi stack init
+Enter a stack name: testbook
+```
+
+This example will attempt to expose the Guestbook application to the Internet with a `Service` of
+type `LoadBalancer`. Since minikube does not support `LoadBalancer`, the Guestbook application
+already knows to use type `ClusterIP` instead; all you need to do is to tell it whether you're
+deploying to minikube:
+
+```sh
+pulumi config set isMinikube
+```
+
+Perform the deployment:
+
+```sh
+$ pulumi up
+Updating stack 'testbook'
+Performing changes:
+
+ Type Name Status
+ + pulumi:pulumi:Stack guestbook-csharp-testbook created
+ + ├─ kubernetes:apps:Deployment redis-replica created
+ + ├─ kubernetes:apps:Deployment frontend created
+ + ├─ kubernetes:apps:Deployment redis-master created
+ + ├─ kubernetes:core:Service redis-master created
+ + ├─ kubernetes:core:Service redis-replica created
+ + └─ kubernetes:core:Service frontend created
+
+Outputs:
+ + frontendIp: "35.232.147.18"
+
+Resources:
+ + 7 created
+
+Duration: 17s
+
+Permalink: https://app.pulumi.com/lukehoban/guestbook-csharp/testbook/updates/1
+```
+
+And finally - open the application in your browser to see the running application. If you're running
+macOS you can simply run:
+
+```sh
+open $(pulumi stack output frontendIp)
+```
+
+> _Note_: minikube does not support type `LoadBalancer`; if you are deploying to minikube, make sure
+> to run `kubectl port-forward svc/frontend 8080:80` to forward the cluster port to the local
+> machine and access the service via `localhost:8080`.
+
+![Guestbook in browser](./imgs/guestbook.png)
diff --git a/kubernetes-cs-guestbook/imgs/guestbook.png b/kubernetes-cs-guestbook/imgs/guestbook.png
new file mode 100644
index 000000000..e32eaffdc
Binary files /dev/null and b/kubernetes-cs-guestbook/imgs/guestbook.png differ