{"id":36459,"date":"2019-04-23T00:40:29","date_gmt":"2019-04-23T07:40:29","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/premier-developer\/?p=36459"},"modified":"2019-04-19T07:52:23","modified_gmt":"2019-04-19T14:52:23","slug":"using-azure-devops-to-deploy-web-applications-to-virtual-machines","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/using-azure-devops-to-deploy-web-applications-to-virtual-machines\/","title":{"rendered":"Using Azure DevOps to Deploy Web Applications to Virtual Machines"},"content":{"rendered":"<p>App Dev Manager <a href=\"https:\/\/www.linkedin.com\/in\/jafar-jaffery-5664883\/\">Jafar Jaffery<\/a> explores how to use Azure DevOps to deploy apps to Virtual Machines.<\/p>\n<hr \/>\n<h2>Overview<\/h2>\n<p>In this post, I will cover a basic end-to-end example of deploying an ASP.NET MVC web application from source code to Production using Azure DevOps. The web app will be hosted within Windows Virtual Machines (VMs). While it\u2019s worth mentioning that hosting web applications using Azure PaaS offerings or via containers would be the preferred route for a variety of reasons, VMs are still widely used in many organizations. With that scenario in mind, this post is geared to helping you get started with streamlining your release process. As a note, much of this process translates easily to using Azure PaaS offerings.<\/p>\n<h2>CI\/CD Pipeline<\/h2>\n<p>The diagram below outlines the CI\/CD (Continuous Integration\/Continuous Delivery) pipeline we\u2019ll be setting up. The CI\/CD pipeline is a practice used by DevOps teams for delivering code changes more frequently and reliably. This enables agile teams to shorten cycle times, improve quality, and deliver value faster. The pipeline below is not intended to be fully comprehensive (e.g., no UI testing, security scanning, load testing, etc.), but has the core components needed to get started. The only prerequisites needed here are your VMs, and an <a href=\"https:\/\/azure.microsoft.com\/en-us\/services\/devops\/\">Azure DevOps<\/a> account (or alternatively, using <a href=\"https:\/\/azure.microsoft.com\/en-us\/services\/devops\/server\/\">Azure DevOps Server<\/a>, previously known as Team Foundation Server).<\/p>\n<p><img decoding=\"async\" width=\"719\" height=\"264\" class=\"wp-image-36461\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12152.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML12152547.PNG\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12152.png 719w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12152-300x110.png 300w\" sizes=\"(max-width: 719px) 100vw, 719px\" \/><\/p>\n<h2>Continuous Integration &#8211; Code \/ Build \/ CI Trigger<\/h2>\n<p>Follow these steps to setup the build:<\/p>\n<ol>\n<li>Go to Pipelines &gt;&gt; Builds &gt;&gt; New build pipeline\n<img decoding=\"async\" width=\"277\" height=\"151\" class=\"wp-image-36462\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12de2.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML12de2c2b.PNG\" \/><\/li>\n<li>Select your Project \/ Repo \/ Default Branch<\/li>\n<li>Select the ASP.NET template<\/li>\n<li>Save the build<\/li>\n<\/ol>\n<p>Once setup, the build should something like this:<\/p>\n<table>\n<tbody>\n<tr>\n<td><img decoding=\"async\" width=\"751\" height=\"685\" class=\"wp-image-36463\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml1260e.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML1260ecb1.PNG\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml1260e.png 751w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml1260e-300x274.png 300w\" sizes=\"(max-width: 751px) 100vw, 751px\" \/><\/td>\n<td><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To enable the CI part of the pipeline, go to the Triggers tab in the build, and check the box for \u201cEnable continuous integration\u201d. The build will now be triggered whenever any code changes are committed to the repository for the branch specified. As a good general practice, you should have your CI\/CD commits done using <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/repos\/git\/pullrequest?view=azure-devops\">Pull Requests<\/a> in conjunction with a <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/repos\/git\/git-branching-guidance?view=azure-devops\">branching strategy<\/a>.<\/p>\n<p><img decoding=\"async\" width=\"1098\" height=\"522\" class=\"wp-image-36464\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12663.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML126630b7.PNG\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12663.png 1098w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12663-300x143.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12663-768x365.png 768w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12663-1024x487.png 1024w\" sizes=\"(max-width: 1098px) 100vw, 1098px\" \/><\/p>\n<h2>Continuous Delivery<\/h2>\n<h2>Deployment Groups<\/h2>\n<p>A deployment group is a logical set of deployment target machines that have agents installed on each one. Deployment groups represent the physical environments; for example, &#8220;Dev&#8221;, &#8220;Test&#8221;, &#8220;UAT&#8221;, and &#8220;Production&#8221;. To setup a deployment group, follow <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/apps\/cd\/deploy-webdeploy-iis-deploygroups?view=azure-devops#create-a-deployment-group\">these steps<\/a>. Once setup, this can be used within the release.<\/p>\n<p><img decoding=\"async\" width=\"482\" height=\"306\" class=\"wp-image-36465\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12acb.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML12acb43a.PNG\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12acb.png 482w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12acb-300x190.png 300w\" sizes=\"(max-width: 482px) 100vw, 482px\" \/><\/p>\n<h2>Release<\/h2>\n<p>A release pipeline takes in the artifact created from the build and releases it through the various stages or environments. To create a new release pipeline, go to Pipelines &gt;&gt; Releases &gt;&gt; New release pipeline.<\/p>\n<p><img decoding=\"async\" width=\"288\" height=\"195\" class=\"wp-image-36466\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/word-image-53.png\" \/><\/p>\n<p>From here, select the \u201cIIS website deployment\u201d template as this will get the basic tasks in place<\/p>\n<p>Once completed using the steps outlined below, the release pipeline should look like this:<\/p>\n<p><img decoding=\"async\" width=\"1143\" height=\"515\" class=\"wp-image-36467\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12d59.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML12d59800.PNG\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12d59.png 1143w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12d59-300x135.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12d59-768x346.png 768w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12d59-1024x461.png 1024w\" sizes=\"(max-width: 1143px) 100vw, 1143px\" \/><\/p>\n<p>Follow the steps shown in the diagram above:<\/p>\n<ol>\n<li>Select the source build pipeline. This is build we created earlier.<\/li>\n<li>Enable the continuous deployment trigger.<\/li>\n<li>Name the stage to your first environment, which in our case is \u201cTesting\u201d.<\/li>\n<li>Set the properties for the \u201cTesting\u201d deployment job &amp; IIS tasks for that job.<\/li>\n<li>Clone the Testing task:\n<img decoding=\"async\" width=\"317\" height=\"175\" class=\"wp-image-36468\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12e7e.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML12e7e33b.PNG\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12e7e.png 317w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12e7e-300x166.png 300w\" sizes=\"(max-width: 317px) 100vw, 317px\" \/>\nThen change the name of the stage to your second environment, which in our case is \u201cProduction\u201d.<\/li>\n<li>Set the properties for the \u201cProduction\u201d deployment job &amp; IIS tasks for that job.<\/li>\n<li>Set the pre-deployment approvers for \u201cProduction\u201d as follows:\n<img decoding=\"async\" width=\"731\" height=\"475\" class=\"wp-image-36469\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12ee0.png\" alt=\"C:\\Users\\jajaffer\\AppData\\Local\\Temp\\SNAGHTML12ee0358.PNG\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12ee0.png 731w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/c-users-jajaffer-appdata-local-temp-snaghtml12ee0-300x195.png 300w\" sizes=\"(max-width: 731px) 100vw, 731px\" \/><\/li>\n<\/ol>\n<h2>Variable Substitution for Environment-Specific Values<\/h2>\n<p>The final piece of the picture here is to ensure that we have the correct config values for each environment we deploy to. To do this, we\u2019ll use variable substitution, which is a built-in feature of Azure DevOps that facilitates substituting your environment-specific values without having to use any specialized tokes in your config files or resorting to creating\/maintaining transform files for each environment. In order to deploy the same package across multiple environments, you can use <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/tasks\/transforms-variable-substitution?view=azure-devops#xml-variable-substitution\">XML variable substitution<\/a>. In case your project has any JSON config files, you can also use <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/tasks\/transforms-variable-substitution?view=azure-devops#json-variable-substitution\">JSON variable substitution<\/a>.<\/p>\n<h2>On-Premise VM Considerations<\/h2>\n<p>For the purposes of this setup, VMs can be host in Azure or On-Premise. For VMs hosted in Azure, you can use hosted agents in Azure DevOps. In case the VMs are hosted on-premise, you\u2019ll have to setup self-hosted agents to provide Azure DevOps visibility to the VMs, as shown in the diagram below. You can get more information on agents in the MS Docs <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/agents\/agents?view=azure-devops\">here<\/a>.<\/p>\n<p><img decoding=\"async\" width=\"738\" height=\"386\" class=\"wp-image-36470\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/word-image-54.png\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/word-image-54.png 738w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2019\/04\/word-image-54-300x157.png 300w\" sizes=\"(max-width: 738px) 100vw, 738px\" \/><\/p>\n<h2>Conclusion<\/h2>\n<p>As I\u2019ve demonstrated here, Azure DevOps offers a robust &amp; easy to set-up platform for your Pipelines. When you use this in unison with the other out-of-box components (Boards, Repos, Test Plans, Artifacts) along with the rich library of marketplace extensions (SonarQube, Docker, Chef, Jenkins, WhiteSource, Slack, Teams, Octopus, etc.), you get a complete DevOps setup. You can get more information on these Azure DevOps components here: <a href=\"https:\/\/azure.microsoft.com\/en-us\/services\/devops\/\">https:\/\/azure.microsoft.com\/en-us\/services\/devops\/<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>While it\u2019s worth mentioning that hosting web applications using Azure PaaS offerings or via containers would be the preferred route for a variety of reasons, VMs are still widely used in many organizations. With that scenario in mind, this post is geared to helping you get started with streamlining your release process. As a note, much of this process translates easily to using Azure PaaS offerings.<\/p>\n","protected":false},"author":582,"featured_media":36460,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[25,22],"tags":[2571,21,3,375],"class_list":["post-36459","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-devops","tag-azure-devops","tag-devops","tag-team","tag-virtual-machine"],"acf":[],"blog_post_summary":"<p>While it\u2019s worth mentioning that hosting web applications using Azure PaaS offerings or via containers would be the preferred route for a variety of reasons, VMs are still widely used in many organizations. With that scenario in mind, this post is geared to helping you get started with streamlining your release process. As a note, much of this process translates easily to using Azure PaaS offerings.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/36459","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=36459"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/36459\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/36460"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=36459"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=36459"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=36459"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}