你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

将 Azure 资源移到新的资源组或订阅

本文介绍如何在同一个订阅内或跨不同的订阅在资源组之间移动 Azure 资源。 如果移动操作涉及到不同的订阅,则两个订阅必须属于同一个 Microsoft Entra ID 租户。 可以使用 Azure 门户Azure PowerShellAzure CLIREST APIPython 等工具来移动资源。

在执行移动操作期间,源资源组和目标资源组都将被锁定。 无法在移动过程中创建、删除或更新这些资源组中的资源。 但是,现有资源仍可完全正常运行。 例如,如果将虚拟机从一个资源组移动到另一个资源组,则无法在移动期间删除虚拟机或修改其属性(如其大小)。 尽管存在这种限制,但虚拟机继续正常运行,依赖虚拟机的服务不会经历任何故障时间。 锁最多可以持续四个小时。 大多数移动都完成得更快,锁也相应地被移除。

只能在移动请求中指定顶级(父)资源。 子资源随父资源自动移动,但无法独立移动。 例如,可以移动父资源(如 Microsoft.Compute/virtualMachines),其子资源(如 Microsoft.Compute/virtualMachines/extensions)也会随之移动。 但是,无法自行移动子资源。

移动资源时会保留其与子资源的依赖关系,但与其他资源的依赖关系可能会中断,可能需要再次配置。 移动某个资源只会更改其关联的资源组,而不会更改该资源的物理区域。

注意

如果源、目标资源组或订阅上存在只读锁,则无法移动 Azure 资源。

更改的资源 ID

移动资源时,会更改其资源 ID。 资源 ID 的标准格式为 /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}。 将资源移到新的资源组或订阅时,会更改该路径中的一个或多个值。

如果在任意位置使用资源 ID,请更改该值。 例如,如果门户中有引用资源 ID 的自定义仪表板,请更新该值。 查找需要针对新资源 ID 进行更新的任何脚本或模板。

移动资源前需查看的清单

移动资源之前,需要执行一些重要步骤。 如果验证这些条件,则可以避免错误。

  1. 源订阅和目标订阅必须处于活动状态。 如果在启用已禁用的帐户时遇到问题,请创建 Azure 支持请求。 选择“订阅管理” 作为问题类型。

  2. 源订阅与目标订阅必须在同一个 Microsoft Entra 租户中。 使用 Azure CLI 或 Azure PowerShell 检查这两个订阅是否具有相同的租户 ID。

    az account show --subscription <your-source-subscription> --query tenantId
    az account show --subscription <your-destination-subscription> --query tenantId
    

    如果源订阅和目标订阅的租户 ID 不匹配,请使用以下方法协调它们:

  3. 若要将资源移入或移出云解决方案提供商 (CSP) 合作伙伴,请参阅在订阅者和 CSP 之间转移 Azure 订阅

  4. 要移动的资源必须支持移动操作。 有关哪些资源支持移动操作的列表,请参阅用于移动操作的 Azure 资源类型

  5. 某些服务在移动资源时有特定的限制或要求。 在移动这些服务中的资源之前,请检查以下移动指导:

  1. 必须为要移动的资源的资源提供程序注册目标订阅。 如果没有,则会收到一条错误,指出“未针对资源类型注册订阅”。 将资源移动到新订阅时,可能会看到此错误,但以前未在订阅中使用资源类型。

    若要获取注册状态,请执行:

    az account set -s <destination-subscription-name-or-id>
    az provider list --query "[].{Provider:namespace, Status:registrationState}" --out table
    

    若要注册资源提供程序:

    az provider register --namespace Microsoft.Batch
    
  2. 在开始移动操作之前,请检查要向其移动资源的订阅的订阅配额。 验证你是否可以请求增加配额,使得目标订阅超出其限制。 有关限制以及如何请求增加的详细指导,请参阅 Azure 订阅和服务限制、配额和约束

  3. 移动资源的帐户至少需要具备下列权限:

    • 在源资源组上:Microsoft.Resources/subscriptions/resourceGroups/moveResources/action
    • 在目标资源组上:Microsoft.Resources/subscriptions/resourceGroups/write
  4. 如果移动具有活动 Azure 角色分配的资源(或其具有相同分配的子资源),则角色分配不会移动并会成为孤立资源。 移动后必须再次创建角色分配。 尽管系统会自动移除孤立的角色分配,但建议在移动之前将其移除。

    若要详细了解如何管理角色分配,请参阅列出 Azure 角色分配分配 Azure 角色

  5. 若要跨订阅移动,则资源及其依赖资源必须位于同一资源组中,并且必须一起移动。 例如,具有托管磁盘的虚拟机需要将虚拟机、托管磁盘和其他依赖资源一起移动。

    如果要将某个资源移到新的订阅,请检查该资源是否有任何依赖资源,以及它们是否位于同一资源组中。 如果资源不在同一资源组中,请检查是否可以将它们合并到同一资源组中。 如果可以,请使用跨资源组的一次移动操作将所有资源合并到同一资源组中。

    有关详细信息,请参阅跨订阅移动方案

