Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add C# Kubernetes Guestbook example #477

Merged
merged 3 commits into from
Nov 27, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.4.0-preview-alpha.1574382353" />
</ItemGroup>

</Project>
254 changes: 254 additions & 0 deletions kubernetes-cs-guestbook/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
// 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 redisMasterLables = new InputMap<string>{
lukehoban marked this conversation as resolved.
Show resolved Hide resolved
{"app", "redis-master"},
};

var redisMasterDeployment = new Pulumi.Kubernetes.Apps.V1.Deployment("redis-master", new DeploymentArgs
{
Spec = new DeploymentSpecArgs
{
Selector = new LabelSelectorArgs
{
MatchLabels = redisMasterLables,
lukehoban marked this conversation as resolved.
Show resolved Hide resolved
},
Template = new PodTemplateSpecArgs
{
Metadata = new ObjectMetaArgs
{
Labels = redisMasterLables,
lukehoban marked this conversation as resolved.
Show resolved Hide resolved
},
Spec = new PodSpecArgs
{
Containers = {
lukehoban marked this conversation as resolved.
Show resolved Hide resolved
new ContainerArgs
{
Name = "master",
Image = "k8s.gcr.io/redis:e2e",
Resources = new ResourceRequirementsArgs
{
Requests = {
{ "cpu", "100m"},
lukehoban marked this conversation as resolved.
Show resolved Hide resolved
{ "memory", "100Mi"},
lukehoban marked this conversation as resolved.
Show resolved Hide resolved
},
},
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 redisReplicaLables = 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 = redisReplicaLables,
},
Template = new PodTemplateSpecArgs
{
Metadata = new ObjectMetaArgs
{
Labels = redisReplicaLables,
},
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.