如何将 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。
可行路径主要有两种:
- 由 CSP 合作伙伴联系 Microsoft 支持,将 subscription 关联到目标 tenant,或完成受支持的订阅转移,再评估是否能够移动资源。
- 如果合作伙伴无法完成上述操作,则在 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,应直接采用数据迁移方案。
推荐的整体迁移顺序
可以按照“新建环境、全量复制、增量同步、短暂停写、切换”的顺序实施:
- 盘点源端资源及其依赖。
- 在 PAYG subscription 中创建目标资源。
- 在目标 tenant 中建立身份和权限。
- 执行第一次全量数据迁移。
- 业务继续运行时同步增量数据。
- 安排维护窗口,停止或限制源端写入。
- 完成最后一次同步并校验数据。
- 修改连接字符串、DNS、密钥和应用配置。
- 观察新环境的运行情况,确认稳定后再停用 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';
切换与回退
切换后不要立即删除源资源。可以按照以下流程操作:
- 降低 DNS TTL,或提前准备配置中心变更。
- 暂停对源 SQL Database 和 Storage Account 的写入。
- 完成最后一次数据库及存储增量同步。
- 校验数据完整性。
- 更新 SQL 连接字符串和 Storage endpoint。
- 更新 Key Vault secret、Managed Identity 和 RBAC。
- 恢复业务流量。
- 监控错误率、延迟、连接失败和数据写入情况。
- 将源端保留为只读状态一段时间,确认不需要回退后再清理。
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 转移。如果不能,就按照“重新部署基础设施并迁移数据”的方式规划整个项目。
需要迁移大量数据库和存储数据时,应先选择少量非关键资源完成一次全流程演练,验证迁移、切换和回退步骤后,再开始批量迁移生产资源。
备注:内容仅供参考。