Del två | I min förra bloggpost gick vi igenom hur vi med hjälp av DSC kan konfigurera våran VM till att vara en VSTS byggagent med stöd för node.js. Vi kommer nu att fortsätta att titta vidare på hur vi kan automatisera utrullningen till Azure.

ARM mall

Börja med att skapa ett nytt tomt ”Azure Resoruce Group” Projekt i Visual Studio. Skapa sedan en mapp döpt ”DSC” under projektet. I DSC mappen lägger du sedan DSC filen som vi skapade i del 1 och döper denna till ”BuildAgentConfig.ps1”.

Kopiera följande JSON dokument och ersätt allt innehåll i ”azuredeploy.json” (ARM template filen i ditt projekt).


{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminPassword": {
      "type": "securestring",
      "defaultValue": "Y0urS3curePassw0rd!"
    },
    "numberOfInstances": {
      "type": "int",
      "minValue": 1,
      "defaultValue": 2
    },
    "_artifactsLocation": {
      "type": "string",
      "metadata": {
        "description": "Auto-generated container in staging storage account to receive post-build staging folder upload"
      }
    },
    "_artifactsLocationSasToken": {
      "type": "securestring",
      "metadata": {
        "description": "Auto-generated token to access _artifactsLocation"
      }
    }
  },
  "variables": {
    "BuildAgentConfigArchiveFolder": "DSC",
    "BuildAgentConfigArchiveFileName": "BuildAgentConfig.zip",
    "environment": "Dev",
    "SystemPrefix": "Agent",
    "NamePrefix": "[concat(variables('SystemPrefix'),variables('environment'))]",
    "VMNicPostFix": "[concat(variables('environment'),'-nic')]",
    "availabilitySetName": "[concat(variables('namePrefix'),'-avset')]",
    "VnetName": "[concat(variables('namePrefix'),'-vnet')]",
    "vnetId": "[resourceId('Microsoft.Network/virtualNetworks', variables('VnetName'))]",
    "virtualNetworkSubnetName": "BackendSubnet",
    "subnetRef": "[concat(variables('vnetId'), '/subnets/', variables('virtualNetworkSubnetName'))]"
  },
  "resources": [
    {
      "apiVersion": "2017-03-30",
      "type": "Microsoft.Compute/availabilitySets",
      "name": "[variables('availabilitySetName')]",
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "AvailabilitySet"
      },
      "properties": {
        "PlatformUpdateDomainCount": 3,
        "PlatformFaultDomainCount": 2
      },
      "sku": {
        "name": "Aligned"
      }
    },
    {
      "apiVersion": "2016-03-30",
      "type": "Microsoft.Network/virtualNetworks",
      "name": "[variables('VnetName')]",
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "VirtualNetwork"
      },
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "10.0.0.0/16"
          ]
        },
        "subnets": [
          {
            "name": "[variables('virtualNetworkSubnetName')]",
            "properties": {
              "addressPrefix": "10.0.2.0/24"
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2016-03-30",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('NamePrefix'), copyindex(),variables('VMNicPostFix'))]",
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "NetworkInterface"
      },
      "copy": {
        "name": "nicLoop",
        "count": "[parameters('numberOfInstances')]"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks/', variables('VnetName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2016-04-30-preview",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat(variables('NamePrefix'), copyindex())]",
      "copy": {
        "name": "virtualMachineLoop",
        "count": "[parameters('numberOfInstances')]"
      },
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "VSTS Build Agent"
      },
      "dependsOn": [
        "nicLoop",
        "[resourceId('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "Standard_B2s"
        },
        "osProfile": {
          "computerName": "[concat(variables('NamePrefix'), copyindex())]",
          "adminUsername": "azadmin",
          "adminPassword": "[parameters('adminPassword')]",
          "windowsConfiguration": {
            "provisionVmAgent": "true"
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftVisualStudio",
            "offer": "VisualStudio",
            "sku": "VS-2017-Ent-Latest-WS2016",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "fromImage",
            "managedDisk": {
              "storageAccountType": "Premium_LRS"
            }
          },
          "dataDisks": []
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('NamePrefix'), copyindex(),variables('VMNicPostFix')))]"
            }
          ]
        }
      },
      "resources": [
        {
          "name": "Microsoft.Powershell.DSC",
          "type": "extensions",
          "location": "[resourceGroup().location]",
          "apiVersion": "2016-03-30",
          "dependsOn": [
            "[resourceId('Microsoft.Compute/virtualMachines', concat(variables('NamePrefix'), copyindex()))]"
          ],
          "tags": {
            "displayName": "BuildAgentConfig"
          },
          "properties": {
            "publisher": "Microsoft.Powershell",
            "type": "DSC",
            "typeHandlerVersion": "2.9",
            "autoUpgradeMinorVersion": true,
            "settings": {
              "configuration": {
                "url": "[concat(parameters('_artifactsLocation'), '/', variables('BuildAgentConfigArchiveFolder'), '/', variables('BuildAgentConfigArchiveFileName'))]",
                "script": "BuildAgentConfig.ps1",
                "function": "Main"
              },
              "configurationArguments": {
                "nodeName": "[concat(variables('NamePrefix'), copyindex())]"
              }
            },
            "protectedSettings": {
              "configurationUrlSasToken": "[parameters('_artifactsLocationSasToken')]"
            }
          }
        }
      ]
    }
  ]
}

