我需要使用 Azure Devops Pipeline 测试新版本,一旦新版本准备就绪,就需要在新的虚拟机上进行测试。我尝试过自定义映像并将其存储在 Azure 市场中,从快照运行创建虚拟机,但很想知道其他人使用什么,以防有更好的东西。
有人使用类似的设置吗?
流水线启动的简化设置,它从自定义映像或快照创建新虚拟机,运行测试,然后报告测试失败或成功。
根据您的要求,
Azure Pipelines Agent
Azure VM 扩展 可能会有所帮助,因为它会自动将新的 Azure VM 添加为部署组中的目标。我们可以使用资源管理器模板与此扩展一起创建 Ubuntu Linux VM。
这是一个示例管道工作流程供您参考。
创建一个名为
DeploymentGroup-VMTest
的新部署组,并记下组 ID(在我的例子中为 439
);
用户
ARM Template deployment
创建新VM的管道任务;下面的示例 ARM 模板包括将 Azure Pipelines Agent
扩展安装到新 VM 上;此扩展会将新虚拟机配置为代理目标 D-Agent-r$(Release.ReleaseId)
,带有 Release
和 For test
标签;代理会将目标添加到部署组中DeploymentGroup-VMTest
;
VM.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.23.1.45101",
"templateHash": "5903517927080867595"
}
},
"parameters": {
"vmName": {
"type": "string",
"defaultValue": "azvm-ubuntu",
"metadata": {
"description": "The name of your Virtual Machine."
}
},
"adminUsername": {
"type": "string",
"defaultValue": "azureuser",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"authenticationType": {
"type": "string",
"defaultValue": "password",
"allowedValues": [
"sshPublicKey",
"password"
],
"metadata": {
"description": "Type of authentication to use on the Virtual Machine. SSH key is recommended."
}
},
"adminPasswordOrKey": {
"type": "securestring",
"metadata": {
"description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
}
},
"dnsLabelPrefix": {
"type": "string",
"defaultValue": "azvmdns",
"metadata": {
"description": "Unique DNS Name for the Public IP used to access the Virtual Machine."
}
},
"ubuntuOSVersion": {
"type": "string",
"defaultValue": "Ubuntu-2004",
"allowedValues": [
"Ubuntu-1804",
"Ubuntu-2004",
"Ubuntu-2204"
],
"metadata": {
"description": "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version."
}
},
"location": {
"type": "string",
"defaultValue": "Southeast Asia",
"metadata": {
"description": "Location for all resources."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_B1s",
"metadata": {
"description": "The size of the VM"
}
},
"virtualNetworkName": {
"type": "string",
"defaultValue": "vNet",
"metadata": {
"description": "Name of the VNET"
}
},
"subnetName": {
"type": "string",
"defaultValue": "Subnet",
"metadata": {
"description": "Name of the subnet in the virtual network"
}
},
"networkSecurityGroupName": {
"type": "string",
"defaultValue": "SecGroupNet",
"metadata": {
"description": "Name of the Network Security Group"
}
},
"securityType": {
"type": "string",
"defaultValue": "TrustedLaunch",
"allowedValues": [
"Standard",
"TrustedLaunch"
],
"metadata": {
"description": "Security Type of the Virtual Machine."
}
},
"VSTSAccountName": {
"type": "string",
"metadata": {
"description": "VSTS account name"
}
},
"TeamProject": {
"type": "string",
"metadata": {
"description": "VSTS team project name"
}
},
"DeploymentGroup": {
"type": "string",
"metadata": {
"description": "Deployment group name"
}
},
"AgentName": {
"type": "string",
"metadata": {
"description": "Name of the agent"
}
},
"PATToken": {
"type": "securestring",
"metadata": {
"description": "Personal Access Token (PAT) for authentication"
}
},
"Tags": {
"type": "array",
"metadata": {
"description": "Tags for the VM"
}
}
},
"variables": {
"imageReference": {
"Ubuntu-1804": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "18_04-lts-gen2",
"version": "latest"
},
"Ubuntu-2004": {
"publisher": "Canonical",
"offer": "0001-com-ubuntu-server-focal",
"sku": "20_04-lts-gen2",
"version": "latest"
},
"Ubuntu-2204": {
"publisher": "Canonical",
"offer": "0001-com-ubuntu-server-jammy",
"sku": "22_04-lts-gen2",
"version": "latest"
}
},
"publicIPAddressName": "[format('{0}PublicIP', parameters('vmName'))]",
"networkInterfaceName": "[format('{0}NetInt', parameters('vmName'))]",
"osDiskType": "Standard_LRS",
"subnetAddressPrefix": "10.1.0.0/24",
"addressPrefix": "10.1.0.0/16",
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[format('/home/{0}/.ssh/authorized_keys', parameters('adminUsername'))]",
"keyData": "[parameters('adminPasswordOrKey')]"
}
]
}
},
"securityProfileJson": {
"uefiSettings": {
"secureBootEnabled": true,
"vTpmEnabled": true
},
"securityType": "[parameters('securityType')]"
},
"extensionName": "GuestAttestation",
"extensionPublisher": "Microsoft.Azure.Security.LinuxAttestation",
"extensionVersion": "1.0",
"maaTenantName": "GuestAttestation",
"maaEndpoint": "[substring('emptystring', 0, 0)]"
},
"resources": [
{
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2021-05-01",
"name": "[variables('networkInterfaceName')]",
"location": "[parameters('location')]",
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]"
},
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
}
}
}
],
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]"
}
},
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]",
"[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]",
"[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]"
]
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2021-05-01",
"name": "[parameters('networkSecurityGroupName')]",
"location": "[parameters('location')]",
"properties": {
"securityRules": [
{
"name": "SSH",
"properties": {
"priority": 1000,
"protocol": "Tcp",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "22"
}
}
]
}
},
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2021-05-01",
"name": "[parameters('virtualNetworkName')]",
"location": "[parameters('location')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
}
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2021-05-01",
"name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('subnetName'))]",
"properties": {
"addressPrefix": "[variables('subnetAddressPrefix')]",
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
},
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]"
]
},
{
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2021-05-01",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Basic"
},
"properties": {
"publicIPAllocationMethod": "Dynamic",
"publicIPAddressVersion": "IPv4",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
},
"idleTimeoutInMinutes": 4
}
},
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2021-11-01",
"name": "[parameters('vmName')]",
"location": "[parameters('location')]",
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "[variables('osDiskType')]"
}
},
"imageReference": "[variables('imageReference')[parameters('ubuntuOSVersion')]]"
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
}
]
},
"osProfile": {
"computerName": "[parameters('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPasswordOrKey')]",
"linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), null(), variables('linuxConfiguration'))]"
},
"securityProfile": "[if(equals(parameters('securityType'), 'TrustedLaunch'), variables('securityProfileJson'), null())]"
},
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
]
},
{
"condition": "[and(equals(parameters('securityType'), 'TrustedLaunch'), and(equals(variables('securityProfileJson').uefiSettings.secureBootEnabled, true()), equals(variables('securityProfileJson').uefiSettings.vTpmEnabled, true())))]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"apiVersion": "2022-03-01",
"name": "[format('{0}/{1}', parameters('vmName'), variables('extensionName'))]",
"location": "[parameters('location')]",
"properties": {
"publisher": "[variables('extensionPublisher')]",
"type": "[variables('extensionName')]",
"typeHandlerVersion": "[variables('extensionVersion')]",
"autoUpgradeMinorVersion": true,
"enableAutomaticUpgrade": true,
"settings": {
"AttestationConfig": {
"MaaSettings": {
"maaEndpoint": "[variables('maaEndpoint')]",
"maaTenantName": "[variables('maaTenantName')]"
}
}
}
},
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]"
]
},
{
"name": "[concat(parameters('vmName'), '/TeamServicesAgentLinux')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"location": "[parameters('location')]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]"
],
"properties": {
"publisher": "Microsoft.VisualStudio.Services",
"type": "TeamServicesAgentLinux",
"typeHandlerVersion": "1.0",
"autoUpgradeMinorVersion": true,
"settings": {
"VSTSAccountName": "[parameters('VSTSAccountName')]",
"TeamProject": "[parameters('TeamProject')]",
"DeploymentGroup": "[parameters('DeploymentGroup')]",
"AgentName": "[parameters('AgentName')]",
"AgentMajorVersion": "auto|2|3",
"Tags": "[parameters('Tags')]"
},
"protectedSettings": {
"PATToken": "[parameters('PATToken')]"
}
}
}
],
"outputs": {
"adminUsername": {
"type": "string",
"value": "[parameters('adminUsername')]"
},
"hostname": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName')), '2021-05-01').dnsSettings.fqdn]"
},
"sshCommand": {
"type": "string",
"value": "[format('ssh {0}@{1}', parameters('adminUsername'), reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName')), '2021-05-01').dnsSettings.fqdn)]"
}
}
}
覆盖模板参数
-vmName“azvm-ubuntu-r$(Release.ReleaseId)”-adminUsername“azureuser”-authenticationType“密码”-adminPasswordOrKey $(PWD)-dnsLabelPrefix“azvmdns-r$(Release.ReleaseId)”-ubuntuOSVersion“ Ubuntu-2004" -location "东南亚" -vmSize "Standard_B1s" -virtualNetworkName "vNet-r$(Release.ReleaseId)" -subnetName "Subnet-r$(Release.ReleaseId)" -networkSecurityGroupName "SecGroupNet-r$(Release) .ReleaseId)" -securityType "TrustedLaunch" -VSTSAccountName $(System.TeamFoundationCollectionUri) -TeamProject $(System.TeamProject) -DeploymentGroup 部署组-VMTest -AgentName D-Agent-r$(Release.ReleaseId) - PATToken $(PAT) -标签 ["用于测试", "发布", "r$(Release.ReleaseId)"]
在 PowerShell 脚本中使用此 API 来删除部署组中意外目标的标签;
Write-Host Define the URL to retrieve the list of targets in DeploymentGroup-VMTest Id: $(DeploymentGroupId)
$targetsUrl = "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/distributedtask/deploymentgroups/$(DeploymentGroupId)/targets?api-version=7.1-preview.1"
$targetsUrl
# Use System.AccessToken of pipeline for API authentication
$headers = @{
'Authorization' = "bearer " + "$(System.AccessToken)"
'Content-Type' = 'application/json'
}
Write-Host Retrieve the targets in DeploymentGroup-VMTest Id: $(DeploymentGroupId)
$targetsResponse = Invoke-RestMethod -Uri $targetsUrl -Method Get -Headers $headers
$targetsResponse | ConvertTo-Json
Write-Host Loop through the targets and remove **For test** tags except D-Agent-r$(Release.ReleaseId)
foreach ($target in $targetsResponse.value) {
$agentName = $target.agent.name
# Exclude the agent "D-Agent-r$(Release.ReleaseId)"
if ($agentName -ne "D-Agent-r$(Release.ReleaseId)") {
$targetId = $target.id
$updateUrl = "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/distributedtask/deploymentgroups/$(DeploymentGroupId)/targets?api-version=7.1-preview.1"
# Check if the target has the tag "For test"
if ($target.tags -contains "For test") {
Write-Host Remove the tag "For test" from the target $agentName
$updateUrl
$tags = $target.tags | Where-Object {$_ -ne "For test"}
Write-Host Romove all tags for $agentName
$body = @"
[
{
"id": "$targetId",
"tags": []
}
]
"@
$body
$result = Invoke-RestMethod -Uri $updateUrl -Method PATCH -Headers $headers -Body $body
$result.value | ConvertTo-Json
}
}
}
在部署组作业中运行测试,将需要带有标签
For test
的目标,并且只有新的 VM 代理 D-Agent-r$(Release.ReleaseId)
具有标签 For test
;