适用于跨订阅移动的方案

将资源从一个订阅移到另一个订阅分为三步。 为了说明这些步骤,下图只描述一个依赖资源:

显示跨订阅移动资源的三步过程的示意图。

  • 步骤 1:如果依赖资源分布在不同的资源组中,请先将它们移到一个资源组。
  • 步骤 2:将资源和依赖资源一起从源订阅移到目标订阅。
  • 步骤 3:也可将依赖资源重新分布到目标订阅中的不同资源组。

移动资源

使用 Azure 门户

  1. 若要移动资源,请选择包含那些资源的资源组。

  2. 选择要移动的资源。 若要移动所有资源,请选中列表顶部的复选框。 或者,分别选择各个资源。

    Azure 门户的屏幕截图,其中显示了要移动的资源的选择。

  3. 选择“移动”按钮

    Azure 门户的屏幕截图,其中显示了带有三个选项的“移动”按钮。

    此按钮提供了三个选项:

    • 移动到新的资源组。
    • 移动到新的订阅。
  1. 如果要将资源移动到新的资源组或订阅,请选择。

  2. 源资源组会自动设置。 指定目标资源组。 如果要移动到新订阅,请指定此选项。 选择下一步

    Azure 门户的屏幕截图,其中显示了用户指定要执行移动操作的目标资源组。

  3. 门户验证资源是否可移动。 等待验证完成。

Azure 门户的屏幕截图,其中显示了移动操作的验证过程。

  1. 验证成功完成后,选择“下一步”。

  2. 确认需要更新这些资源的工具和脚本。 若要开始移动资源,请选择“移动”。

Azure 门户的屏幕截图,其中显示了用户确认需要在开始移动操作之前更新工具和脚本。

  1. Azure 门户会在移动完成后通知你。

Azure 门户的屏幕截图,其中显示了包含移动操作结果的通知。

使用 Azure CLI

Validate

若要在不实时移动资源的情况下测试移动方案,请使用 az resource invoke-action 命令。 仅当需要对结果进行建模而不进行后续操作时,才使用此命令。 若要运行此操作,你需要源资源组、目标资源组以及要移动的每个资源的资源 ID。

使用 \" 转义请求正文中的双引号。

az resource invoke-action --action validateMoveResources \
  --ids "/subscriptions/{subscription-id}/resourceGroups/{source-rg}" \
  --request-body "{  \"resources\": [\"/subscriptions/{subscription-id}/resourceGroups/{source-rg}/providers/{resource-provider}/{resource-type}/{resource-name}\", \"/subscriptions/{subscription-id}/resourceGroups/{source-rg}/providers/{resource-provider}/{resource-type}/{resource-name}\", \"/subscriptions/{subscription-id}/resourceGroups/{source-rg}/providers/{resource-provider}/{resource-type}/{resource-name}\"],\"targetResourceGroup\":\"/subscriptions/{subscription-id}/resourceGroups/{destination-rg}\" }" 

