ASP.NET Core CI/CD on Azure Web App with Jenkins - Day One

Introduction

As the name implies, DevOps is the integration of development and operations. It is a new stream of automation that takes software development and its life cycle to the next level, thereby reducing manual and risk/error-prone situations. It adds value to the delivery and serves to enhance the quality of the software. In today's era, if we look around, we see a lot of tools and technologies built to leverage DevOps. One of them is Jenkins. Jenkins is not new, but its seamless and easy methodology of integration into any system has made it more robust and reliable. Gone are the days when integration and deployment were troublesome manual tasks. Having these kinds of tools in place helps a developer, in fact, the whole team, forget about the integration and deployment, as they know that there is an automated process in place to take care of this. This article will cover the topic of continuous integration and deployment using Jenkins in detail. This article will explain the concept of CI/CD, Jenkins, getting started with Jenkins, and integrating and deploying an ASP.NET Core application locally and to the Azure Service as well. While we go through, we’ll also cover topics like creating Azure service, creating Azure service principal, and configuring Jenkins on Azure.

Roadmap

The following is the road map we would be following to completely learn end-to-end development and configurations of Continuous Integration and Deployment (CI/CD) of Asp.Net Core Application on Azure Web App using Jenkins.

  • Day 1: Continuous Integration of ASP.NET Core application using Jenkins
  • Day 2: Publish the ASP.Net core application to Azure App Service and Configure Jenkins on Azure
  • Day 3: Integrate Jenkins with Azure Active Directory and Service Principal
  • Day 4: CI/CD of ASP.NET Core application on Azure using Jenkins Azure Pipeline.

DevOps

DevOps is the combination of different people, processes, and operation tools. It helps the development and operations team in providing a common, mutually understandable platform. It segregates and draws the line between where the development team stops and where the operation team starts. The tools and technologies for continuous integration and deployment are part of DevOps which helps fetch the committed code, restore the dependencies, compile the application, run the unit test cases (if any), deploy the application, and make sure it is up and running. There is a lot more that comes under DevOps that is out of the scope of this article, like monitoring the application and its related attributes.

Continuous Integration

The situation where a developer commits the code to a source control (be it SVN, Git or any other source control) and an operation/process/tool continuously monitoring that source control to fetch the fresh copy of the code, restore the dependencies, compile the code, run all the unit tests, integrate the code with the code of other developers, generate the report, notify team members and generate the artifacts and deployable package is known as Continuous Integration in simple terms. There are many more operations that could be part of Continuous Integration, but this is the basic flow to understand it.

Continuous Deployment

Continuous deployment is the next step that a DevOps operation/process/tool looks to. It helps the team continuously deploy the deployable package produced by CI based on certain parameters. These CI and CD steps are repetitive and are subject to how their triggers or callers are configured. The deployment could be done in stages, for example, there could be stages where the code first needs to be deployed on the dev server, then the QA server, then UAT, Stage, and then Prod. Continuous deployment thereby eliminates the manual process of deployment and based on certain triggers, parameters, and conditions, the code automatically is deployed and runs on the configured servers, also in sequential stages.

Jenkins

Jenkins being an open-source tool for automation, helps a team/developer build and test the software code continuously. It makes it easy for a developer to integrate and test the code without manual intervention. The tool could be set up to create a deployment pipeline that includes continuous integration of the code at each code commit, continuously testing the build, publishing artifacts and documents, and deploying the code. Jenkins could be configured on the servers, say it be development, staging, or production as per the deployment needs.

Azure Web App Service

Azure App Services serve as a Platform as a Service (PAAS) in the Azure cloud. Azure Web App Service makes it easy to host an application on a cloud platform with the liberty to build and deploy the application using tools, frameworks, and platforms as per discretion. It takes care of autoscaling, high availability, and load balancing of the applications so that developers do not have to worry about the environment and can focus on development.

Theme

This article series will explain using Jenkins for CI and CD of an ASP.NET Core web application on the local development environment, publishing the web application to Azure Web App Service, and configuring Jenkins on Azure for continuous integration and continuous deployment of the hosted application. GitHub will DevOps as a source control repository. We’ll create a pipeline using Jenkins that fetches the code from GitHub, builds the code, runs the tests, and deploys the package. This will be a repetitive task on each commit to the code located on GitHub.

Theme

Prerequisites

