{"id":31616,"date":"2017-05-15T04:38:39","date_gmt":"2017-05-15T12:38:39","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/?p=31616"},"modified":"2019-02-14T15:51:42","modified_gmt":"2019-02-14T23:51:42","slug":"deploying-applications-to-azure-vm-scale-sets","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/deploying-applications-to-azure-vm-scale-sets\/","title":{"rendered":"Deploying Applications to Azure Virtual Machine Scale Sets"},"content":{"rendered":"<p>This blog post shows how you can deploy an application from Visual Studio Team Services to Azure Virtual Machine Scale Set.\u00a0 An application running on a VM Scale Set is typically deployed in one of the two ways:<\/p>\n<ul>\n<li>Install new software on a platform image at deployment time by using VM extensions.<\/li>\n<li>Create a custom VM image that includes both the OS and the application in a single VHD<\/li>\n<\/ul>\n<p>Creating a custom image approach, also known as immutable deployments has its advantages. It is predictable, as you are promoting the image which you have already tested. It is also easy to scale and makes rollback to a well-known previous state easier. Another important scenario is\u00a0when you want to scale out, the VM extension based approach can result in a slow scale out because the extensions will run on a new VM each time it is created. If the scale set is based on a custom image, any new VM is a copy of the source custom image and the scale out will be faster as the prerequisites and application are already installed.<\/p>\n<p>In this example, we will first build and test a NodeJs application and then use the new <strong>Build immutable machine image<\/strong> task to build custom Ubuntu 16.04 VHD image which has NGINX, PM2 and the NodeJs application installed and configured. This image can then be used for Azure Virtual Machine Scale Sets deployment.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/05\/116.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2017\/05\/116-1024x460.png\" alt=\"VM Scale Sets - End to End Continuous Delivery workflow\" width=\"879\" height=\"395\" class=\"size-large wp-image-31966\" \/><\/a><\/p>\n<h3>Code<\/h3>\n<p><span><a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\">Download\/fork our NodeJs sample app<\/a><\/span><span>.<\/span> Upload your code to Team Services or you\u2019re on-premises Team Foundation Server: either push your code to Git or check in your code to TFVC.<\/p>\n<h3>Build<\/h3>\n<ul>\n<li><span><a href=\"https:\/\/www.visualstudio.com\/en-in\/docs\/build\/apps\/node\/nodejs-to-azure#expando-begin-create-build-definition-open-team-project\">Open your team project in your web browser <\/a><\/span><\/li>\n<li><span><a href=\"https:\/\/www.visualstudio.com\/en-in\/docs\/build\/apps\/node\/nodejs-to-azure#expando-begin-create-build-definition-create\">Create a build definition (Build &amp; Release tab &gt; Builds)<\/a><\/span><\/li>\n<li>Click Empty to start with an empty definition.<\/li>\n<li>In the repository tab of build definition make sure the repository selected is the one where you pushed (Git) or checked in (TFVC) your code<\/li>\n<\/ul>\n<p>On the<span>\u00a0<\/span><strong>Tasks<\/strong><span>\u00a0<\/span>or<span>\u00a0<\/span><strong>Build<\/strong><span>\u00a0<\/span>tab, add these steps.<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Package: npm install<\/strong><\/td>\n<td>Install your npm package dependencies.<\/p>\n<ul>\n<li>Command:<span>\u00a0<\/span> install<\/li>\n<li>Set the working folder to the folder where your application code is committed in the repository<\/li>\n<\/ul>\n<p>For example, in case of<span><a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\"> sample app<\/a><\/span> it will be NodejsWebApp1<\/td>\n<\/tr>\n<tr>\n<td><strong>Build: Gulp<\/strong><\/td>\n<td><span>Transpiles typescript to JavaScript.<\/span><\/p>\n<ul>\n<li>Gulp File Path:<span> Set the Gulp file path. For example, in case of <a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\">sample app<\/a> it will be NodejsWebApp1\/gulpfile.js<\/span><\/li>\n<li>Advanced section, set the working folder to the folder where your gulpfile.js is located<\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td><strong>Package: npm test<\/strong><\/td>\n<td>Test your application.<\/p>\n<ul>\n<li>Command:\u00a0 test<\/li>\n<li>Set the working folder to the folder where your application code is committed in the repository<\/li>\n<\/ul>\n<p>For example, in case of<span><a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\"> sample app<\/a><\/span> it will be NodejsWebApp1 and a Mocha test will be run<\/td>\n<\/tr>\n<tr>\n<td><strong>Build: Publish Build Artifacts<\/strong><\/td>\n<td>Publish the build outputs.<\/p>\n<ul>\n<li>Path to Publish:<span>\u00a0Use variables or <\/span>$(Build.ArtifactStagingDirectory) <span>Folder or file path to publish. Either fully qualified path or relative to repo root. <\/span>For example, in case of<a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\"> sample app<\/a> it will be NodejsWebApp1<\/li>\n<li>Artifact name:<span>\u00a0<\/span>drop<\/li>\n<li>Artifact Type:<span>\u00a0<\/span>Server<\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4>Enable continuous integration (CI)<\/h4>\n<p>On the<span>\u00a0<\/span><strong>Triggers<\/strong><span>\u00a0<\/span>tab, enable<span>\u00a0<\/span><strong>Continuous integration<\/strong><span>\u00a0<\/span>(CI). This tells the system to queue a build whenever someone on your team commits or checks in new code.<\/p>\n<h4>Save, queue, and test the build<\/h4>\n<p>Save and queue the build. Once the build is done, click the link to the completed build (for example,<span>\u00a0<\/span><em>Build 1634<\/em>), click<span>\u00a0<\/span><strong>Artifacts<\/strong>, and then click<span>\u00a0<\/span><strong>Explore<\/strong><span>\u00a0<\/span>to see the files produced by the build.<\/p>\n<h3>Release<\/h3>\n<ul>\n<li>Open the\u00a0<span><\/span><strong>Releases<\/strong><span>\u00a0<\/span>tab of the<span>\u00a0<\/span><strong>Build &amp; Release<\/strong><span>\u00a0<\/span>hub, open the<span>\u00a0<\/span><strong>+<\/strong><span>\u00a0<\/span>drop-down in the list of release definitions, and choose<span>\u00a0<\/span><strong>Create release definition with empty definition.<\/strong><\/li>\n<li>Select the build definition you created earlier as the source of artifact to be deployed.<\/li>\n<\/ul>\n<p>Now add these steps. <strong>Bake Immutable image for VMSS<\/strong> and <strong>Azure PowerShell.\u00a0<\/strong>The Bake Immutable image for VMSS uses Packer to create a VHD. The whole bake process involves:<\/p>\n<ul>\n<li>Creating a new Virtual Machine with the selected base OS<\/li>\n<li>Installing all the prerequisites and application on the VM by using a deployment script<\/li>\n<li>Creating a VHD and storing it in the Azure storage account<\/li>\n<li>Deleting the new Virtual Machine which was created<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<table>\n<tbody>\n<tr>\n<td width=\"103\"><strong>Bake Immutable image for VMSS<\/strong><\/td>\n<td width=\"519\">\n<ul>\n<li><strong>Packer template:<\/strong><span>\u00a0You can bring your own packer configuration json or use the auto generate feature where the task generates a packer template for you. In this example let us use the auto generated packer configuration.<\/span><\/li>\n<li><strong>Azure subscription<\/strong>: Select the Azure service connection you want to use<\/li>\n<li><strong>Storage location<\/strong>: The location of storage account where the VHD will be stored. This should be the same location where the Virtual Machine Scale Set is or will be created.<\/li>\n<li><strong>Base Image Source<\/strong>: You can either choose from a curated gallery of OS images or provide url of your custom image. For this example, let us choose Ubuntu 16.04 LTS<\/li>\n<li><strong>Deployment Package:<\/strong><span>\u00a0<\/span>Specify the path for deployment package directory relative to $(System.DefaultWorkingDirectory). For example, in case of <a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\">sample app<\/a> it will be $(System.DefaultWorkingDirectory)\/Packer-NodeJs\/drop<\/li>\n<li><strong>Deployment Script: <\/strong>Specify the relative path to PowerShell script(for Windows) or shell script(for Linux) which deploys the package. This script should be contained in the deployment package path selected above. For example, in case of <a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\">sample app<\/a> it will be Deploy\/ubuntu\/deployNodejsApp.sh\u00a0 In the <a href=\"https:\/\/github.com\/azooinmyluggage\/Packer-NodeJs-Demo\">sample app<\/a> deployment script takes care of installing curl, Node.js, NGINX, PM2, copying over the application and then configuring NGINX and PM2 to run the application.<\/li>\n<li><strong>Output \u2013<\/strong> Image URL: Provide a name for the output variable which will store the generated machine image url. For example <strong>bakedImageUrl<\/strong><\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td width=\"103\"><strong>Azure PowerShell<\/strong><\/td>\n<td width=\"519\">This task will update the Virtual Machine Scale Set with the new VHD which was created.<\/p>\n<ul>\n<li><strong>Azure Connection Type: <\/strong>Select Azure Resource Manager<\/li>\n<li><strong>Azure RM Subscription: <\/strong>Select the Azure service connection you want to use<\/li>\n<li><strong>Script type: Select inline<\/strong><\/li>\n<li><strong>Inline Script: <\/strong>Use the following script to update the Virtual machine Scale Set<\/li>\n<\/ul>\n<p><em># get the VMSS model<\/em><\/p>\n<p><em>$vmss = Get-AzureRmVmss -ResourceGroupName resource_group_name -VMScaleSetName VM_scale_set_name<\/em><\/p>\n<p><em># set the new version in the model data<\/em><\/p>\n<p><em>$vmss.virtualMachineProfile.storageProfile.osDisk.image.uri=&#8221;<strong>$(bakedImageUrl)<\/strong>&#8220;<\/em><\/p>\n<p><em># update the virtual machine scale set model<\/em><\/p>\n<p><em>Update-AzureRmVmss -ResourceGroupName resource_group_name -Name resource_group_name -VirtualMachineScaleSet $vmss<\/em><\/p>\n<p><em><\/em>You can use variables to pass on the resource group and Virtual Machine Scale Set names.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<ul>\n<li>Type a name for the new release definition and, optionally, change the name of the environment from\u00a0<span><\/span><strong>Default Environment<\/strong><span>\u00a0<\/span>to<span>\u00a0<\/span><strong>Dev<\/strong>. Also, set the deployment condition on the environment to \u201cAutomatically start after release creation\u201d.<\/li>\n<li>Save the new release definition. Create a new release and verify that the application has been deployed correctly.<\/li>\n<\/ul>\n<h4>Packer configuration template<\/h4>\n<p>The <strong>Bake immutable image for VMSS<\/strong> task makes it easy for users who are new to immutable VHD based deployments to use Packer without learning concepts like provisioners and builders. If you are deploying to Virtual Machines by using deployment scripts then you can try out this task and use it for either creating new Virtual Machine instances or creating\/updating Virtual Machine Scale Sets.<\/p>\n<p>The auto generate mode of the task generates the packer configuration with:<\/p>\n<ul>\n<li>Builder for Azure<\/li>\n<li>Provisioners depends on the type of base OS selected. For Linux, it is shell script and for Windows it is PowerShell script. The deployment script provided is used by the provisioner.<\/li>\n<\/ul>\n<p>A custom packer configuration json can also be used.<\/p>\n<h3>Setup Continuous Delivery from Azure portal<\/h3>\n<p>The entire build and release Continuous delivery can be setup from the Azure portal as well by using the Continuous Delivery option available in the Virtual Machine scale set blade.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/05\/214.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2017\/05\/214-1024x553.png\" alt=\"Virtual machine Scale Sets - Setup Continuous Delivery from Azure Portal\" width=\"879\" height=\"475\" class=\"size-large wp-image-31975 aligncenter\" \/><\/a><\/p>\n<p>There are few things you should keep in mind while setting immutable deployments. For example:<\/p>\n<ol>\n<li>The Azure storage account (which is used as VHD storage) should be in the same location as the VM Scale Set which will get updated by the generated image<\/li>\n<li>If the VM Scale set was created by using a platform image, then it cannot be updated by using Custom image.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This blog post shows how you can deploy an application from Visual Studio Team Services to Azure Virtual Machine Scale Set.\u00a0 An application running on a VM Scale Set is typically deployed in one of the two ways: Install new software on a platform image at deployment time by using VM extensions. Create a custom [&hellip;]<\/p>\n","protected":false},"author":230,"featured_media":45953,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[224,226,1],"tags":[],"class_list":["post-31616","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-ci","category-devops"],"acf":[],"blog_post_summary":"<p>This blog post shows how you can deploy an application from Visual Studio Team Services to Azure Virtual Machine Scale Set.\u00a0 An application running on a VM Scale Set is typically deployed in one of the two ways: Install new software on a platform image at deployment time by using VM extensions. Create a custom [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/31616","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/230"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=31616"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/31616\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=31616"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=31616"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=31616"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}