如果验证通过,则会看到:

{} Finished .. 

如果验证失败,则会看到一条错误消息,说明无法移动资源的原因。

移动

要将现有资源移到另一个资源组或订阅,请使用 az resource move 命令。 在 --ids 参数中,提供要移动的资源 ID 的空格分隔列表。

下面的命令演示了如何将多个资源移动到新的资源组。 它们适用于 Bash 终端或 Azure PowerShell 控制台中的 Azure CLI。 若要将资源移动到新订阅,请提供 --destination-subscription-id 参数。

webapp=$(az resource show -g OldRG -n ExampleSite --resource-type "Microsoft.Web/sites" --query id --output tsv)
plan=$(az resource show -g OldRG -n ExamplePlan --resource-type "Microsoft.Web/serverfarms" --query id --output tsv)
az resource move --destination-group newgroup --ids $webapp $plan

使用 Azure PowerShell

Validate

若要在不实时移动资源的情况下测试移动方案,请在 Azure PowerShell 中使用 Invoke-AzResourceAction 命令。 仅当需要对结果进行建模而不进行后续操作时,才使用此命令。

$sourceName = "sourceRG"
$destinationName = "destinationRG"
$resourcesToMove = @("app1", "app2")

$sourceResourceGroup = Get-AzResourceGroup -Name $sourceName
$destinationResourceGroup = Get-AzResourceGroup -Name $destinationName

$resources = Get-AzResource -ResourceGroupName $sourceName | Where-Object { $_.Name -in $resourcesToMove }

Invoke-AzResourceAction -Action validateMoveResources `
  -ResourceId $sourceResourceGroup.ResourceId `
  -Parameters @{
  resources = $resources.ResourceId;  # Wrap in an @() array if providing a single resource ID string.
  targetResourceGroup = $destinationResourceGroup.ResourceId
  }

如果验证成功,则不会显示输出。 但是,如果验证失败,错误消息将解释为何无法移动资源。

移动

要将现有资源移到另一个资源组或订阅,请使用 Move-AzResource 命令。 下面的示例演示了如何将多个资源移动到新的资源组。

$sourceName = "sourceRG"
$destinationName = "destinationRG"
$resourcesToMove = @("app1", "app2")

$resources = Get-AzResource -ResourceGroupName $sourceName | Where-Object { $_.Name -in $resourcesToMove }

Move-AzResource -DestinationResourceGroupName $destinationName -ResourceId $resources.ResourceId

若要移到新订阅,请包含 DestinationSubscriptionId 参数的值。

使用 Python

Validate

若要在不实时移动资源的情况下测试移动方案,请使用 ResourceManagementClient.resources.begin_validate_move_resources 方法。 仅当需要对结果进行建模而不进行后续操作时,才使用此方法。

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ResourceManagementClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

resource_client = ResourceManagementClient(credential, subscription_id)

source_name = "sourceRG"
destination_name = "destinationRG"
resources_to_move = ["app1", "app2"]

destination_resource_group = resource_client.resource_groups.get(destination_name)

resources = [
  resource for resource in resource_client.resources.list_by_resource_group(source_name)
  if resource.name in resources_to_move
]

resource_ids = [resource.id for resource in resources]

validate_move_resources_result = resource_client.resources.begin_validate_move_resources(
  source_name,
  {
  "resources": resource_ids,
  "target_resource_group": destination_resource_group.id
  }
).result()

print("Validate move resources result: {}".format(validate_move_resources_result))

如果验证成功,则不会显示输出。 但是,如果验证失败,错误消息将解释为何无法移动资源。

移动

要将现有资源移到另一个资源组或订阅,请使用 Python 中的 ResourceManagementClient.resources.begin_move_resources 命令。 下面的示例演示了如何将多个资源移动到新的资源组。

import os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ResourceManagementClient

credential = AzureCliCredential()
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

resource_client = ResourceManagementClient(credential, subscription_id)

source_name = "sourceRG"
destination_name = "destinationRG"
resources_to_move = ["app1", "app2"]

