亚马逊AWS官方博客

Amazon CloudFront部署小指南(二十四):将CloudFront “多域名”改造为”多租户”架构

摘要:通过多租户架构简化 CloudFront 配置管理


一、简介

在使用 Amazon CloudFront 时,许多用户会采用”多域名”架构—— 在一个 Distribution 下关联多个域名,以实现配置共享,包括源站配置、安全配置、CDN配置和网络配置。这种方式虽然简化了管理,但也带来了一些显著的问题:

1.1 多域名架构的局限性

  1. 无法实现基于单个域名的缓存操作:当需要刷新某个特定域名的缓存时,只能刷新整个 Distribution 的缓存,影响所有域名
  2. 无法实现基于单个域名的安全策略:所有域名共享同一套 WAF 规则,无法为不同域名定制安全策略
  3. 无法实现基于单个域名的配置管理:源站、CDN 和网络配置都是共享的,无法针对单个域名进行独立调整

1.2 使用CloudFront SaaS Manager 特性改造”多租户”架构

我们将利用CloudFront SAAS manager 特性将现有的”多域名”架构改造为”多租户”架构,产生多租户架构下的高级应用场景。

关于 CloudFront SaaS Manager 的详细介绍和基础部署步骤,请参考我们之前发布的博客文章:《Amazon CloudFront SaaS Manager 介绍》https://aws.amazon.com/cn/blogs/china/introducing-cloudfront-saas-manager/ ,该文章详细介绍了: – CloudFront SaaS Manager 的核心概念和架构 – 租户(Tenant)、分配(Distribution)、连接组(Connection Group)的基础配置 – 多租户架构的初始部署流程 – 基本的管理和监控方法

1.3 多租户架构的优势

  • 租户(Tenant)与域名一对一映射:每个租户直接对应一个域名
  • 独立的安全策略:可以为每个租户设置独立的 WAF 规则集(WebACL)
  • 独立的缓存管理:可以针对单个租户进行缓存刷新操作
  • 动态配置关联:租户可以动态关联不同的 Distribution,实现源站-CDN 配置的无缝迁移(缓存不丢失)
  • 网络配置解耦:通过 Connection Group,租户可以动态关联不同的网络配置,实现如 Unicast 到 Anycast 的无缝迁移

1.4 为什么不用”一域名一Distribution”?

另一种方案是为每个域名创建单独的 Distribution,虽然也能实现上述需求,但会线性增加管理复杂度。因为在实际场景中,源站-CDN-网络配置往往是可以共享的,使用多租户架构可以在保持配置共享的同时,获得独立管理的灵活性。

二、核心概念解析

在深入了解架构对比之前,先理解 CloudFront SaaS Manager 的三个核心概念:

2.1 Tenant(租户)

租户是多租户架构的核心单元,与域名一对一映射。每个租户可以: – 绑定一个独立的域名 – 关联独立的 WAF 规则集(WebACL) – 执行独立的缓存刷新操作 – 动态切换关联的 Distribution 和 Connection Group

2.2 Distribution(分配)

Distribution 在多租户架构中作为配置模板使用,定义了: – 源站配置(Origin) – CDN 配置(缓存策略、压缩、HTTP 版本等) – 缓存行为(Cache Behavior) – 可以被多个租户共享,实现配置复用

2.3 Connection Group(连接组)

Connection Group 定义网络层配置,包括: – 网络类型(Unicast 或 Anycast) – 网络优化策略 – 可以被多个租户共享 – 支持动态切换,实现网络配置的无缝迁移

这三个概念通过动态关联的方式组合在一起,形成了灵活且强大的多租户架构。租户可以随时切换关联的 Distribution 或 Connection Group,实现零停机的配置迁移。

三、架构对比

3.1 传统多域名架构

[图1]

问题:所有域名共享配置,无法独立管理

3.2 多租户架构(SaaS Manager)

[图2]

优势: – ✅ 租户独立管理 – ✅ 配置模板共享 – ✅ 动态关联切换 – ✅ 零停机迁移

四、多租户架构下的新能力

4.1 场景一:单独域名关联 WAF

在多租户架构下,每个租户可以关联独立的 WAF WebACL,实现精细化的安全策略。

