Build Your First CI/CD Pipeline using Azure DevOps

Continuous integration and continuous delivery (CI/CD) are considered by most to be the backbone of DevOps. Things start to get really interesting when you combine these practices with programmable infrastructure and a suite of services that allow you to automate the entire lifecycle of an application.

The goal with this guide is to give you a practical example of what that all looks like when you’re building, testing, and deploying applications with Azure DevOps Services. I’ll walk you through the end-to-end process of building a fully automated build and release pipeline for a Node and Express application. We’ll use Azure DevOps Services to create the CI/CD pipeline and Azure App Service for deploying to development/staging and production.

To follow along, you’ll need a GitHub account and Azure Subscription. The demo application is open source, so the Azure DevOps pipeline infrastructure we build will be covered under the free tier.

Create Your Azure DevOps Organization

The first step is to navigate to and sign in to Azure DevOps. If you’ve never done this before, you’ll need to create a new organization.

Figure 1. Creating an Azure Organization.

You need to have at least one organization, which is used to store your projects, structure your repositories, set up your teams, and manage access to data. The guidance from Microsoft is to keep things simple and start with a single organization. For more advanced scenarios, take a look at plan your organization structure in Microsoft’s documentation.

After clicking on continue, you may end up with an organization name that was generated at random. You can change this as shown in Figure 2.

Figure 2. Updating Your Azure Organization Name.

Simply navigate to Organization Settings > Overview and update the name.

Fork the Node & Express Demo App Repository

I wanted to demonstrate an application that was somewhat realistic but not overly complex for this walkthrough. The Node and Express app is a simple website for a fictitious company. This app uses Express and Handlebars to serve up a few common pages you’d see on any company website. Also included are some unit tests that ensure those routes are working and serving up the right content.

You can head over to my GitHub account to fork this repository.

Figure 3. Fork the node-express-azure Repository.

Next, we can move on to deploying the infrastructure to support both development and production deployment slots using Azure App Service.

Deploy the App Service Infrastructure

We’re going to use an Azure Web App for Linux resource to power our Node and Express application. We’ll set things up so our CI/CD pipeline can build and deploy the app into a development/staging slot. Then we’ll set up up a manual approval into the production slot.

We’ll use an Azure Resource Manager (ARM) template to build the App Service infrastructure.

Navigate to the node-express-azure repository you forked in the previous step. You’ll see a “Deploy to Azure” button about halfway down the screen.

Figure 4. Deploying the ARM Template.

Clicking the “Deploy to Azure” button will redirect you to the Azure portal as shown in Figure 5.

Figure 5. Launching the ARM Template.

Notice that you’ll need to set a globally unique hostname for your web application, along with a name for the new app service plan. I’d recommend deploying these resources into a new resource group. That way when you’re done with this walkthrough, you can clean up the Azure resources easily by deleting the resource group.

Click “Purchase” to launch the template to agree that you’ll have to pay for the App Service resources that this template deploys on your behalf.

After you launch the template you should see a successful deployment message, and you should have a new resource group similar to the one shown in Figure 6. Notice that there is an App Service Plan, a web app that represents the production deployment slot, and a slot for development called “dev”.

Figure 6. Reviewing the Resources.

Quick side note about the ARM template: the Deploy to Azure button references the azuredeploy.json ARM template in my GitHub repository. If you want to update the template, update the version in your own repo, and don’t forget to change the target of the button in the source of your file.

Create a Build Pipeline

We’re ready to move on and set up a build pipeline in Azure DevOps. Head back to and create a new project inside your organization. Use the settings shown in Figure 7.

Figure 7. The New Project Settings.

After clicking on the “Create project” button, you’ll see a summary page for the project. Navigate to Pipelines and click on Builds as shown in Figure 8.

Figure 8. Creating a New Build Pipeline.

Next, click the button to create a new build pipeline. You’ll be prompted to choose a repository. Select GitHub. You’ll see a screen like the one in Figure 9 where you’ll need to authorize the Azure DevOps service to connect to your GitHub account on your behalf. Click Authorize.

Figure 9. Authorizing the GitHub Connection.

After your connection to GitHub has been authorized select the node-express-azure repo that you forked in the first step. You should end up seeing a “New pipeline” screen like the one shown in Figure 10.

Figure 10. Creating the New Build Pipeline.

The new pipeline wizard should recognize that we already have an azure-pipelines.yml in the repository. This file contains all of the settings that the build service should use to build and test our application, as well as generate the output artifacts that will be used to deploy the app later in our release pipeline.

After you click “Run” to kick off your first build, you should see a screen like the one shown in Figure 11.

Figure 11. Reviewing the Build Status.

Notice that a lot went on with the build. The service used an Ubuntu 16.04 build agent to grab the code from GitHub, installed our development dependencies, and then ran our unit tests to validate the application. Finally, the code was bundled into an output artifact and published so we can use it as an input artifact for our upcoming release pipeline.

