PAYATHON 2026

如何将 SQL Azure servers 和 Storage Accounts 迁出 CSP subscription

架构老王

结论

如果两个 subscription 分属不同的 Microsoft Entra ID(原 Azure AD)tenant,而 CSP subscription 又无法执行 Change Directory 或 subscription transfer,就不能通过 Azure Resource Manager 的资源移动功能,将 SQL logical servers、elastic pools、databases 和 Storage Accounts 原样移至 PAYG subscription。

可行路径主要有两种:

  1. 由 CSP 合作伙伴联系 Microsoft 支持,将 subscription 关联到目标 tenant,或完成受支持的订阅转移,再评估是否能够移动资源。
  2. 如果合作伙伴无法完成上述操作,则在 PAYG subscription 中重新创建资源,并迁移数据。通常,这种方式的过程更可控,风险也更低。

需要区分“合作伙伴之间的 CSP 转移”“billing ownership 转移”和“更换 tenant”。前两种操作不一定会改变 subscription 所属的 tenant,因此未必能解决跨 tenant 移动资源的问题。

为什么不能直接移动

Azure Resource Manager 要求参与跨 subscription move 的源 subscription 和目标 subscription 位于同一个 tenant。这不仅涉及计费关系,还涉及以下配置:

  • Azure RBAC 主体和角色分配
  • Managed Identity
  • Microsoft Entra 管理员配置
  • Key Vault、客户管理密钥和访问策略
  • Private Endpoint、Private DNS Zone 和虚拟网络引用
  • Azure Policy、资源锁和服务主体
  • Marketplace 服务及第三方资源许可

不同 tenant 中的用户、组和服务主体,即使名称相同,Object ID 也不相同。资源中的数据或许可以复制,但相关身份、权限和依赖关系无法自动沿用。

account.windowsazure.com 是旧式账户管理入口。该页面出现 500 错误,并不表示可以绕过 tenant 限制迁移资源,也不适合继续作为主要迁移手段。

先确认 CSP 是否可以由后台处理

开始大规模复制数据前,应让 CSP 合作伙伴向 Microsoft 提交支持请求,并明确确认:

  • 能否将现有 subscription 重新关联到指定的 Microsoft Entra tenant
  • 能否将 CSP subscription 转换或转移到目标计费关系
  • 转移后 subscription ID 是否保持不变
  • 操作是否会改变 tenant,而不仅是更换 CSP partner 或 billing owner
  • SQL Database、Storage 和 Marketplace 资源是否存在转移限制
  • 操作是否会影响 Managed Identity、RBAC、Key Vault 或 Private Endpoint

如果支持人员确认可以更换 tenant,仍要提前导出 RBAC、身份和依赖配置。目录变更后,旧 tenant 中的角色分配通常无法继续使用,需要在新 tenant 中重新授权。

如果合作伙伴无法提供这种操作,就不必继续尝试 ARM move,应直接采用数据迁移方案。

推荐的整体迁移顺序

可以按照“新建环境、全量复制、增量同步、短暂停写、切换”的顺序实施:

  1. 盘点源端资源及其依赖。
  2. 在 PAYG subscription 中创建目标资源。
  3. 在目标 tenant 中建立身份和权限。
  4. 执行第一次全量数据迁移。
  5. 业务继续运行时同步增量数据。
  6. 安排维护窗口,停止或限制源端写入。
  7. 完成最后一次同步并校验数据。
  8. 修改连接字符串、DNS、密钥和应用配置。
  9. 观察新环境的运行情况,确认稳定后再停用 CSP 资源。

目标 Storage Account 和 SQL logical server 会使用新的资源 ID、主机名和访问密钥,因此这不是透明迁移,必须调整应用配置。

SQL Azure servers、pools 和 databases 的迁移

SQL logical server 和 elastic pool 属于管理层资源。无法跨 tenant 整体搬迁时,需要先在 PAYG subscription 中重新创建:

  • SQL logical server
  • elastic pools 及其容量配置
  • firewall rules
  • private endpoints 和 DNS 配置
  • failover groups
  • auditing、diagnostic settings 和告警
  • Microsoft Entra administrator
  • server identity 和 Key Vault 权限
  • database-level users、权限及其他安全对象

数据库的迁移方式应根据可接受的停机时间、数据库规模和功能依赖来选择。

方案一:Azure SQL Database 数据库复制

如果源端和目标端满足条件,可以使用数据库复制。跨 subscription 操作通常需要通过 T-SQL 发起,而不是依赖 Portal。

