├── .dockerignore
├── src
├── GreetingsService
│ ├── appsettings.json
│ ├── appsettings.Development.json
│ ├── GreetingsService.csproj
│ └── Program.cs
└── NetOnKubernetes.sln
├── .gitignore
├── README.md
├── Dockerfile
└── greetings-service-deployment.yaml
/.dockerignore:
--------------------------------------------------------------------------------
1 | bin/
2 | obj/
--------------------------------------------------------------------------------
/src/GreetingsService/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Information"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/src/GreetingsService/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Information"
6 | },
7 | "AllowedHosts": "*"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folder
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # MsTest test results
6 | TestResults
7 |
8 | ## Ignore Visual Studio temporary files, build results, and
9 | ## files generated by popular Visual Studio add-ons.
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.sln.docstates
15 | .vs/
16 |
17 | # Visual Studio profiler
18 | *.psess
19 | *.vsp
20 | *.vspx
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # .NET on Kubernetes
2 |
3 | This is a demo repo to demonstrate techniques for building .NET services for Kubernetes
4 |
5 | Using with Docker Desktop with Kubernetes installed:
6 |
7 | 1. Build the container image:
8 |
9 | `docker build -t greetings-service:0.0.1 .`
10 |
11 | 2. Deploy to Kubernetes:
12 |
13 | `kubectl apply -f greetings-service-deployment.yaml`
--------------------------------------------------------------------------------
/src/GreetingsService/GreetingsService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | true
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim AS runtime
2 | WORKDIR /app
3 |
4 | FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim AS sdk
5 |
6 | ARG build_number=0.0.1
7 |
8 | WORKDIR /app
9 |
10 | COPY src/ .
11 |
12 | # restore nuget packages
13 | RUN dotnet restore
14 |
15 | # build
16 | RUN dotnet build --no-restore "-p:Version=${build_number}"
17 |
18 | # test
19 | # RUN dotnet test --no-build GreetingService.Tests/GreetingService.Tests.csproj
20 |
21 | # publish
22 | RUN dotnet publish --no-build -o output
23 |
24 | FROM runtime AS runtime
25 | # ENV ASPNETCORE_URLS=http://+:5432
26 |
27 | WORKDIR /app
28 | COPY --from=sdk /app/output/ ./
29 | ENTRYPOINT ["./GreetingsService"]
--------------------------------------------------------------------------------
/src/NetOnKubernetes.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31919.166
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A1058638-A938-4EC3-810C-1BCB56D697E6}"
7 | ProjectSection(SolutionItems) = preProject
8 | ..\.dockerignore = ..\.dockerignore
9 | ..\.gitignore = ..\.gitignore
10 | ..\Dockerfile = ..\Dockerfile
11 | ..\greetings-service-deployment.yaml = ..\greetings-service-deployment.yaml
12 | ..\README.md = ..\README.md
13 | EndProjectSection
14 | EndProject
15 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreetingsService", "GreetingsService\GreetingsService.csproj", "{76B3A9A2-080B-4345-B9C0-D32BAC4F3229}"
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Release|Any CPU = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {76B3A9A2-080B-4345-B9C0-D32BAC4F3229}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {76B3A9A2-080B-4345-B9C0-D32BAC4F3229}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {76B3A9A2-080B-4345-B9C0-D32BAC4F3229}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {76B3A9A2-080B-4345-B9C0-D32BAC4F3229}.Release|Any CPU.Build.0 = Release|Any CPU
27 | EndGlobalSection
28 | GlobalSection(SolutionProperties) = preSolution
29 | HideSolutionNode = FALSE
30 | EndGlobalSection
31 | GlobalSection(ExtensibilityGlobals) = postSolution
32 | SolutionGuid = {EDB63460-174D-4987-856A-44966CF852EC}
33 | EndGlobalSection
34 | EndGlobal
35 |
--------------------------------------------------------------------------------
/greetings-service-deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: greetings-service
5 | data:
6 | GREETINGS_MESSAGE: "Hello World From Config Map!"
7 | GREETINGs_NUMBER: "1234"
8 |
9 | ---
10 | apiVersion: v1
11 | kind: Service
12 | metadata:
13 | name: greetings-service-service
14 | spec:
15 | selector:
16 | app: greetings-service
17 | ports:
18 | - name: greetings-service-service-port
19 | protocol: TCP
20 | port: 3456
21 | targetPort: 5432
22 | nodePort: 30001
23 | type: LoadBalancer
24 |
25 | ---
26 | apiVersion: apps/v1
27 | kind: Deployment
28 | metadata:
29 | name: greetings-service-deployment
30 | labels:
31 | app: greetings-service
32 | version: v1
33 | annotations:
34 | prometheus.io/port: '9216'
35 | prometheus.io/scrape: 'true'
36 | spec:
37 | replicas: 2
38 | selector:
39 | matchLabels:
40 | app: greetings-service
41 | template:
42 | metadata:
43 | labels:
44 | app: greetings-service
45 | spec:
46 | containers:
47 | - name: greetings-service
48 | image: greetings-service:0.0.5
49 | envFrom:
50 | - configMapRef:
51 | name: greetings-service
52 | resources:
53 | limits:
54 | memory: 200Mi
55 | cpu: 100m
56 | requests:
57 | memory: 200Mi
58 | cpu: 100m
59 | livenessProbe:
60 | httpGet:
61 | path: /live
62 | port: 5432
63 | readinessProbe:
64 | httpGet:
65 | path: /ready
66 | port: 5432
67 | lifecycle:
68 | postStart:
69 | httpGet:
70 | path: /postStart
71 | port: 5432
72 | preStop:
73 | httpGet:
74 | path: /preStop
75 | port: 5432
76 |
--------------------------------------------------------------------------------
/src/GreetingsService/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.Configuration;
4 | using Microsoft.Extensions.Logging;
5 | using System.Text.Json;
6 | using Prometheus;
7 | using Microsoft.AspNetCore.Http;
8 |
9 | namespace GreetingsService;
10 |
11 | public static class Program
12 | {
13 | public static void Main()
14 | {
15 | var builder = WebApplication.CreateBuilder();
16 | builder.Logging.ClearProviders();
17 | builder.Logging.AddJsonConsole(options =>
18 | {
19 | options.IncludeScopes = false;
20 | options.TimestampFormat = "yyyy:MM:dd hh:mm:ss ";
21 | options.JsonWriterOptions = new JsonWriterOptions
22 | {
23 | // sometimes useful to change this to true when testing locally.
24 | // but it needs to be false for Fluent Bit to process log lines correctly
25 | Indented = false
26 | };
27 | });
28 | builder.WebHost.ConfigureKestrel(options =>
29 | {
30 | options.ListenAnyIP(5432);
31 | });
32 |
33 | var hasStarted = false;
34 | var app = builder.Build();
35 |
36 | // configure the Prometheus metrics endpoint, should appear at /metrics
37 | app.UseRouting();
38 | app.UseEndpoints(endpoints =>
39 | {
40 | endpoints.MapMetrics();
41 | });
42 |
43 | // liveness probe, return HTTP status code 500 if you want the container to be restarted
44 | app.MapGet("/live", () => Results.Ok());
45 | // rediness probe, return 200 OK when the application is ready to respond to requests.
46 | // this can turn on and off if necessary, for example if a backend service is not available.
47 | app.MapGet("/ready", () => hasStarted ? Results.Ok() : Results.StatusCode(500));
48 |
49 | // PostStart and PreStop event hooks.
50 | app.MapGet("/postStart", (ILogger logger)
51 | => logger.LogInformation("PostStart event"));
52 | app.MapGet("/preStop", (ILogger logger)
53 | => logger.LogInformation("PreStop event"));
54 |
55 | app.MapGet("/", (IConfiguration configuration) =>
56 | {
57 | var message = configuration["GREETINGS_MESSAGE"]
58 | ?? "Hello World! env var not found.";
59 | return new Greeting(message);
60 | });
61 |
62 | app.Run();
63 |
64 | // mark as true when complex startup logic has completed and the service is ready to take requests.
65 | hasStarted = true;
66 | }
67 | }
68 |
69 | public record Greeting(string Message);
70 |
71 | public class GreetingApp { }
--------------------------------------------------------------------------------