Click on the release button at the top of this screen to create a new release pipeline.

Create a Release Pipeline

When you get into the release pipeline screen, you’ll need to select a template. For this scenario, we are going to choose “App Service deployment with slot”.

Figure 12. Selecting the Deployment Template.

Click on the apply button to create the new deployment stage within the release pipeline. On the next screen, you’ll be able to configure this stage. Change the name to “development” as shown in Figure 13.

Figure 13. Updating the Development Stage.

While on this screen, click on the link that says “2 tasks” inside your development stage. This will take you to a screen where you can configure the deployment task. Make sure you fill out all the fields as shown in Figure 14.

Figure 14. Configuring the Deployment Task.

Next, highlight and remove the second deployment task for swapping the slots.

Figure 15. Removing the Slot Swap Task.

Finally, click Save.

Figure 16. Save the Changes to the Development Stage.

Head back over to the "Pipeline" tab at the top left of the screen. Inspect the deployment triggers for the artifacts as shown in Figure 17.

Figure 17. Reviewing the Deployment Trigger.

Notice that continuous deployment is enabled by default. Going forward, each new build will trigger a deployment to our development slot in Azure App Service.

First, let's trigger a manual release.

Create Your First Release to Development

Click the "Release" button on the top right of the release pipeline screen and create a new release. Use the settings as shown in Figure 18.

Figure 18. Triggering a Release.

Click on the "Create" button to deploy the application to the development deployment slot. You should see a successful status in the properties of the release.

Figure 19. Reviewing the Release Status.

Navigate to the public URL of the "dev" deployment slot in your web browser. The hostname will have "-dev" appended to it. For example, my web app is named "node-express-demo" and the "dev" deployment slot URL is

Figure 20. The Demo Node App Running in the "dev" Deployment Slot.

You should see the sample web application when you visit the "dev" slot URL. The production slot will show the default Azure App Service splash page since it is virtually untouched at this point. Let's change that in the next step.

Create a Release Stage for Production

Head back over to the Azure DevOps portal and go to Pipelines > Releases. Click on the "Edit" button to modify the pipeline. Highlight the Development stage and click the dropdown to clone the stage.

Figure 21. Cloning the Development Stage.

Rename the stage to "Production".

Next, click the pre-deployment conditions button for the Production stage. Enable pre-deployment approvals and add yourself as an approver.

Figure 22. Requiring Approval for Production Deployment.

We're doing this because we don't want automated deployments going straight into production. We're not building a continuous deployment pipeline for production. We're building continuous delivery pipeline.

Continuous delivery is a process that ensures our application is production ready. When we are doing a scheduled deployment we can do so with confidence since we know the application has been through a pipeline of tests before-hand.

Next, click on the "task" link on the Production stage. We need to modify this task so that it does not deploy our code into the development slot.

Figure 23. Updating the Deployment Task.

Simply uncheck "slot" and this will infer that the production slot of the web app should be used during the deployment. Click save when complete.

Validating the Pipeline

Navigate to your GitHub account and into the views folder of the demo application. Edit the index.handlebars file to update the app to version 2.0.0.

Figure 24. Radically Modifying the Code Base for the App.

Committing the change in this repo should automatically trigger a build, perform our tests, and publish a deployment package. We can confirm this by reviewing the build status.

After the build, you should see a new release. The development stage should be green indicating that the deployment succeeded. The production stage should be blue and show that it's pending approval.

Figure 25. Reviewing the Release Status.

Click approve to kick-off the production deployment.

Figure 26. Deploying to Production. Never do this on a Friday!

Go back to your pipeline view and you should see the deployment to production succeeded.

Figure 27. Validating the Status.

Finally, head over to the web app URL for the production slot to confirm the correct version is running.

Figure 28. Reviewing the Version.

You should see version 2.0.0 on the homepage.

Set up a Build Badge for Your Project

Have you ever seen those build pass/fail badges when browsing projects on GitHub? They're really cool because you can tell at a glance if the code is still working or if it's old and busted.

Let's setup a badge for this project.

Go back to your Builds section and click the status badge button.

Figure 29. Locating the Status Badge Button.

Copy the markdown code for the status badge.

Figure 30. Copying the Markdown.

Now, go back to GitHub and modify the file in your node-express-azure repo. Paste the markdown you copied from the status badge page.

Figure 31. Updating

Commit the change and view the README. You should see a build passing status icon.

Figure 32. Badge Status Icon in Action.

If you're still reading after all this time, respect! You now know who to build a CI/CD pipeline on Azure.

You can simply delete all the resources to clean things up. Delete the resource group you created for this project, delete the Node demo project in the Azure DevOps portal, and delete the GitHub repo that you forked from my account (unless you want to keep a copy).

Where to go from here

Isn't this awesome stuff? There's so much more. For now, check out these resources to dive deeper.

Subscribe to the CloudSkills Weekly Newsletter

Get exclusive access to special trainings, updates on industry trends, and tips on how to advance your career in the tech industry.