The following are the prerequisites for the developers to have on their machines before getting started.

  1. Visual Studio 2017/2019.
  2. Dotnet 2.1 SDK installed.
  3. Azure Subscription Free/Paid.
  4. Java 1.5 or higher.
  5. Git account
  6. Git for Windows

Installing Jenkins

Let’s install and get Jenkins running on the local development environment step by step.

Prerequisites

Jenkins is a Java application and needs Java Runtime to run. So, install Java 1.5 SDK or its higher version on the development machine. Download the latest version here.

Download and Install

Navigate to the URL -https://jenkins.io/ and follow the instructions given below.

  1. Click on the Download button and it will show the list of options for downloadable. We’ll use the Windows version of Jenkins downloadable. So, click on Windows in the LTS list and the download should begin immediately.
     LTS list
  2. Once downloaded, unzip the package and run the MSI to install Jenkins, follow the instructions of the wizard, and install Jenkins.
     MSI
  3. Jenkins will be installed on localhost:8080 by default. Once the installation is done. Navigate to the URL http://localhost:8080/ and the screen will appear to unlock Jenkins. Use the password stored in the file initialAdminPassword to unlock Jenkins as shown in the following image.
    Unlock Jenkins

Jenkins Plugins

Before working with Jenkins, there are few plugins that need to be installed. Since Jenkins supports many tools and frameworks, the desired set of tools needs to be plugged into Jenkins to get things working. We’ll install our needed set of plugins. Initially, install all of those that are recommended by clicking on the first option, “Install Suggested Plugins.”

Install Suggested Plugins

This will take a while while we install all the basic plugins for Jenkins.

Getting stert

Get it Running

Once the basic plugins are installed, it will ask to create an Admin user. You can provide the desired details and make sure you remember the username and password.

Save

Once you provide the details and click on “Save and Continue”, you are done installing Jenkins. To get it running, click on “Start using Jenkins”.

Save and Continue

To avoid a login each time you open Jenkins, you can go to the “Configure Global Security” section shown on the Jenkins dashboard. Check the “Allow anonymous read access” option.

Configure Global Security

Installing Custom Plugins

Since we will be using an Asp.Net application and unit tests, install the related plugins that support this application. Go to the Plugin manager and install MSBuild, MSTest, MSTestRunner, PowerShell, VSTestRunner, and Git plugins if those are not already installed.

Custom Plugins

Installing

ASP.NET Core Application

I have used ASP.Net Core MVC application version 2.1 for demonstration. It is a simple application, just showing the host or container in which the application is running.

Download or Create the ASP.NET Core Web Application

Create any sample ASP.NET core application, or clone/download the already created application from here.

ASP.NET Core

You can use the git clone command to clone the repository in the desired folder of the local drive.

 Local drive

Build the Application Locally

Let’s compile the application locally through the .NET command to make sure it is working fine and later we can automate these steps using the same command configured in Jenkins.

  1. Open the developer command prompt for Visual Studio.
     Command prompt
  2. On the command prompt, navigate to the folder where the solution file is cloned. Type the command “dotnet build <solution file name>”. This will compile the solution file.
    Dotnet build

Run the Unit Tests Locally

If you open the solution file in Visual Studio, you’ll see that there is a test project named “JenkinsIntegration.Tests.csproj” that contains a single test. We’ll run this test via the dotnet command locally and log the results in a log file. So, run the rest via the “dotnet test <test project name> --logger:trx” command as shown below. Once the tests are passed, it will say “Test Run Successful”.

 Unit Tests

You can check the test results i.e. the created log file in the “TestResults” folder under the test project directory.

TestResults

Continuous Integration of ASP.NET Core application using Jenkins

We see that our application compiles the file and the tests are also green. It is time to get rid of this manual process of running the command and automate this build and test running process. We’ll do this using two approaches in Jenkins, the Pipeline approach and the Freestyle project approach.

Pipeline Approach

