可以将托管 DevOps 池代理配置为在隔离的虚拟网络或现有虚拟网络中运行。 本文介绍如何将池配置为在虚拟网络中运行代理。
选择网络类型
托管 DevOps 池支持两种类型的网络配置:
- 独立虚拟网络:每个池获取其自己的独立虚拟网络,该虚拟网络由托管 DevOps 池服务创建和管理。
-
注入到现有虚拟网络中的代理:可以自带虚拟网络和子网。 为池创建的所有虚拟机都将使用该子网,其他任何资源都无法使用该子网。 您可能希望在以下情况下将托管 DevOps 池中的代理添加到自己的虚拟网络:
- 持续集成和持续交付(CI/CD)代理需要通过 Azure ExpressRoute 等服务访问仅在公司网络中可用的资源。
- CI/CD 代理需要访问被隔离到私有终结点的资源。
- 你希望通过引入自己的虚拟网络和公司特定的防火墙规则来隔离 CI/CD 基础设施。
- 任何其他无法通过现成托管 DevOps 池网络功能实现的独特用例。
独立虚拟网络
默认情况下,所有池都使用Microsoft提供的虚拟网络,该虚拟网络限制所有入站流量,并具有以下出站流量配置选项。
- 默认出站访问连接是当前的默认值,允许使用Microsoft提供的 IP 地址的所有出站流量。 Azure 中的虚拟机的默认出站访问功能已计划淘汰。 当默认出站访问停用时,池将默认配置一个静态 IP 地址。
- 可以将池配置为使用最多 16 个静态出站 IP 地址,而不是使用默认出站访问。 托管 DevOps 池将在池所在的同一区域中创建 NAT 网关,以提供 IP 地址。 通过此配置,可以在管道需要访问的外部服务上列出特定的 IP 地址。
- NAT 网关会产生额外的 Azure 成本。 可以使用 Azure 成本计算器对费用进行建模。 有关详细信息,请参阅 Azure NAT 网关定价。
重要
如果在创建池后修改静态 IP 地址计数,IP 地址可能会更改,并且需要在更新作完成后获取新的 IP 地址并更新外部服务上的允许列表。
若要在创建池时配置 IP 地址设置,请转到“ 网络 ”选项卡。若要更新现有池,请转到 “设置>网络”。
选择“无”,通过公共 IP 地址路由以使用默认出站访问。
选择 Microsoft提供的 IP 来配置静态出站 IP 地址,并指定要使用的静态 IP 地址数。 托管 DevOps 池会为你创建 NAT 网关并管理 IP 地址。
注释
存在一个已知问题:如果池配置了托管标识,除非为托管标识的 DevOpsInfrastructure 服务主体分配了托管标识操作员角色,否则 API 调用不会返回该属性。 有关详细步骤,请参阅使用 Azure 门户分配 Azure 角色。
要使静态 IP 地址正常运行,不需要授予此角色。 如果没有此角色分配,仍可以通过在 Azure 门户中的 “网络 ”页上查看分配的 IP 地址来找到这些地址。
注入到现有虚拟网络中的代理
您可以通过以下步骤配置您的池代理以使用您的虚拟网络:
前面的步骤将子网分配给池以进行独占访问。 其他的池或资源无法使用该子网。
池可以使用多个子网将多个池连接到同一虚拟网络。 每个子网都被分配并与自己的池相关联。
创建或引入虚拟网络和子网
子网必须有足够的地址空间来容纳要关联的池的最大池大小(包括 Azure 在子网中保留的五个 IP 地址)。
如果使用 ExpressRoute,则需要通过暂时删除或更改资源组上的管理锁来允许写入。
重要
池和虚拟网络必须位于同一区域。 否则,尝试创建池或更新网络配置时,会收到类似于以下内容的错误:“虚拟网络 MDPVN 位于区域 eastus 中,但池 mdpnonprodsub 位于 australiaeast 区域。 这些必须位于同一区域。
授予读者和网络参与者对 DevOpsInfrastructure 服务主体的访问权限
确保 DevOpsInfrastructure 主体在虚拟网络上具有 Reader 和 Network Contributor 访问权限。
可以创建具有以下权限的自定义角色,而不是使用内置角色:
Microsoft.Network/virtualNetworks/*/readMicrosoft.Network/virtualNetworks/subnets/join/actionMicrosoft.Network/virtualNetworks/subnets/serviceAssociationLinks/validate/actionMicrosoft.Network/virtualNetworks/subnets/serviceAssociationLinks/writeMicrosoft.Network/virtualNetworks/subnets/serviceAssociationLinks/delete
为服务关联链接访问权限创建自定义角色。 可以在“ 访问控制 ”选项卡上的资源组或订阅级别创建示例角色,如以下示例所示。
检查 DevOpsInfrastructure 的主要访问权限
选择虚拟网络的 访问控制(IAM), 然后选择“ 检查访问权限”。
搜索并选择 DevOpsInfrastructure。
验证你是否具有 读取者 级别访问权限。 验证是否为
Microsoft.Network/virtualNetworks/subnets/join/action、Microsoft.Network/virtualNetworks/subnets/serviceAssociationLinks/validate/action和Microsoft.Network/virtualNetworks/subnets/serviceAssociationLinks/write分配了访问权限。 自定义角色应在此处显示。
如果 DevOpsInfrastructure 主体没有这些权限,请添加它们。 选择虚拟网络的 访问控制(IAM), 然后选择 “授予对此资源的访问权限”。
将子网委托给 Microsoft.DevOpsInfrastructure/pools
在门户中,打开“子网属性”,然后在Microsoft.DevOpsInfrastructure/pools”下选择。 选择“保存”。
此过程将子网指定为供池独享访问。 其他的池或资源无法使用该子网。 若要将多个池连接到同一虚拟网络,必须使用多个子网。 每个子网必须分配并与其自己的池相关联。 有关子网委派的详细信息,请参阅 此子网委派概述。
子网委托给 Microsoft.DevOpsInfrastructure/pools 后,您可以更新资源池以便使用该子网。
将子网与池关联
若要创建新池,请转到“网络”选项卡。若要更新现有池,请转到“设置>”,然后选择注入到现有虚拟网络>配置的代理。
选择委托给的订阅、虚拟网络和
Microsoft.DevOpsInfrastructure/pools值,然后选择“确定”。
网络更新完成后,池中新创建的资源将使用委托的子网。
重要
更新池时,不要在虚拟网络上放置 Delete 锁。 在池更新操作期间,管理的 DevOps 池会在子网上创建 服务关联链接。 如果更新失败,托管 DevOps 池将尝试清理服务关联链接,但如果存在 Delete 锁,则会收到错误 InUseSubnetCannotBeDeleted 。 托管 DevOps 池无法删除服务关联链接,该链接使子网处于锁定状态(无法删除)。 若要解决此问题,请删除 删除 锁并重试更新作。
有关详细信息,请参阅 在将锁应用到 Azure 资源之前要考虑的事项。
限制出站连接
如果在网络(例如,网络安全组或防火墙)上安装了限制出站连接的系统,则需要将某些终结点添加到允许名单,以完全支持托管的 DevOps 池。 这些终结点分为两类:全局必需终结点(在任何使用托管 DevOps 池的计算机上都必需)和特定场景所需的终结点。 除非另有说明,否则所有终结点都是 HTTPS。
启动托管 DevOps 资源池所需的终结点
如果未将这些终结点添加到允许列表,计算机将无法作为托管 DevOps 池服务的一部分联机,并且无法在池上运行管道:
-
*.prod.manageddevops.microsoft.com:用于与托管 DevOps 池服务通信的托管 DevOps 池终结点。 -
rmprodbuilds.azureedge.net:用于下载托管 DevOps 池工作程序的二进制文件和启动脚本。 代理部分的工作器二进制文件现在从rm-agent.prod.manageddevops.microsoft.com下载(以前是从agent.prod.manageddevops.microsoft.com下载的),这部分内容已在先前必须的*.prod.manageddevops.microsoft.com条目中涵盖。 -
*.queue.core.windows.net:用于与托管 DevOps 池服务通信的工作队列。
连接到 Azure DevOps 所需的端点
如果不将这些终结点添加到允许列表,则计算机可能联机,甚至可能进入 分配 状态,但无法与 Azure DevOps 通信,因为 Azure DevOps Services 任务代理无法连接或无法启动。
-
download.agent.dev.azure.com:Azure DevOps 代理的内容分发网络(CDN)位置,用于下载 Azure DevOps 代理(以前vstsagentpackage.azureedge.net;有关详细信息,请参阅 适用于 Azure DevOps 的 Edgio CDN 即将停用)。 -
dev.azure.com:需要处理与 Azure DevOps 的通信。
Linux 机器所需的端点
这些终结点是启动 Ubuntu 计算机所必需的,但如果池仅使用 Windows,则不需要这些终结点。 设置 Azure DevOps 任务代理时,会添加所需的包并 apt-get 运行命令。 如果未将以下终结点添加到允许列表,则此过程将失败。
-
azure.archive.ubuntu.com:预配 Linux 计算机。 此终结点是 HTTP(端口 80),而不是 HTTPS(端口 443)。 -
www.microsoft.com:预配 Linux 计算机。 -
security.ubuntu.com:预配 Linux 计算机。 -
packages.microsoft.com:预配 Linux 计算机。 -
ppa.launchpad.net:预配一些特定的 Linux 分发版。 -
dl.fedoraproject.org:配置某些 Linux 发行版。
某些 Azure DevOps 功能所需的终结点
特定 Azure DevOps 功能需要这些可选终结点才能在管道上运行。 在以下集合中,通配符可以替换为托管你管道的特定 Azure DevOps 组织。 例如,如果组织命名 contoso,则可以使用 contoso.services.visualstudio.com 而不是 *.services.visualstudio.com。
*.services.visualstudio.com-
*.vsblob.visualstudio.com:用于上传和使用制品。 -
*.vssps.visualstudio.com:用于对某些功能使用 Azure DevOps 进行身份验证。 *.visualstudio.com
注释
上述条目是所需的最小域。 如果遇到任何问题,请参阅 Azure DevOps 允许的 IP 地址和域 URL 中所需域的完整列表。
与 Azure 相关的终结点
Azure 虚拟机(VM)可能会通过子网将流量路由到某些 Azure 功能。 对于这些请求,可以直接通过 Azure 路由请求,或者通过网络启用访问。
-
可以直接通过 Azure 路由流量,以避免增加网络安全组或防火墙的吞吐量压力。 无需将以下选项中列出的域添加到允许列表。
例如,可以使用 数据磁盘 功能来涉及对 Azure 存储的网络调用。 在网络上启用 Microsoft.Storage 服务终结点时,流量会直接通过 Azure 路由,从而避免网络规则并减少负载。
若要避免通过服务终结点路由流量,请将域
md-*.blob.storage.azure.net添加到允许列表。 配置 数据磁盘需要此域。
Akamai CDN 分发 IP
2025 年 5 月 1 日,Azure DevOps CDN 资产转换为 Akamai 和 Azure Front Door 提供的解决方案。 确保网络对 Akamai IP 范围具有出站访问权限。 有关详细信息,请参见:
如果将 Azure DevOps 管道配置为在容器内运行,则还需要将容器映像的源(Docker 或 Azure 容器注册表)添加到允许列表。
验证终结点连接
通过在该子网上的一个资源上运行以下脚本,确认该子网可以与托管 DevOps 池一起使用。 此步骤将帮助你验证网络流是否已配置为访问所有这些可用的终结点和托管 DevOps 控制平面。
重要
必须在子网中的资源(例如 VM 或容器)上运行此脚本,以验证网络路径是否从该子网打开到所需的终结点。
若要使用 PowerShell Core 或 PowerShell 5 或更高版本运行脚本,请将以下脚本另存为 ValidateMDPEndpoints.ps1。 运行以下 PowerShell 命令: .\ValidateMDPEndpoints.ps1 -organization "<your-organization>"
# ValidateMDPEndpoints.ps1
param (
[string]$organization
)
$azureDevOpsUris = @(
"https://dev.azure.com",
"https://vssps.dev.azure.com",
"https://vsrm.dev.azure.com",
"https://management.azure.com",
"https://login.microsoftonline.com",
"https://graph.microsoft.com",
"https://aadcdn.msftauth.net",
"https://${organization}.visualstudio.com",
"https://${organization}.vsrm.visualstudio.com",
"https://${organization}.vstmr.visualstudio.com",
"https://${organization}.pkgs.visualstudio.com",
"https://${organization}.vssps.visualstudio.com",
"https://download.agent.dev.azure.com",
"download.agent.dev.azure.com"
)
$managedDevOpsPoolsControlPlaneUris = @(
# List of agent queue endpoints - maps to *.queue.core.windows.net
"https://rmprodaedefaultcq.queue.core.windows.net",
"https://rmprodbrsdefaultcq.queue.core.windows.net",
"https://rmprodcncdefaultcq.queue.core.windows.net",
"https://rmprodcusdefaultcq.queue.core.windows.net",
"https://rmprodeus2defaultcq.queue.core.windows.net",
"https://rmprodgwcdefaultcq.queue.core.windows.net",
"https://rmprodincdefaultcq.queue.core.windows.net",
"https://rmprodneudefaultcq.queue.core.windows.net",
"https://rmprodseadefaultcq.queue.core.windows.net",
"https://rmprodszndefaultcq.queue.core.windows.net",
"https://rmproduksdefaultcq.queue.core.windows.net",
"https://rmprodwus3defaultcq.queue.core.windows.net",
# CDN for downloading the Managed DevOps Pools agent - maps to *.prod.managedevops.microsoft.com
"rm-agent.prod.manageddevops.microsoft.com"
# List of control plane endpoints - maps to *.manageddevops.microsoft.com
"default.ae.prod.manageddevops.microsoft.com",
"default.brs.prod.manageddevops.microsoft.com",
"default.cnc.prod.manageddevops.microsoft.com",
"default.cus.prod.manageddevops.microsoft.com",
"default.eus2.prod.manageddevops.microsoft.com",
"default.gwc.prod.manageddevops.microsoft.com",
"default.inc.prod.manageddevops.microsoft.com",
"default.neu.prod.manageddevops.microsoft.com",
"default.sea.prod.manageddevops.microsoft.com",
"default.szn.prod.manageddevops.microsoft.com",
"default.uks.prod.manageddevops.microsoft.com",
"default.wus3.prod.manageddevops.microsoft.com"
)
$unreachableUris = @()
foreach ($uri in $azureDevOpsUris) {
try {
$hostName = ($uri -replace "^https?://", "") -replace "/.*", ""
$connection = Test-NetConnection -ComputerName $hostName -Port 443 -WarningAction SilentlyContinue
if (-not $connection.TcpTestSucceeded) {
$unreachableUris += $uri
}
} catch {
$unreachableUris += $uri
}
}
if ($unreachableUris.Count -eq 0) {
Write-Output "All Azure DevOps endpoints are reachable."
} else {
Write-Output "The following Azure DevOps endpoints could not be reached:"
$unreachableUris | ForEach-Object { Write-Output $_ }
}
foreach ($uri in $managedDevOpsPoolsControlPlaneUris) {
try {
$hostName = ($uri -replace "^https?://", "") -replace "/.*", ""
$connection = Test-NetConnection -ComputerName $hostName -Port 443 -WarningAction SilentlyContinue
if (-not $connection.TcpTestSucceeded) {
$unreachableUris += $uri
}
} catch {
$unreachableUris += $uri
}
}
if ($unreachableUris.Count -eq 0) {
Write-Output "All Azure Managed DevOps Pools endpoints are reachable."
} else {
Write-Output "The following Managed DevOps Pools endpoints could not be reached:"
$unreachableUris | ForEach-Object { Write-Output $_ }
}
将 Azure DevOps 代理配置为通过代理服务器运行
如果在映像上配置了代理服务,并且希望池上运行的工作负载在此代理后面运行,则必须在映像上添加以下环境变量:
-
VSTS_AGENT_INPUT_PROXYURL:用于在后台运行的已配置代理的 URL。 -
VSTS_AGENT_INPUT_PROXYUSERNAME:使用代理所需的用户名。 -
VSTS_AGENT_INPUT_PROXYPASSWORD:使用代理的密码。
对于 Windows,这些环境变量应为系统环境变量。 对于 Linux,这些变量应位于 /etc/environment 文件中。 如果在映像上未正确设置这些系统变量或未配置代理服务,则预配新代理会失败并出现网络连接问题。
如果要从 Azure 虚拟机规模集代理进行迁移,并且已在映像上使用代理环境变量,则无需进行任何更改。 Azure 虚拟机规模集代理中介绍了此过程:自定义管道代理配置。