Simple script for building and publishing .NET Core application to Docker

Build and publish .NET Core application to Docker container or Kubernetes

Recently I wanted to try to spin up a simple .NET Core application on my local cluster which I built in my previous article Manual setup of Kubernetes cluster on a Virtual Machine with kubeadm. The problem I had is that I needed to test applications in this cluster and deploy them as service in order to monitor potential issues behavior.

As deployment of Kubernetes service needs an image to pull from, I decided to use dockerhub to push my test images, but they first needed to be created.

Building the image from the scratch

When building the image it is important that you have a clean environment and have only binaries in the target image which you will use to run the application. For his purpose I picked an approach similar to the one Visaul Studio provides when you select Docker support in the new .NET Core project.

The image building process consists of:

I used a sample project of a simple service that just logs start and stop of the service. Since this code is not in the master branch, that means I need only specific branch so I will pull only the branch I want to test the code from on the K8 cluster.

git clone --single-branch -b single-library https://github.com/dejanstojanovic/dotnetcore-windows-linux-service.git
    

This line will only clone single-library branch to an intermediate container instance and build the code from that code base. This repository is public but for private repository you can use Github url with supplied credentials to clone the repository

git clone --single-branch -b single-library https://usernam:password@github.com/dejanstojanovic/dotnetcore-windows-linux-service.git
    

For this repository this is not necessary because it is public. I am also targeting linux-x64 Runtime IDentifier, which will work without any problem with dotnet Core SDK image, but you can target any other Linux distro specific runtime. List of the supported RIDs is https://docs.microsoft.com/en-us/dotnet/core/rid-catalog#linux-rids

FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src
RUN git clone --single-branch -b single-library https://github.com/dejanstojanovic/dotnetcore-windows-linux-service.git
RUN cd dotnetcore-windows-linux-service
RUN dotnet publish "./dotnetcore-windows-linux-service/Sample.Service/Sample.Service.csproj" --configuration=Release --runtime=linux-x64 --output=/app

FROM microsoft/dotnet:2.1.401-sdk AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "Sample.Service.dll"]

    

Tagging and pushing to the dockerhub

This Docker file will build you a local image but after every build you will have to tag the image and push it to the docker hub repository of your own in order to pull it when initiating deployment for Kubernetes service. Docker does not cleanup container after they are stopped so after every image build you will have trash left in your machine form the dean intermediate container used for image build.

To do all this I used bash and wrapped the Docker file with it to do this additional work which is:

  • tagging the image (in this case I am using the timestamp of the building time to tag the image)
  • pushing image to dockerhub repository
#!/bin/bash

#set dockerhub account
dockeraccount="dejanstojanovic"
servicename="sampleservice"

#get timestamp for the tag
timestamp=$(date +%Y%m%d%H%M%S)

#build image
sudo docker build -t $servicename:$timestamp .

#remove dangling images
sudo docker system prune -f

#push to dockerhub
sudo docker login
#sudo docker login -u username -p password
sudo docker tag $servicename:$timestamp $dockeraccount/$servicename:$timestamp
sudo docker push $dockeraccount/$servicename:$timestamp
    

Docker is already authenticated on my image build machine so I do not need to authenticate but if you want to automate you can use -u (--username) and -p (--password) params for docker login to authenticate before pushing the image to dockerhub.

Once you have all your values entered you need to add execute permissions to the file with chmod

sudo chmod+x image-build.sh
    

Now when you execute the script you will have the image uploaded to your dockerhub repository.

Spinning up the image in Kubernetes

Now when you have the image in the docker hub you can spin it up in the Kubernetes cluster. Before you define the deployment and the image repository to create containers from we are going to need the service created in the Kubernetes cluster.

I prefer declarative way of doing this with yaml files, so for the service I will use the pre-defined service yaml configuration

apiVersion: v1
kind: Service
metadata:
  name: sample-service-app-service
  labels:
    app: sample-service-app
spec:
  type: NodePort
  ports:
  - port: 5100
    nodePort: 30001
    protocol: TCP
  selector:
    app: sample-service-app
    

To create this service, just tell kubectl to apply this configuration

sudo kubectl apply -f sample-service-app.yml
    

Now that we have the service we can create the deployment in the cluster where we are going to use our image we built and run it in sample-service-app service

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-service-app-deployment
spec:
  replicas: 10
  minReadySeconds: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: sample-service-app
    spec:
      containers:
      - name: sample-service-app-pod
        image: dejanstojanovic/sampleservice:latest
        ports:
        - containerPort: 5100
        env:
        - name: ASPNETCORE_ENVIRONMENT
          value: Production
    

Service and deployment and bond with same tag sample-service-app. Deployment is add to the K8 cluster same way we added the service to the cluster through kubectl.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

.NET

read more

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

Comments for this article