在目标 logical server 的 master 数据库中执行类似命令:

CREATE DATABASE [TargetDatabase]
AS COPY OF [source-server].[SourceDatabase];

复制完成后,可以将数据库加入提前创建好的 elastic pool:

ALTER DATABASE [TargetDatabase]
MODIFY (
    SERVICE_OBJECTIVE = ELASTIC_POOL (
        name = [TargetPool]
    )
);

复制前需要确认:

  • 发起复制的登录在源服务器和目标服务器上都有所需权限
  • 两端网络规则允许管理连接
  • 目标区域和服务层支持所需配置
  • 数据库大小未超过目标服务层限制
  • 数据库使用的功能在目标环境中可用
  • TDE、客户管理密钥和 Key Vault 权限已经配置
  • 跨 tenant 场景使用的身份验证方式受到支持

跨 tenant 的 Microsoft Entra 身份并非同一个安全主体。如果直接复制因身份或权限限制失败,不要反复尝试绕过控制面限制。此时应改用 SqlPackage、Azure Database Migration Service、事务复制或其他数据级迁移方式。

方案二:BACPAC 导出和导入

对于规模适中、可以接受较长迁移窗口的数据库,可以使用 SqlPackage。

导出:

SqlPackage \
  /Action:Export \
  /SourceServerName:"tcp:source-server.database.windows.net,1433" \
  /SourceDatabaseName:"SourceDatabase" \
  /SourceUser:"migration_user" \
  /SourcePassword:"<SOURCE_PASSWORD>" \
  /TargetFile:"SourceDatabase.bacpac"

导入:

SqlPackage \
  /Action:Import \
  /TargetServerName:"tcp:target-server.database.windows.net,1433" \
  /TargetDatabaseName:"TargetDatabase" \
  /TargetUser:"migration_user" \
  /TargetPassword:"<TARGET_PASSWORD>" \
  /SourceFile:"SourceDatabase.bacpac"

不要将密码直接写入长期保存的脚本、日志或流水线配置。应使用安全变量或密钥管理服务。

BACPAC 适合一次性逻辑迁移,不适合停机窗口很短的大型数据库或高写入数据库。如果迁移期间应用仍在持续写入,还需要处理数据一致性和最终增量同步。

方案三:低停机迁移

如果数据库较大,或业务只能接受很短的停机时间,可以评估:

  • Azure Database Migration Service
  • Azure SQL Data Sync
  • transactional replication
  • 应用层双写
  • 业务分批迁移

这些方案能否使用,取决于数据库类型、服务层、表结构和采用的 SQL 功能。例如,缺少合适主键的表可能不适用于某些增量同步方案。

切换前至少执行以下检查:

SELECT
    SUM(row_count) AS total_rows
FROM sys.dm_db_partition_stats
WHERE index_id IN (0, 1);

行数只能用于初步核对。对于重要业务数据,还要检查聚合结果、最大更新时间、关键表校验值和抽样记录。

Storage Accounts 的迁移

复制 Storage Account 中的数据,无法保留原有的资源 ID、endpoint、account key、RBAC 和网络配置。正确做法是在目标 subscription 中创建新账户,再分别迁移 Blob、Azure Files、Table 和 Queue 数据。

创建目标账户时,需要核对:

  • region 和 redundancy
  • performance tier
  • hierarchical namespace
  • access tier
  • minimum TLS version
  • public network access
  • firewall 和 private endpoints
  • soft delete、versioning 和 lifecycle rules
  • immutability policy 和 legal hold
  • encryption scope 和客户管理密钥
  • CORS、Event Grid 和 diagnostic settings

Blob 数据迁移

Blob 数据通常可以通过 AzCopy 进行服务端复制。下面的示例按容器迁移:

azcopy copy \
  "https://sourceaccount.blob.core.windows.net/source-container?<SOURCE_SAS>" \
  "https://targetaccount.blob.core.windows.net/target-container?<TARGET_SAS>" \
  --recursive=true

最终切换前,可以再次运行增量复制:

azcopy copy \
  "https://sourceaccount.blob.core.windows.net/source-container?<SOURCE_SAS>" \
  "https://targetaccount.blob.core.windows.net/target-container?<TARGET_SAS>" \
  --recursive=true \
  --overwrite=ifSourceNewer

如果 Blob 使用 snapshots、versions、tags、immutability policy、encryption scope 或 archive tier,应先验证迁移工具能否保留这些属性。只复制当前 Blob 内容,并不等于完整复制 Storage Account 的所有状态。

Azure Files