[图3.CloudFront 租户 WAF 配置]

4.1.1 使用场景

  • 不同业务线的安全需求:电商域名需要防爬虫,API 域名需要防 DDoS
  • 合规要求:不同地区的域名需要遵守不同的安全合规标准
  • 灵活的安全策略:可以为高风险域名配置更严格的规则

4.1.2 架构图

[图4]

4.2 场景二:单独域名刷新缓存

传统多域名架构下,刷新缓存会影响所有域名。多租户架构支持针对单个租户进行缓存刷新。

[图5.CloudFront 租户缓存刷新]

4.2.1 使用场景

  • 独立的内容更新:某个域名更新了内容,不影响其他域名的缓存
  • 紧急修复:快速刷新有问题的域名缓存,不影响其他正常服务
  • 成本优化:只刷新需要的缓存,减少不必要的回源流量

4.2.2 对比图

传统架构:刷新影响所有域名

[图6]

多租户架构:精准刷新单个租户

[图7]

4.3 场景三:单独域名迁移配置

这是多租户架构最强大的能力:零停机、零缓存丢失的配置迁移。

[图8.CloudFront 租户关联切换]

在CloudFront SAAS manager中, 每个租户的缓存是独立于Distribution存在的,所以在切换 Distribution 过程前后,缓存会跟随Tenant自动保留。

4.3.1 使用场景

  • 源站切换:从源站 A 迁移到源站 B
  • 配置优化:测试新的 CDN 配置(缓存策略、压缩设置等)
  • 网络升级:从 Unicast 迁移到 Anycast
  • 灰度发布:新功能先在部分域名上测试

4.3.2 迁移优势对比

特性 传统架构 多租户架构
配置切换时间 15-30 分钟 即时生效
缓存丢失 ✗ 全部丢失 ✓ 完全保留
回滚能力 ✗ 困难 ✓ 即时回滚
影响范围 所有域名 单个租户
灰度测试 ✗ 不支持 ✓ 支持

五、改造和迁移步骤

5.1 迁移流程图

[图9]

5.2 步骤 1:创建多租户分配/连接组和租户域名

5.2.1 创建 Connection Group(连接组)

Connection Group 用于定义网络配置,重要提示:确保 Connection Group 的网络配置与待迁移的标准 Distribution 一致(如 Anycast 和 IPv6 设置),避免迁移过程中的网络行为变化。

# 查看现有标准 Distribution 的网络配置
aws cloudfront get-distribution --id <OLD_DISTRIBUTION_ID>

# 创建启用 IPv6 的连接组(默认使用 Anycast)
aws cloudfront create-connection-group \
  --name "anycast-ipv6-connection-group" \
  --ipv6-enabled \
  --enabled

# 如果需要指定特定的 Anycast IP 列表
aws cloudfront create-connection-group \
  --name "anycast-with-static-ip" \
  --ipv6-enabled \
  --enabled \
  --anycast-ip-list-id "<ANYCAST_IP_LIST_ID>"

5.2.2 创建多租户 Distribution

创建作为配置模板的 Distribution,可以根据不同的源站配置创建多个:

# 创建 Distribution 模板 A(例如:主源站配置)
aws cloudfront create-distribution \
  --distribution-config file://distribution-template-a.json \
  --tags Items=[{Key=Type,Value=SaaSTemplate},{Key=Name,Value=TemplateA}]

# 创建 Distribution 模板 B(例如:备用源站配置)
aws cloudfront create-distribution \
  --distribution-config file://distribution-template-b.json \
  --tags Items=[{Key=Type,Value=SaaSTemplate},{Key=Name,Value=TemplateB}]

5.2.3 创建租户(Tenant)- 使用占位符域名

重要:由于目标域名(如 domain1.example.com)已经存在于标准 Distribution 上,直接使用会报域名重复错误。因此需要先使用占位符域名创建租户。

# 创建租户配置文件 tenant1.json
cat > tenant1.json << 'EOF'
{
  "DistributionId": "<MULTI_TENANT_DISTRIBUTION_ID>",
  "Name": "tenant-domain1",
  "Domains": [
    {
      "Domain": "domain1-placeholder.example.com"
    }
  ],
  "ConnectionGroupId": "<CONNECTION_GROUP_ID>",
  "Customizations": {
    "WebAcl": {
      "Action": "override",
      "Arn": "arn:aws:wafv2:us-east-1:<AWS_ACCOUNT_ID>:global/webacl/tenant1-acl/<WAF_ACL_ID_1>"
    }
  },
  "Enabled": true
}
EOF

