Posted by Mike Pfeiffer on January, 14, 2019
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.
The first step is to navigate to dev.azure.com and sign in to Azure DevOps. If you’ve never done this before, you’ll need to create a new 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.
Simply navigate to Organization Settings > Overview and update the name.
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.
Next, we can move on to deploying the infrastructure to support both development and production deployment slots using Azure App Service.
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.
Clicking the “Deploy to Azure” button will redirect you to the Azure portal as shown in Figure 5.
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”.
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 README.md file.
We’re ready to move on and set up a build pipeline in Azure DevOps. Head back to dev.azure.com and create a new project inside your organization. Use the settings shown in Figure 7.
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.
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.
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.
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.
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.
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”.
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.
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.
Next, highlight and remove the second deployment task for swapping the slots.
Finally, click Save.
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.
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.
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.
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.
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 https://node-express-demo-dev.azurewebsites.net.
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.
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.
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.
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.
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.
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.
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.
Click approve to kick-off the production deployment.
Go back to your pipeline view and you should see the deployment to production succeeded.
Finally, head over to the web app URL for the production slot to confirm the correct version is running.
You should see version 2.0.0 on the homepage.
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.
Copy the markdown code for the status badge.
Now, go back to GitHub and modify the README.md file in your node-express-azure repo. Paste the markdown you copied from the status badge page.
Commit the change and view the README. You should see a build passing status icon.
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).
Isn't this awesome stuff? There's so much more. For now, check out these resources to dive deeper.
Sign up for the CloudSkills Weekly Newsletter for access to exclusive training, updates on industry trends, and advice to amplify your career in cloud-native computing.