destination_resource_group = resource_client.resource_groups.get(destination_name)

resources = [
  resource for resource in resource_client.resources.list_by_resource_group(source_name)
  if resource.name in resources_to_move
]

resource_ids = [resource.id for resource in resources]

resource_client.resources.begin_move_resources(
  source_name,
  {
  "resources": resource_ids,
  "target_resource_group": destination_resource_group.id
  }
)

使用 REST API

Validate

validate move operation 操作测试你的移动应用场景,而不实际移动资源。 使用此操作检查移动是否会成功。 发送移动请求时会自动调用验证。 仅当需要对结果进行建模而不进行后续操作时,才使用此操作。 若要运行此操作,需要:

  • 源资源组的名称
  • 目标资源组的资源 ID
  • 要移动的每个资源的资源 ID
  • 你的帐户的访问令牌

发送以下请求:

POST https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<source-group>/validateMoveResources?api-version=2019-05-10
Authorization: Bearer <access-token>
Content-type: application/json

包含请求正文:

{
 "resources": ["<resource-id-1>", "<resource-id-2>"],
 "targetResourceGroup": "/subscriptions/<subscription-id>/resourceGroups/<target-group>"
}

如果请求格式正确,则操作将返回:

Response Code: 202
cache-control: no-cache
pragma: no-cache
expires: -1
location: https://management.azure.com/subscriptions/<subscription-id>/operationresults/<operation-id>?api-version=2018-02-01
retry-after: 15
...

202 状态代码指示已接受验证请求,但尚未确定移动操作是否会成功。 location 值包含用于检查长时间运行操作的状态的 URL。

若要检查状态,请发送以下请求:

GET <location-url>
Authorization: Bearer <access-token>

在操作运行时,你将继续收到 202 状态代码。 请等待 retry-after 值中所示的秒数,然后重试。 如果移动验证成功,则会收到 204 状态代码。 如果移动验证失败,你会收到错误消息,类似于:

{"error":{"code":"ResourceMoveProviderValidationFailed","message":"<message>"...}}

移动

要将现有资源移到另一个资源组或订阅,请使用 Move resources 操作。

POST https://management.azure.com/subscriptions/{source-subscription-id}/resourcegroups/{source-resource-group-name}/moveResources?api-version={api-version}

在请求正文中指定要移动的目标资源组和资源。

{
 "resources": ["<resource-id-1>", "<resource-id-2>"],
 "targetResourceGroup": "/subscriptions/<subscription-id>/resourceGroups/<target-group>"
}

常见问题解答

我的资源移动操作通常只需几分钟的时间,但这次已运行了几乎一个小时。 是否哪个环节出错了?

移动资源是一项复杂的操作,包含不同的阶段。 它不仅仅涉及你尝试移动的资源的资源提供程序。 Azure 资源管理器允许移动操作在四小时内完成,因为资源提供程序之间的依赖关系。 此持续时间可让他们有时间从暂时性问题中恢复。 如果你的移动请求还在四小时期间内,则操作会继续尝试完成,并且可能会成功。 该操作在此期间锁定源和目标资源组,以避免一致性问题。

为什么我的资源组在资源移动期间被锁定了四个小时?

  • 移动操作被允许在四小时内完成。 该操作在此期间锁定源和目标资源组,以防止修改它们。

  • 移动请求中有两个阶段。 第一阶段的资源移动以及依赖于所移动资源的资源提供程序会在第二阶段收到通知。 如果某个资源提供程序在任一阶段失败,则资源组可能会被锁定整整四个小时。 资源管理器启动移动操作期间失败的所有步骤。

  • 如果资源在四小时内未移动,则资源管理器会解锁两个资源组。 成功移动的资源位于目标资源组中。 未能移动的资源留在源资源组中。

在资源移动期间锁定源和目标资源组有什么影响?

该锁会阻止你删除任一资源组。 锁还会阻止在每个资源组中创建新资源、删除资源或更新资源的属性(例如,更改虚拟机的大小)。