The pipeline project approach helps to create a workflow for the set of activities to run in a sequential manner or in the form of a flowchart. This pipeline in Jenkins could be created by writing small scripts for each stage of CI that we target i.e. fetching the source code, compiling it, running the tests, etc.

  1. On the Jenkins home page, click on “Create new jobs”.
    Pipeline Approach
  2. Select the project type as “Pipeline” and give the project a meaningful name for e.g. “JenkinsPipeline” in this case.
    Pipeline
  3. On the next screen, you need to provide a basic sequential script for the pipeline to execute the stages one by one. For e.g. checkout, build, and run tests i.e. the things that we did manually. Following is the script that I used in the Pipeline script as shown in the following image.
    pipeline {
     agent any
     environment {
      dotnet = 'C:\\Program Files\\dotnet\\dotnet.exe'
     }
     stages {
      stage('Checkout') {
       steps {
        git credentialsId: 'b92a2c28-2693-4fc1-8490-49c7db00ed8a', url: 'https://github.com/akhilmittal/Getting-Started-With-Jenkins', branch: 'master'
       }
      }
      stage('Build') {
       steps {
        bat 'dotnet build JenkinsIntegration\\jenkinsIntegration.sln --configuration Release'
       }
      }
      stage('Test') {
       steps {
        bat 'dotnet test JenkinsIntegration\\JenkinsIntegration.Tests\\JenkinsIntegration.Tests.csproj --logger:trx'
       }
      }
     }
    }
    
    Advanced Project

The pipeline script created above has three stages.

  1. Checkout: In this stage, we provide the URL of the Git repository, the branch as master, and the git credentials id. Git credentials could be stored in Jenkins configuration and a corresponding ID will be provided that could be used in the configurations so that you do not have to provide the credentials again and again.
  2. Build: Once the checkout is done, the dotnet build command is used to build the solution as we did manually.
  3. Test: Once the code has compiled, it runs the tests via the dotnet test command.

So, we simply configured our manual commands in the form of a script. In the environment section, we provided the path of the dotnet exe because we are using it in our script and Jenkins should know where the exe must be run from.

  1. We also need to configure, that when should our pipeline build be triggered. So, in the “Build Triggers” section check the two options of Poll SCM and GitHub hook trigger as shown in the following image. Here we can set the intervals for which Jenkins should check the code on GitHub and perform the build And provide the schedule as “* * * * *” which means, keep checking the Git repository, and as soon as a commit/check-in is done, trigger the build process. We can also trigger the build manually if we go from the Jenkins dashboard.
     SCM
  2. Go to the Jenkins home page and we see our job created there. On the right side is the icon to trigger the build. Now, trigger the build manually to check if the workflow really works.
    Trigger build
  3. Once the build trigger finishes execution, it shows the status on the left side panel. You can click on the build on the left side while it is executing to know the live status of the build or when it is complete. Click on the build and we see that our pipeline headers like Checkout, Build and “UnitTests” are listed in a sequential way telling the time each process took. Since all the processes run successfully including the tests. You can also check the log file we intended to create after running the tests by clicking on the Logs on “UnitTests” completed process as shown below.
    Logs
  4. The following is the log file that was generated with passing tests.
     Log file

Freestyle Project Approach

Freestyle project is another approach to do the same thing except you do not have to write scripts here and provide needed configurations. Let’s check this step by step.

  1. Again, on the dashboard, click on “Create new jobs”.
    Create new jobs
  2. Provide a name to the item for e.g. “JenkinsFreeStyle” and select Freestyle project as the project type.
    JenkinsFreeStyle
  3. On the next screen, under “Source Code Management”, select Git (since we are using Git) and provide the Git credentials. Provide the branch as “*/master”.
    Source Code Management
  4. In the “Build Triggers,” we’ll again use which is explained in the last section.
     Last section
  5. In the Build section, we’ll now provide our dotnet commands to be executed sequentially both for compiling and running the tests as shown below.
     Dotnet commands
  6. In the post-build actions, let’s provide the name of the test result file we intend to create. Quote the same name in the dotnet test command in the Build section.
    Post-build
  7. Now save the configuration, go to the home page, and run the created trigger. Now once the build completes, check the build execution for the newly triggered build. We see that the build is executed, and tests are passed. You can check the test results by clicking on the “Latest Test Results” link.
    Latest Test Results
  8. The link navigates to the test method and says it is passed.
    Link navigates

Conclusion

So, we explored Jenkins and how it works seamlessly with our .net core application on our local. This was a small sample application with fewer configurations and only one simple test. There could be cases where your build may fail, or tests do not pass. In that case, be patient and try to check logs to understand what caused the failure and try to fix that. In the next article, we will see how to publish the Asp.NET Core application to Azure App Service.