Azure Files 可以使用 AzCopy 或其他受支持的文件迁移工具,但以下内容需要单独确认:

  • SMB 属性和 ACL
  • 文件时间戳
  • snapshots
  • Active Directory 身份配置
  • share quota
  • Azure File Sync 配置

示例:

azcopy copy \
  "https://sourceaccount.file.core.windows.net/source-share?<SOURCE_SAS>" \
  "https://targetaccount.file.core.windows.net/target-share?<TARGET_SAS>" \
  --recursive=true \
  --preserve-smb-info=true

--preserve-smb-info 能否满足实际的权限保留要求,取决于认证方式和共享配置。正式迁移前,必须使用测试 share 验证。

Table 和 Queue

用于 Blob 或 Files 的迁移命令不会自动迁移 Table 和 Queue。

  • Azure Table Storage 可以使用 Azure Data Factory、Storage SDK 或专用迁移程序逐实体复制。
  • Queue Storage 通常需要由应用或迁移程序读取消息,再写入新队列。消息的可见性超时、TTL、出队次数和处理状态不一定能够原样保留。
  • 如果队列承载着正在处理的业务任务,建议先停止生产者,等待消费者排空队列,再切换至新账户。

简单的 Table Storage 迁移程序应采用分页读取和幂等 upsert:

await foreach (TableEntity entity in sourceClient.QueryAsync<TableEntity>())
{
    await targetClient.UpsertEntityAsync(
        entity,
        TableUpdateMode.Replace);
}

实际使用时,还需要加入重试、限速、错误记录、分区并发控制和最终校验。

身份和权限必须重新建立

跨 tenant 迁移时,以下配置无法仅靠复制数据完成迁移:

  • Azure RBAC role assignments
  • Microsoft Entra users、groups 和 service principals
  • Managed Identity
  • SQL Microsoft Entra users
  • Storage account keys 和 SAS
  • Key Vault access policies 或 RBAC
  • deployment credentials
  • application registrations
  • federated credentials

例如,数据库中可能保留了基于外部身份的用户定义,但新 tenant 中不存在对应的 Object ID。需要先在目标 tenant 中创建或确认新的主体,再重新授权。

可以使用以下查询检查数据库中的外部用户:

SELECT
    name,
    type_desc,
    authentication_type_desc
FROM sys.database_principals
WHERE authentication_type_desc = 'EXTERNAL';

切换与回退

切换后不要立即删除源资源。可以按照以下流程操作:

  1. 降低 DNS TTL,或提前准备配置中心变更。
  2. 暂停对源 SQL Database 和 Storage Account 的写入。
  3. 完成最后一次数据库及存储增量同步。
  4. 校验数据完整性。
  5. 更新 SQL 连接字符串和 Storage endpoint。
  6. 更新 Key Vault secret、Managed Identity 和 RBAC。
  7. 恢复业务流量。
  8. 监控错误率、延迟、连接失败和数据写入情况。
  9. 将源端保留为只读状态一段时间,确认不需要回退后再清理。

SQL logical server 和 Storage Account 的 endpoint 会发生变化,例如:

source-server.database.windows.net
target-server.database.windows.net

sourceaccount.blob.core.windows.net
targetaccount.blob.core.windows.net

如果代码中硬编码了 endpoint、资源 ID、subscription ID 或 tenant ID,也要同时修改。

最容易遗漏的事项

迁移清单至少还应包含:

  • SQL firewall rules、private link 和 DNS
  • elastic pool 容量及每库限制
  • SQL Agent 替代任务、Elastic Jobs 或 Automation
  • failover groups 和 geo-replication
  • auditing、Defender、diagnostic settings
  • Storage lifecycle management rules
  • Blob versioning、soft delete 和 snapshots
  • Event Grid subscriptions
  • Function、Logic App 和 Data Factory 连接
  • backup retention 与合规要求
  • Azure Policy、resource locks、tags 和 budgets
  • 目标 subscription 的配额和区域容量
  • 迁移期间产生的读取、写入、出口流量和临时资源费用

在这些限制下,跨 tenant 搬迁无法通过一个 Portal 操作完成。应先要求 CSP 合作伙伴和 Microsoft 明确答复,是否可以在后台完成 tenant 或 subscription 转移。如果不能,就按照“重新部署基础设施并迁移数据”的方式规划整个项目。

需要迁移大量数据库和存储数据时,应先选择少量非关键资源完成一次全流程演练,验证迁移、切换和回退步骤后,再开始批量迁移生产资源。

备注:内容仅供参考。