Deploying an ASP.NET core application into a Docker image within Kubernetes

In the previous post we looked and an “off the shelf” image of nginx, which we deployed to Kubernetes and were able to access externally using Ingress. This post follows on from that one, so do refer back to it if you have any issues with the following configurations etc.

Let’s look at the steps for deploying our own Docker image to k8s and better still let’s deploy a dotnet core webapp.

Note: Kubernetes is deprecating its support for Docker, however this does not mean we cannot deployed docker images, just that we need to use the docker shim or generated container-d (or other container) images.

The App

We’ll create a standard dotnet ASP.NET core Razor application which you can obviously do what you wish to, but we’ll take the default implementation and turn this into a docker image and then deploy it to k8s.

So to start with…

  • Create a .NET core Razor application (mine’s named razordemo), you can do this from Visual Studio or using
    dotnet new webapp -o razordemo --no-https -f net5.0
    
  • If you’re running this on a remote machine don’t forget to change launchSettings.json localhost to 0.0.0.0 if you need to.
  • Run dotnet build

It’d be good to see this is all working, so if let’s run the demo using

dotnet run

Now use your browser to access http://your-server-ip:5000/ and you should see the Razor demo home page, or use curl to see if you get valid HTML returned, i.e.

curl http://your-server-ip:5000

Generating the Docker image

Note: If you changed launchSettings.json to use 0.0.0.0, reset this to localhost.

Here’s the Dockerfile for building an image, it’s basically going to publish a release build of our Razor application then set up the image to run the razordemo.dll via dotnet from a Docker instance.

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY razordemo.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "razordemo.dll"]

Now run docker build using the following

docker build . -t razordemo --no-cache

If you want to check the image works as expect then run the following

docker run -d -p 5000:80 razordemo 

Now check the image is running okay by using curl as we did previously. If all worked you should see the Razor demo home page again, but now we’re seeing if within the docker instance.

Docker in the local registry

Next up, we want to deploy this docker image to k8s.

k8s will try to get an image from a remote registry and we don’t want to deploy this image outside of our network, so we need to rebuild the image, slightly differently using

docker build . -t localhost:32000/razordemo --no-cache

Reference: see Using the built-in registry for more information on the built-in registry.

Before going any further, I’m using Ubuntu and micro8s, so will need to enable the local registry using

microk8s enable registry

I can’t recall if this is required, but I also enabled k8s DNS using

microk8s.enable dns

Find the image ID for our generated image using

docker images

Now use the following commands, where {the image id} was the one found from the above command

docker tag {the image id} localhost:32000/razordemo
docker push localhost:32000/razordemo

The configuration

This is a configuration based upon my previous post (the file is named razordemo.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  selector:
    matchLabels:
      run: webapp
  replicas: 1
  template:
    metadata:
      labels:
        run: webapp
    spec:
      containers:
      - name: webapp
        image: localhost:32000/razordemo
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: webapp
  labels:
    run: webapp
spec:
  ports:
    - port: 80
      protocol: TCP
  selector:
    run: webapp
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: razor-ingress
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp
            port: 
              number: 80

Now apply this configuration to k8s using (don’t forget to change the file name to whatever you named your file)

kubectl apply -f ./razordemo.yaml

Now we should be able to check the deployed image, by either using the k8s dashboard or run

kubectl get ep webapp

Note the endpoint and curl to that endpoint, if all worked well you should be able to see the ASP.NET generate home page HTML and better still access http://your-server-ip from another machine and see the webpage.