Azure DevOps代理配置:如何让YAML流水线在Microsoft托管代理与自托管代理间自动选择空闲代理运行
配置YAML流水线实现跨代理自动调度
先明确两个关键前提:
- Microsoft托管代理是Azure Pipelines提供的临时代理(每次运行会创建新实例,用完销毁),属于
Azure Pipelines池,你无法“拥有”一个固定的托管代理,而是按需使用微软维护的公共代理池。 - 自托管代理是你自行部署维护的长期运行代理,属于你创建的自定义代理池。
下面分两种场景给出解决方案:
场景1:两个代理都是自托管(含Azure VM部署的自托管代理)
如果你的“Microsoft托管代理”其实是部署在Azure VM上的自托管代理(而非微软官方托管的临时代理),那最简单的方式是把两个自托管代理加入同一个自定义代理池:
- 在Azure DevOps的
项目设置→代理池中,创建或选择一个自定义池,把两个自托管代理都添加进去。 - (可选)给两个代理添加相同的自定义标签(比如
shared-runner),用于更精准的代理匹配。 - 在YAML流水线中指定这个代理池即可,Azure DevOps会自动在池内的空闲代理上运行任务:
pool: name: '你的自定义代理池名称' # 可选:如果加了标签,可指定标签进一步筛选 demands: - Agent.Name -equals shared-runner steps: - script: echo "任务会自动在池内空闲的代理上执行" displayName: '运行测试任务'
场景2:一个是微软官方托管代理,一个是自托管代理
因为微软托管代理和自托管代理分属不同的代理池,Azure DevOps原生不支持跨池自动调度空闲代理,但可以通过动态检测代理状态+条件选择池的方式实现近似效果:
实现步骤:
- 启用脚本权限:在流水线编辑页→
变量→流水线变量,勾选允许脚本访问OAuth令牌,让脚本能调用Azure DevOps API。 - 获取自托管池ID:在Azure DevOps的
组织设置→代理池→选择你的自托管池,URL中的数字就是池ID(比如https://dev.azure.com/你的组织/_settings/agentpools?poolId=123中的123)。 - 使用以下YAML配置,先检测自托管代理是否空闲,再动态选择对应的池:
variables: # 替换为你的自托管代理池ID selfHostedPoolId: '123' # 替换为你的自托管代理池名称 selfHostedPoolName: '你的自托管池名称' jobs: - job: CheckAgentAvailability # 先在微软托管代理上运行检测脚本 pool: vmImage: 'ubuntu-latest' steps: - powershell: | # 调用Azure DevOps API获取自托管池的代理状态 $orgUrl = "$(System.CollectionUri)" $pat = "$(System.AccessToken)" $headers = @{ Authorization = "Bearer $pat" } $agentsUrl = "$orgUrl/_apis/distributedtask/pools/$(selfHostedPoolId)/agents?api-version=7.1-preview.1" try { $agents = Invoke-RestMethod -Uri $agentsUrl -Headers $headers -Method Get # 筛选在线且未被占用的代理 $freeAgents = $agents.value | Where-Object { $_.status -eq 'online' -and $_.assignedRequest -eq $null } if ($freeAgents.Count -gt 0) { Write-Host "检测到空闲的自托管代理,将使用自托管池" Write-Host "##vso[task.setvariable variable=targetPool;isOutput=true]$(selfHostedPoolName)" } else { Write-Host "自托管代理全部忙碌,将使用微软托管代理" Write-Host "##vso[task.setvariable variable=targetPool;isOutput=true]AzurePipelines" } } catch { Write-Warning "检测代理状态失败,默认使用微软托管代理" Write-Host "##vso[task.setvariable variable=targetPool;isOutput=true]AzurePipelines" } name: SetTargetPool - job: RunPipelineTasks dependsOn: CheckAgentAvailability pool: ${{ if eq(dependencies.CheckAgentAvailability.outputs['SetTargetPool.targetPool'], variables.selfHostedPoolName) }}: name: $(selfHostedPoolName) ${{ else }}: vmImage: 'ubuntu-latest' # 可替换为你需要的托管镜像,比如windows-latest steps: - script: echo "当前运行在:$(Agent.Name),所属池:$(Agent.PoolName)" displayName: '显示代理信息' # 这里添加你的实际任务步骤 - script: echo "执行核心任务逻辑"
注意事项:
- 检测脚本存在微小的时间差,如果检测后自托管代理被其他任务占用,仍会进入排队状态。
- 默认
System.AccessToken有足够的权限读取代理池信息,若遇到权限问题可在组织设置中调整权限。
内容的提问来源于stack exchange,提问作者Rasmus
相关产品推荐
相关产品推荐

