Skip to content

Commit

Permalink
Add C# Kubernetes Guestbook example (pulumi#477)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukehoban committed Nov 27, 2019
1 parent 5e15b35 commit 9b685eb
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 0 deletions.
12 changes: 12 additions & 0 deletions kubernetes-cs-guestbook/Guestbook.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Pulumi.Kubernetes" Version="1.3.2-preview" />
</ItemGroup>

</Project>
270 changes: 270 additions & 0 deletions kubernetes-cs-guestbook/Program.cs
Original file line number Diff line number Diff line change
@@ -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<int> 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<string>{
{ "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<string>{
{ "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<string>{
{ "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<string> frontendIP;
if (isMiniKube)
{
frontendIP = frontendService.Spec.Apply(spec => spec.ClusterIP);
}
else
{
frontendIP = frontendService.Status.Apply(status => status.LoadBalancer.Ingress[0].Hostname);
}
return new Dictionary<string, object>{
{ "frontendIp", frontendIP },
};
});
}
}
8 changes: 8 additions & 0 deletions kubernetes-cs-guestbook/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -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
66 changes: 66 additions & 0 deletions kubernetes-cs-guestbook/README.md
Original file line number Diff line number Diff line change
@@ -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 <value>
```

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)
Binary file added kubernetes-cs-guestbook/imgs/guestbook.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9b685eb

Please sign in to comment.