下图显示了当你尝试删除正在移动的资源组时来自 Azure 门户的错误消息:

Azure 门户的屏幕截图,其中显示了尝试删除正在进行的移动操作中涉及的资源组时出现的错误消息。

在上图中,虚拟机资源属于当前正在进行移动操作的资源组(“TestB”)。 当你尝试更新虚拟机的属性(例如其大小)时,Azure 门户会返回错误消息。 之所以发生此错误,是因为资源组在移动期间被锁定,这可以防止资源被修改。

Azure 门户的屏幕截图,其中显示了当用户尝试更新虚拟机的属性(虚拟机大小)时出现的错误消息。

此外,源资源组和目标资源组无法在资源移动期间同时参与其他移动操作。 例如,如果要将资源从资源组 A 移动到资源组 B,则资源组 A 和资源组 B 不能同时参与另一个移动操作。 不能同时将资源移入或移出资源组 C。此限制可防止在移动过程中多个冲突的操作锁定资源组。

错误代码“MissingMoveDependentResources”的含义是什么?

移动资源时,依赖的资源必须存在于目标资源组或订阅中,或者包含在移动请求中。 当依赖的资源不满足此要求时,你将收到 MissingMoveDependentResources 错误代码。 错误消息提供有关移动请求中需要包含的依赖资源的详细信息。

例如,移动某个虚拟机可能需要移动具有三个不同资源提供程序的七个资源类型。 这些资源提供程序和类型为:

  • Microsoft.Compute

    • virtualMachines
    • disks
  • Microsoft.Network

    • networkInterfaces
    • publicIPAddresses
    • networkSecurityGroups
    • virtualNetworks
  • Microsoft.Storage

    • storageAccounts

另一个常见示例涉及移动虚拟网络,其中你可能需要移动与该虚拟网络关联的多个其他资源。 移动请求可能要求移动公共 IP 地址、路由表、虚拟网络网关、网络安全组和其他资源。 虚拟网络网关应与其虚拟网络位于同一资源组中,因为它们无法单独移动。

错误代码“RequestDisallowedByPolicy”的含义是什么?

资源管理器会在尝试移动之前验证移动请求。 此验证包括检查为移动所涉及的资源定义的策略。 例如,当你尝试移动密钥保管库时,验证失败,但贵组织有一个策略来拒绝在目标资源组中创建密钥保管库。 返回的错误代码为 RequestDisallowedByPolicy。

有关策略的详细信息,请参阅什么是 Azure Policy?

为何无法移动 Azure 中的某个资源?

并非所有 Azure 资源都允许移动操作。

可以在一个操作中移动多少资源?

尽可能将大型移动拆分为不同的移动操作。 在一次操作中有 800 多项资源时,资源管理器会立即返回错误。 但是,移动少于 800 个资源也可能因超时而失败。

资源未处于“成功”状态错误的意思是什么?

当你收到一条错误消息,指示无法移动资源,因为它未处于“成功”状态时,这可能是因为依赖资源正在阻止移动。 通常,错误代码为 MoveCannotProceedWithResourcesNotInSucceededState

如果源或目标资源组包含虚拟网络,则移动期间会检查依赖于该虚拟网络的所有资源的状态。 此检查包括直接或间接依赖网络的资源。 如果任何资源未处于成功状态,则会阻止移动。 例如,如果虚拟机使用未报告成功状态的虚拟网络,则会阻止移动。 即使虚拟机不是要移动的资源之一,也会阻止移动。 即使虚拟机不在源或目标资源组中,也会阻止移动。

若要解决此问题,请将资源移动到没有虚拟网络的资源组,或者联系支持人员

是否可以将资源组移动到其他订阅?

否,你无法将资源组移动到新订阅。 但是,你可以将资源组中的所有资源移到另一个订阅中的资源组。 标记、角色分配和策略等设置不会自动从原始资源组传输到目标资源组。 你需要手动将这些设置应用到新的资源组。

后续步骤

若要验证哪些 Azure 资源支持移动操作,请参阅移动资源的操作支持