Deployment

För att testa mallen kan vi göra en deployment via VS.

  1. Kontrollera så at PAT nyckeln och VSTS informationen i DSC filen är korrekt
  2. Högerklicka på projektet i Visual Studio och välj Deploy, New…
  3. Logga in och välj rätt Azure prenumeration
  4. Skapa en ny resursgrupp
  5. Klicka på Edit Parameters…
  6. Sätt ett admin lösenord, antal instanser och sedan spara
  7. Klicka på Deploy för att starta utrullningen

Efter ca 10min borde servern vara igång och agenten installerad. Logga in i VSTS för att kontrollera att Agenten är online.

Key take away

Namnstandard
Mallen kommer att skapa samtliga resurser med en namnstandard som är baserad på Microsoft best practices https://docs.microsoft.com/en-us/azure/architecture/best-practices/naming-conventions

Artifacts
Eftersom våran DSC är en fristående fil så måste vi använda oss av sk. artifacts för att ARM ska hitta filen. _artifactsLocation och _artifactsLocationSasToken sätts automatiskt av Visual Studio vid deployment, men i sista steget när vi går över till VSTS måste vi sätta dessa parametrar själva.

_artifactsLocation är en URL till en Azure blob storage och _artifactsLocationSasToken är en tidsbegränsad åtkomstnyckel till denna plats.

VS Version
Notera att ARM mallen är inställd på att använda en Visual Studio 2017 Enterprise image till våran IaaS VM. Denna image kan tex ersättas med ”VS-2017-Ent-Latest-Preview-WS2016” för att få åtkomst till den senaste preview versionen av Visual Studio 2017.
”offer”: ”VisualStudio”,
”sku”: ”VS-2017-Ent-Latest-WS2016”,
”version”: ”latest”

PAT Nyckel
I del 1 konfigurerade vi DSC mallen med en PAT nyckel för VSTS, var noga med att denna också finns med i detta projekt.

Artifacts Location
Istället för att låta Visual Studio skapa ett storage account, se över din infrastruktur och ta fram ett lagringskonto som kan användas i framtiden med VSTS.

Relaterade inlägg

Vill du vara säker på att inte missa något

Som du märker brinner vi för att dela med oss av våra erfarenheter, nyttiga lärdomar och spaningar ut i exosfären. Se till att följa vårt nyhetsbrev eller vårt flöde på Linkedin så du inte missar något.

Detta fält är dolt när formuläret visas

This website uses cookies

Cookies ("cookies") consist of small text files. The text files contain data which is stored on your device. To be able to place some type of cookies we need your consent. We at Exobe AB, corporate identity number 556769-5605 use these types of cookies. To read more about which cookies we use and storage duration, click here to get to our cookiepolicy.

Manage your cookie-settings

Necessary cookies

Necessary cookies are cookies that need to be placed for fundamental functions on the website to work. Fundamental functions are for instance cookies that are needed for you to use menus and navigate the website.

Functional cookies

Functional cookies need to be placed for the website to perform in the way that you expect. For instance to remember which language you prefer, to know if you are logged in, to keep the website secure, remember login credentials or to enable sorting of products on the website in the way that you prefer.

Statistical cookies

To know how you interact with the website we place cookies to collect statistics. These cookies anonymize personal data.

Personalization cookies

In order to provide a better experiance we place cookies for your preferances

Ad measurement cookies

To be able to provide a better service and experience we place cookies to tailor marketing for you. Another purpose for this placement is to market products or services to you, give tailored offers or market and give recommendations on new concepts based on what you have bought from us previously.

Ad measurement user cookies

In order to show relevant ads we place cookies to tailor ads for you

Personalized ads cookies

To show relevant and personal ads we place cookies to provide unique offers that are tailored to your user data