# 创建租户 1
aws cloudfront create-distribution-tenant \
  --cli-input-json file://tenant1.json

# 创建租户 2 配置文件
cat > tenant2.json << 'EOF'
{
  "DistributionId": "<MULTI_TENANT_DISTRIBUTION_ID>",
  "Name": "tenant-domain2",
  "Domains": [ {
      "Domain": "domain2-placeholder.example.com"}
  ],
  "ConnectionGroupId": "<CONNECTION_GROUP_ID>",
  "Customizations": {
    "WebAcl": {
      "Action": "override",
      "Arn": "arn:aws:wafv2:us-east-1:<AWS_ACCOUNT_ID>:global/webacl/tenant2-acl/<WAF_ACL_ID_2>"
    }
  },
  "Enabled": true
}
EOF

# 创建租户 2
aws cloudfront create-distribution-tenant \
  --cli-input-json file://tenant2.json

# 保存返回的租户 ID(格式为 dt_xxx)供后续使用
# 输出示例:
# {"DistributionTenant": { "Id": "<TENANT1_ID>",... }}

5.2.4 测试占位符域名

在迁移前,使用占位符域名进行功能测试:

# 获取 Connection Group 的路由端点(DNS 名称)
aws cloudfront get-connection-group \
  --id "<CONNECTION_GROUP_ID>" \
  --query 'ConnectionGroup.RoutingEndpoint' --output text
# 输出示例:<ROUTING_ENDPOINT>

# 配置 DNS 记录指向 Connection Group 的路由端点
# domain1-placeholder.example.com -> <ROUTING_ENDPOINT>

# 测试访问
curl -v https://domain1-placeholder.example.com/test-path

# 测试缓存刷新(使用 Distribution ID)
aws cloudfront create-invalidation \
  --distribution-id "<MULTI_TENANT_DISTRIBUTION_ID>" \
  --paths "/*"

# 测试 WAF 规则
curl -H "User-Agent: BadBot" https://domain1-placeholder.example.com/

5.3 步骤 2:域名迁移 — 从标准分配到多租户分配

5.3.1 修改标准 Distribution 的备用域名为通配符

将标准 Distribution 上的具体域名改为通配符域名(*.example.com),这样可以保持 domain1.example.com 不中断服务(因为通配符域名会继续匹配)。

# 获取当前标准 Distribution 配置
aws cloudfront get-distribution-config \
  --id <OLD_DISTRIBUTION_ID> \
  --output json > old-dist-config.json

# 编辑配置文件,将 Aliases 中的 "domain1.example.com" 改为 "*.example.com"
# 原配置:
# "Aliases": { "Quantity": 3, "Items": ["domain1.example.com", "domain2.example.com", "domain3.example.com"] }

# 新配置:
# "Aliases": {"Quantity": 1, "Items": ["*.example.com"] }

# 更新标准 Distribution
aws cloudfront update-distribution \
  --id <OLD_DISTRIBUTION_ID> \
  --distribution-config file://old-dist-config-updated.json \
  --if-match <ETAG_VALUE>

# 等待部署完成(约 15-30 分钟)
aws cloudfront wait distribution-deployed --id <OLD_DISTRIBUTION_ID>

说明:此时 domain1.example.com 仍然可以正常访问,因为通配符 *.example.com 会匹配该域名。

5.3.2 更新租户域名为正式域名

更新租户使用正式域名。这时虽然DNS没有变更,但CloudFront共享底层网络的特性会保证业务不中断:

# 方法一:使用命令行参数(简单场景)
# 获取租户 1 的 ETag
ETAG1=$(aws cloudfront get-distribution-tenant \
  --id "<TENANT1_ID>" \
  --query 'ETag' --output text)

# 更新租户 1 的域名
aws cloudfront update-distribution-tenant \
  --id "<TENANT1_ID>" \
  --if-match "$ETAG1" \
  --domains Domain="domain1.example.com"

