CI/CD for a web application using Azure DevOps
Introduction
Azure DevOps platform was shown for the first time at the end of September 2018. To check what this new tool from Microsoft has to offer, we have decided to develop continuous integration and continuous deployment processes (CI/CD) for a simple (monolithic) web application. For that purpose, we are going to use PWA application for claim reporting, which we have developed beforehand.
The solution, which we would like to construct, will look as follows:
The continuous integration process downloads the source code from GitHub repository, compiles the application and packages it into a container which then is uploaded to DockerHub image repository. The continuous deployment process downloads a container’s image from DockerHub and runs it in an already prepared environment. In our case, it will be the Azure App Service.
Preparation
Before we start to develop CI/CD processes, we must prepare a few things:
- We create an account https://github.com/ and repository to which we put the code of our application. The application is containerized (it has Dockerfile prepared).
- We create an account at https://hub.docker.com/ and define a team together with the namespace assigned to it.
- We create an account at http://dev.azure.com and start a new project.
- We create an account at https://portal.azure.com, install Azure CLI, authorize (issuing: az login) and prepare runtime environment for our application:
- we select the name of our application, Azure Resource Group and image repository in DockerHub, for example:
RG_NAME=claim-reporter
APP_NAME=claim-reporter-app
IMAGE=altkom/claim-reporter-app
- we create the Resource Group:
az group create \
--location westeurope \
--name ${RG_NAME}
- we create the Service Plan:
az appservice plan create \
--name ${APP_NAME} \
--resource-group ${RG_NAME} \
--is-linux
- we create a new “App Service” type resource:
az webapp create \
--plan ${APP_NAME} \
--resource-group ${RG_NAME} \
--name ${APP_NAME} \
--deployment-container-image-name ${IMAGE}
Continuous Integration process
Defining the continuous integration process in Azure DevOps requires 11 simple steps:
1) On the main screen of the selected project, we choose the “Builds” tab and click the button “New Pipeline”:
2) We choose the platform on which we are going to host our code repository (Github or Azure):
3) We choose a method of integration with GitHub:
4) We install Azure Pipelines plug-in on GitHub account:
5) We grant necessary permissions to a plug-in:
6) We select the code repository:
7) We choose a template for a new pipeline:
Available templates include simple examples of build pipelines for several popular technological stacks: Java (ant, maven, gradle), JavaScript (npm, grunt, gulp, angular, react, vue), .NET (Full, Core), UWP, Python, Ruby, Go, PHP, Xamarin, Xcode, C/C++, Docker, etc.
8) We look it through and save with no modifications :
The definition of the pipeline has been saved in code’s repository in the azure-pipelines.yml file.
A new commit causes initiation of build process which (for obvious reasons) ends up with a failure:
9) To make the build process working, we have to adopt the definition to the specifics of our project. We start from defining three variables in a pipeline:
- dockerId – login for DockerHub account
- dockerNamespace – namespace created on DockerHub
- dockerPass – a necessary password for authentication (you must remember to mark the variable as storing the password in order to avoid displaying it in the console and logs)
10) We adjust pipeline’s definition, which is saved in the azure-pipelines.yml file:
# azure-pipelines.yml
pool:
vmImage: 'Ubuntu 16.04'
variables:
app: 'claim-reporter-app'
image: '$(dockerNamespace)/claim-reporter-app'
tag: '$(build.buildId)'
steps:
- script: docker login -u $(dockerId) -p $(dockerPass)
displayName: 'docker login'
- script: docker build -t $(image) $(app)
displayName: 'docker build $(app)'
- script: docker tag $(image) $(image):$(tag)
displayName: 'docker tag $(image):$(tag)'
- script: docker push $(image):$(tag)
displayName: 'docker push $(image):$(tag)'
- script: docker push $(image):latest
displayName: 'docker push $(image):latest'
11) We save the changes in the repository which initiates the build process:
We may also see the build status on GitHub:
Created container images have appeared on DockerHub:
Continuous Deployment process
To define a simple Continuous Deployment process, we must take eight steps:
- On the project’s screen we move to “Releases” tab and select an option “New Pipeline”:
2) We select “Azure App Service deployment” template and click “Apply”:
3) We specify the name of the pipeline and its first step:
4) We open the deployment artifact selection screen and choose “Docker Hub” as a source:
5) We configure the connection with an account on DockerHub:
6) Next, we select namespace as well as a repository and confirm by clicking the button “Add”:
7) We move to the “Tasks” tab:
We select Azure subscription, click “Authorize” and log into Azure account (warning: make sure that pop-up blockers are switched off). Then we choose the target location by indicating “App Service” created beforehand and click “Save”:
8) We come back to the pipeline’s configuration screen and add the deployment process trigger:
The process, which we developed, looks as follows:
We initiate the first deployment manually (Release -> Create a release), by choosing the version of artifact, which is supposed to be used:
After a while, the installation process will be complete:
and our application is going to appear under the desired address:
Summary
A few experiments, which we have carried out using Azure DevOps platform, allowed us to make the following observations:
- it is not a new solution, but graphically refreshed VSTS service – main changes have occurred in pricing, which I’m going to mention in the following points;
- Azure DevOps platform allows to quickly and easily construct CI/CD pipelines – for simple cases;
- configuring the integration with GitHub and DockerHub is painless;
- the integration with GitHub works very well in both ways: on GitHub, for every commit, we may see the status of compilation triggered by that particular change, while in the Azure DevOps we have a convenient view of the changelist which have been included in a given build;
- lack of proper CLI is the reason why all operations have to be done via GUI, which most engineers consider as a disadvantage; official CLI (in 0.1.3 version) does not allow defining pipelines; there is also alternative solution created by community: VSTeam, however, it is only available from Powershell, and has its limitations as well;
- a platform offers HTTP REST API and Client’s libraries for a few programming languages; however, not all functionalities are supported this way;
- the tool is not stable yet – we had some issues with commits that failed to trigger builds (silently, without any error messages);
- we can see some conceptual inconsistencies between Azure and Azure DevOps platforms – although we would like to perform deployment using Azure DevOps, we still have to select docker image repository while creating App Service container (we cannot create an empty App Service instance);
- a wizard for creating build pipelines is very simplified – for example, it does not allow to define environment variables which build process is going to use, and cannot be skipped; it means that if we want to use variables, we must set the pipeline first (which will trigger its execution), then edit it, configure variables and re-run the build process;
- platform’s graphic interface is inconsistent in some places – for example, YAML file, which includes the definition of the build pipeline, can be edited from visual interface only during its creation; all further changes have to be introduced by performing commits directly to code’s repository;
- current service tarification makes it a perfect solution for small teams and small, Open Source projects (proof-of-concept for example).
To sum it all up – Azure DevOps platform offers a wide range of features. We are hoping that few shortcomings, which we have discovered, will soon be removed.
Robert Kuśmierek
Lead Software Engineer, ASC LAB