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

Denna webbplats använder cookies

Cookies ("kakor") består av små textfiler. Dessa innehåller data som lagras på din enhet. För att kunna placera vissa typer av cookies behöver vi inhämta ditt samtycke. Vi på Exobe AB, orgnr. 556769-5605 använder oss av följande slags cookies. För att läsa mer om vilka cookies vi använder och lagringstid, klicka här för att komma till vår cookiepolicy.

Hantera dina cookieinställningar

Nödvändiga cookies

Nödvändiga cookies är cookies som måste placeras för att grundläggande funktioner på webbplatsen ska kunna fungera. Grundläggande funktioner är exempelvis cookies som behövs för att du ska kunna använda menyer och navigera på sajten.

Funktionella cookies

Funktionella cookies behöver placeras för att webbplatsen ska kunna prestera som du förväntar dig, exempelvis så att den känner av vilket språk som du föredrar, för att känna av om du är inloggad, för att hålla webbplatsen säker, komma ihåg inloggningsuppgifter eller för att kunna sortera produkter på webbplatsen utefter dina preferenser.

Cookies för statistik

För att kunna veta hur du interagerar med webbplatsen placerar vi cookies för att föra statistik. Dessa cookies anonymiserar personuppgifter.

Cookies för personlig anpassning

För att ge dig en bättre upplevelse placerar vi cookies för dina preferenser

Cookies för annonsmätning

För att kunna erbjuda bättre service och upplevelse placerar vi cookies för att kunna anpassa marknadsföring till dig. Ett annat syfte med denna behandling är att kunna marknadsföra produkter eller tjänster till dig, ge anpassade erbjudanden eller marknadsföra och ge rekommendationer kring nya koncept utifrån vad du har köpt tidigare.

Cookies för personlig annonsmätning

För att kunna visa relevant reklam placerar vi cookies för att anpassa innehållet för dig

Cookies för anpassade annonser

För att visa relevanta och personliga annonser placerar vi cookies för att tillhandahålla unika erbjudanden som är skräddarsydda efter din användardata