Today, we will continue our journey with Nuke by adding new targets to the solution presented in Nuke: Deploy ASP.NET Web App to Azure. This time, we will deploy our app to a local Kubernetes cluster using Helm.
But first, we will need the following:
A standalone Kubernetes server and client.
Generating the build number
Our first target will get the build number using GitVersion (we discussed it in Semantic Versioning with GitVersion). Let's start by adding the following NuGet package::
Next, add the following namespaces to access all gitversion
commands:
using static Nuke.Common.Tools.GitVersion.GitVersionTasks;
using Nuke.Common.Tools.GitVersion;
Add a variable to store the generated build number:
private string BuildNumber;
And now, the target itself:
Target GetBuildNumber => _ => _
.Executes(() =>
{
var (result, _) = GitVersion();
BuildNumber = result.SemVer;
});
Building the Docker image
The first step is to create a Dockerfile
in our project folder as follows:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore "./nuke-sandbox-app/nuke-sandbox-app.csproj"
# Build and publish a release
RUN dotnet publish "./nuke-sandbox-app/nuke-sandbox-app.csproj" -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "nuke-sandbox-app.dll"]
Add the following namespaces to access all docker
commands:
using static Nuke.Common.Tools.Docker.DockerTasks;
using Nuke.Common.Tools.Docker;
Add a variable to store the Docker image repository used in the project:
private readonly string Repository = "raulnq/nuke-sandbox-app";
And for the final step, add the target:
Target BuildImage => _ => _
.DependsOn(GetBuildNumber)
.Executes(() =>
{
var dockerFile = RootDirectory / "nuke-sandbox-app" / "Dockerfile";
var image = $"{Repository}:{BuildNumber}";
DockerBuild(s => s
.SetPath(RootDirectory)
.SetFile(dockerFile)
.SetTag(image)
);
});
Installing the Helm package
And finally, here is the step to install the Helm package in the Kubernetes cluster. You can first check Useful commands for Helm. Go to your solution folder and run the following commands to create the Helm package:
mkdir helm
cd helm
helm create nuke-sandbox-app
Keep only these files in your Helm package:
helm\nuke-sandbox-app
|-- templates
| |-- _helpers.tpl
| |-- deployment.yaml
| `-- service.yaml
|-- .helmignore
|-- Chart.yaml
`-- values.yaml
Modify the deployment.yaml
file as follows:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "nuke-sandbox-app.fullname" . }}
labels:
{{- include "nuke-sandbox-app.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "nuke-sandbox-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "nuke-sandbox-app.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
The service.yaml
file:
apiVersion: v1
kind: Service
metadata:
name: {{ include "nuke-sandbox-app.fullname" . }}
labels:
{{- include "nuke-sandbox-app.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "nuke-sandbox-app.selectorLabels" . | nindent 4 }}
And the values.yaml
file:
replicaCount: 1
image:
repository: raulnq/nuke-sandbox-app
pullPolicy: IfNotPresent
tag: "1.0"
nameOverride: ""
fullnameOverride: ""
service:
type: ClusterIP
port: 80
Go back to the build.cs
file and add:
using static Nuke.Common.Tools.Helm.HelmTasks;
using Nuke.Common.Tools.Helm;
using System.Collections.Generic;
Add a variable to store the Helm release name used in the project:
private readonly string ReleaseName = "release-nuke-sandbox-app";
To wrap up, we will add two targets: one to install and the other to uninstall the Helm package:
Target HelmInstall => _ => _
.DependsOn(BuildImage)
.Executes(() =>
{
var chart = HelmDirectory / "nuke-sandbox-app";
HelmUpgrade(s => s
.SetRelease(ReleaseName)
.SetSet(new Dictionary<string, object>() { { "image.tag", BuildNumber }, { "image.repository", Repository } })
.SetChart(chart)
.EnableInstall()
);
});
Target HelmUninstall => _ => _
.Executes(() =>
{
HelmDelete(s => s
.SetReleaseNames(ReleaseName)
);
});
That's it! Now it's time to run our Nuke command:
nuke HelmInstall
We can check our deployment with kubectl get deployments
:
NAME READY UP-TO-DATE AVAILABLE AGE
release-nuke-sandbox-app 1/1 1 1 18s
And uninstall when needed:
nuke HelmUninstall
You can find the updated solution here.