# 方法二:使用 JSON 文件(推荐用于生产环境)
# 获取当前配置
aws cloudfront get-distribution-tenant \
  --id "<TENANT1_ID>" \
  > tenant1-current.json

# 提取 ETag
ETAG=$(jq -r '.ETag' tenant1-current.json)

# 创建更新配置文件
cat > update-tenant1-domain.json << EOF
{
  "Id": "<TENANT1_ID>",
  "IfMatch": "$ETAG",
  "Domains": [  {"Domain": "domain1.example.com } ]
}
EOF

# 执行更新
aws cloudfront update-distribution-tenant \
  --cli-input-json file://update-tenant1-domain.json

# 验证租户配置
aws cloudfront get-distribution-tenant \
  --id "<TENANT1_ID>"

5.4 更新 DNS 记录

将域名的 CNAME 记录从标准 Distribution 切换到多租户 Distribution 的 Connection Group 路由端点:

# 获取 Connection Group 的路由端点
ROUTING_ENDPOINT=$(aws cloudfront get-connection-group \
  --id "<CONNECTION_GROUP_ID>" \
  --query 'ConnectionGroup.RoutingEndpoint' --output text)

echo "路由端点: $ROUTING_ENDPOINT"
# 输出示例:<ROUTING_ENDPOINT>

# 更新 DNS 记录(以 Route 53 为例)
aws route53 change-resource-record-sets \
  --hosted-zone-id <HOSTED_ZONE_ID> \
  --change-batch '{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "domain1.example.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "'"$ROUTING_ENDPOINT"'"}]
      }}]}'

5.5 验证迁移结果

# 验证 DNS 解析
dig domain1.example.com CNAME

# 验证 HTTPS 证书
curl -v https://domain1.example.com/ 2>&1 | grep "subject:"

# 验证缓存功能
curl -I https://domain1.example.com/test-path | grep "X-Cache"

# 验证 WAF 规则
aws wafv2 get-web-acl-for-resource \
  --resource-arn "arn:aws:cloudfront::<AWS_ACCOUNT_ID>:distribution/<MULTI_TENANT_DISTRIBUTION_ID>"

# 监控 Distribution 错误率
aws cloudwatch get-metric-statistics \
  --namespace AWS/CloudFront \
  --metric-name 4xxErrorRate \
  --dimensions Name=DistributionId,Value=<MULTI_TENANT_DISTRIBUTION_ID> \
  --start-time 2026-02-11T00:00:00Z \
  --end-time 2026-02-11T23:59:59Z \
  --period 300 \
  --statistics Average

5.6 迁移注意事项

  1. 零业务中断:整个改造迁移步骤不会引发业务访问的中断
  2. 证书准备:确保多租户 Distribution 的 SSL 证书包含所有待迁移的域名(如使用通配符证书)
  3. 监控告警:设置 CloudWatch 告警监控错误率和延迟
  4. 回滚准备:保留标准 Distribution 配置,必要时可快速回滚
  5. 分批迁移:建议先迁移低流量域名,验证无误后再迁移核心域名

六、总结

CloudFront 多租户架构通过 SaaS Manager 实现了域名和配置的解耦,在保持配置共享优势的同时,提供了:

  • ✅ 独立管理能力:每个域名可以独立配置 WAF、刷新缓存
  • ✅ 灵活的配置切换:零停机、零缓存丢失的配置迁移
  • ✅ 降低管理复杂度:配置模板化,避免重复配置
  • ✅ 支持灰度发布:通过实验功能安全地测试新配置

相比传统的”一域名一 Distribution”方案,多租户架构在管理效率和灵活性上都有显著提升,是大规模 CloudFront 部署的推荐架构。

➡️ 下一步行动:

相关产品:

相关文章:

*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。

本篇作者

叶明

亚马逊云科技边缘产品架构师,负责 CloudFront 和 Global Accelerator 服务在中国和全球的市场拓展,专注于互联网用户访问云上服务的感受的优化以及数据洞察。在互联网基础设施领域有丰富的实践经验。


AWS 架构师中心:云端创新的引领者

探索 AWS 架构师中心,获取经实战验证的最佳实践与架构指南,助您高效构建安全、可靠的云上应用