在本系列的上一篇文章中,我们解释了Terraform中的远程状态(Remote State)概念的基础知识,以及如何在多租户(Multi-Tenancy)环境中利用它来继承信息。现在,我们将通过一个具体的架构示例对此进行说明。
引言
一个有效的多租户架构应遵循企业的组织结构,同时考虑云平台的最佳实践。现代云平台提供了多种方式来映射层次化的组织结构 - 无论是Compartments(OCI)、Organizations和Accounts(AWS)、资源组(Azure)还是项目和文件夹(GCP)。
架构概念介绍

在我们的架构示例中,我们将一个“客户的全球数据中心”视为最高的组织单元。在此单元内存在不同的区域:
全球系统和服务: 包括IAM、监控、计费和其他中央服务。
区域数据中心: 面向不同需求的地理分布式基础架构。
组织性分区: 例如按部门、安全区域或其他标准划分。
此模型的特别之处在于:每个组织单元代表一个独立的逻辑区域,具有明确的责任范围。这些单元构成了不同租户或组织单元之间的自然边界,同时提供了权限和配置继承的框架。
作为自然多租户模型的层次化组织结构
云基础架构的层次化结构为多租户场景提供了多个优势:
层次化组织: 单元可以嵌套,类似于文件夹结构。
策略继承: 权限可以从较高级别继承到较低级别。
资源管理: 可以为每个组织单元定义配额限制。
成本核算: 计费和测量在组织单元级别进行。
举例来说:一家公司可以为每个业务部门设置一个顶层单元。在这些单元内,可能存在生产、开发和测试等进一步的子单元。最底层可能是与具体项目相关的单元。
这种层次结构不仅反映了组织结构,还简化了对访问权限和资源的管理。例如,管理员可以获得对特定部门单元的访问权限,而无需访问其他部门的资源。
不同的分区层次
我们可以沿着不同的维度来划分基础架构:
技术性分区: 例如“站点A区域数据中心”,其中包含不同的技术区(DC1、DC2、DC3、DC4)。
组织性分区: 例如“站点B区域数据中心”,其中包含不同的部门(部门1、部门2等)。
安全区域: 例如“站点n区域数据中心”,其中包括高度安全(High Security)、中等(Medium)、低级(Low)和公共(Public)区域。
价值流: 跨越其他结构的业务流程。
这些不同的分区维度可能会重叠和互补。挑战在于如何在Terraform中清晰地表示它们,并同时实现它们之间的信息流。
特别重要的是通过远程状态(Remote State)继承数据。我们看到信息如何从较高层(全球数据中心)传递到较低层(区域数据中心及其子单元)。这正是我们在上一部分中讨论的远程状态模式的体现。
使用Terraform模块的实际实现
在Terraform中实现此类架构需要采用结构化的模块方法。我们为每个层次结构级别创建专用的Terraform项目。
提示: 远程状态数据源的具体配置根据所使用的后端而有所不同。对于常见选项(如S3、GCS或Consul),需要进行相应的调整。
1. 全局基础架构的Root模块:

# 1. 全局基础架构 (Root级别)
module "global_datacenter" {
source = "./modules/organization"
name = "global-datacenter-customer"
description = "客户的全球数据中心"
parent_id = var.root_organization_id
}
module "global_network" {
source = "./modules/network"
organization_id = module.global_datacenter.id
cidr_block = "10.0.0.0/16"
name = "global-network"
}
# 全局必要的系统和服务
module "global_services" {
source = "./modules/organization"
name = "global-services"
description = "客户所需的全局系统和服务"
parent_id = module.global_datacenter.id
}
# IAM、监控、计费服务模块将在此处实现...
output "global_datacenter_id" {
value = module.global_datacenter.id
}
output "global_network_id" {
value = module.global_network.id
}
output "global_services_id" {
value = module.global_services.id
}
2. 按技术分区的区域基础架构:

# 2. 位置A的区域数据中心 (多个数据中心)
data "terraform_remote_state" "global" {
backend = "remote"
config = {
organization = "my-org"
workspaces = {
name = "global-infrastructure"
}
}
}
module "location_a" {
source = "./modules/organization"
name = "location-a-regionales-datacenter"
description = "位置A的区域数据中心"
parent_id = data.terraform_remote_state.global.outputs.global_datacenter_id
}
# 配置4个数据中心作为子单元
module "dc1" {
source = "./modules/organization"
name = "dc1"
description = "数据中心 1"
parent_id = module.location_a.id
}
module "dc2" {
source = "./modules/organization"
name = "dc2"
description = "数据中心 2"
parent_id = module.location_a.id
}
module "dc3" {
source = "./modules/organization"
name = "dc3"
description = "数据中心 3"
parent_id = module.location_a.id
}
module "dc4" {
source = "./modules/organization"
name = "dc4"
description = "数据中心 4"
parent_id = module.location_a.id
}
# 为位置A的全局网络配置子网
module "subnet_dc1" {
source = "./modules/subnet"
organization_id = module.dc1.id
network_id = data.terraform_remote_state.global.outputs.global_network_id
cidr_block = "10.0.1.0/24"
name = "subnet-dc1"
}
# 更多的子网配置 (DC2、DC3、DC4...)
# 在其他Terraform项目中使用的输出
output "location_a_id" {
value = module.location_a.id
}
output "dc1_id" {
value = module.dc1.id
}
output "subnet_dc1_id" {
value = module.subnet_dc1.id
}
# 其他输出项
3. 按组织分区的区域基础架构:

# 3. 位置B的区域数据中心 (组织架构)
data "terraform_remote_state" "global" {
backend = "remote"
config = {
organization = "my-org"
workspaces = {
name = "global-infrastructure"
}
}
}
module "location_b" {
source = "./modules/organization"
name = "location-b-regional-datacenter"
description = "位置B的区域数据中心"
parent_id = data.terraform_remote_state.global.outputs.global_datacenter_id
}
# 组织部门
module "department_1" {
source = "./modules/organization"
name = "department-1"
description = "部门 1"
parent_id = module.location_b.id
}
module "department_2" {
source = "./modules/organization"
name = "department-2"
description = "部门 2"
parent_id = module.location_b.id
}
module "department_3" {
source = "./modules/organization"
name = "department-3"
description = "部门 3"
parent_id = module.location_b.id
}
module "department_4" {
source = "./modules/organization"
name = "department-4"
description = "部门 4"
parent_id = module.location_b.id
}
# 部门专属子网
module "subnet_department_1" {
source = "./modules/subnet"
organization_id = module.department_1.id
network_id = data.terraform_remote_state.global.outputs.global_network_id
cidr_block = "10.0.10.0/24"
name = "subnet-department-1"
}
# 在其他Terraform项目中使用的输出
output "location_b_id" {
value = module.location_b.id
}
output "department_1_id" {
value = module.department_1.id
}
output "subnet_department_1_id" {
value = module.subnet_department_1.id
}
4. 按安全分区的区域基础架构:

# 4. 位置n的区域数据中心 (安全区域)
data "terraform_remote_state" "global" {
backend = "remote"
config = {
organization = "my-org"
workspaces = {
name = "global-infrastructure"
}
}
}
module "location_n" {
source = "./modules/organization"
name = "location-n-regional-datacenter"
description = "位置n的区域数据中心"
parent_id = data.terraform_remote_state.global.outputs.global_datacenter_id
}
# 安全区域作为子单元
module "high" {
source = "./modules/organization"
name = "high"
description = "高级安全区域"
parent_id = module.location_n.id
}
module "med" {
source = "./modules/organization"
name = "med"
description = "中级安全区域"
parent_id = module.location_n.id
}
module "low" {
source = "./modules/organization"
name = "low"
description = "低级安全区域"
parent_id = module.location_n.id
}
module "pub" {
source = "./modules/organization"
name = "pub"
description = "公共区域"
parent_id = module.location_n.id
}
# 安全区域特定的子网
module "subnet_high" {
source = "./modules/subnet"
organization_id = module.high.id
network_id = data.terraform_remote_state.global.outputs.global_network_id
cidr_block = "10.0.20.0/24"
name = "subnet-high"
prohibit_public_ip = true
}
# 其他安全资源,如Security Lists和Network Security Groups...
# 输出
output "location_n_id" {
value = module.location_n.id
}
output "high_security_id" {
value = module.high.id
}
output "subnet_high_id" {
value = module.subnet_high.id
}
5. 部门或团队特定的基础架构:

# 5. 示例:部门中的资源使用远程状态信息
data "terraform_remote_state" "standort_b" {
backend = "remote"
config = {
organization = "my-org"
workspaces = {
name = "regional-location-b"
}
}
}
module "vm_instances" {
source = "./modules/compute"
instances = {
app_server_department_1 = {
organization_id = data.terraform_remote_state.location_b.outputs.department_1_id
subnet_id = data.terraform_remote_state.location_b.outputs.subnet_department_1_id
size = "medium"
image = var.app_image_id
}
# 其他虚拟机实例 ...
}
}
动态模块配置以实现灵活的部署模式
为了进一步提高灵活性,我们还可以使用动态配置。这在我们需要管理大量相似资源时特别有用:
module "regional_datacenters" {
source = "./modules/regional_datacenter"
for_each = var.datacenter_configs
name = each.key
description = each.value["description"]
parent_id = data.terraform_remote_state.global.outputs.global_datacenter_id
network_cidr = each.value["network_cidr"]
security_level = each.value["security_level"]
subunits = each.value["subunits"]
}
# 使用示例,如何从根模块调用此模块
# datacenter_configs = {
# "europe-west" = {
# description = "欧洲西部数据中心"
# network_cidr = "10.1.0.0/16"
# security_level = "high"
# subunits = ["prod", "staging", "dev", "test"]
# },
# "us-east" = {
# description = "美国东海岸数据中心"
# network_cidr = "10.2.0.0/16"
# security_level = "medium"
# subunits = ["prod", "dev"]
# }
# }
模块化结构的优势
这种模块化结构使我们能够将组织的逻辑层次结构转换为独立的Terraform项目,同时确保这些项目之间的信息交换:
明确的责任划分: 每个团队管理其自己的Terraform代码和状态。
自动的信息继承: 管理全局基础架构的团队可以进行更改,而无需区域或部门级别的团队调整其代码。
独立的部署: 某个区域出现的错误不会自动影响其他区域。
可扩展性: 新的组织单元可以轻松添加,而无需更改现有结构。
一致的治理: 通过输出的继承,确保所有层级的一致配置。
完整的多租户设置示例
以下是一个示例,展示如何在实际项目中结合这些模式:
module "tenant_environments" {
source = "./modules/tenant_environment"
for_each = {
for tenant in var.tenants : tenant.name => tenant
}
name = each.key
parent_id = module.tenant_root_organization.id
environments = each.value["environments"]
network_cidr = each.value["network_cidr"]
security_policy = each.value["security_policy"]
}
# tenant_environments 可用于不同的客户、
# 业务部门或项目。
#
# 示例:
# tenants = [
# {
# name = "finance-department"
# environments = ["prod", "dev", "test"]
# network_cidr = "10.10.0.0/16"
# security_policy = "high"
# },
# {
# name = "marketing-department"
# environments = ["prod", "staging"]
# network_cidr = "10.20.0.0/16"
# security_policy = "medium"
# }
# ]
借助这种结构化的方法,我们能够以技术上稳健且组织上合理的方式管理复杂的多租户环境。通过明确的责任划分,结合远程状态(Remote State)的精准信息继承,使我们即便在大型、分布式团队中也能高效地使用Terraform。
远程状态(Remote-State)信息的安全性考量
尽管远程状态(Remote States)非常有用,但它们可能包含潜在的敏感信息。尤其是在多租户(Multi-Tenancy)环境中,保护这些信息至关重要。
为确保仅授权的团队能够访问远程状态的输出,您应采取以下措施:
- 访问控制限制: 使用您的后端的访问控制机制(例如S3的IAM策略、Consul的ACL,或Terraform Cloud/Enterprise中的基于角色的访问控制)。
- 最小化输出: 仅将绝对必要的信息定义为输出。每个额外的输出属性都会增加敏感数据泄露的风险。
- 避免不必要的输出: 具有安全关键值(例如密码、私钥)的输出应尽可能避免作为输出提供,而应通过机密管理服务(如HashiCorp Vault或Secrets Manager)来管理。
- 信息汇总: 与其单独提供数据库密码、API密钥或其他敏感详细信息作为输出,不如优先使用结构化输出,仅聚合相关参数。
- 使用代理状态文件(Proxy-Statefiles):过滤远程状态的输出,仅包含与特定租户相关的信息,并将其作为新的状态提供。该租户仅允许访问该代理状态。
远程状态依赖的错误处理
在多租户架构中使用远程状态会带来特殊的错误处理挑战。错误来源可能包括不可用的后端、输出不一致或意外更改,这些都可能导致严重问题。为了尽量减少这些风险,您应采取以下措施:
- 可用性检查: 在Terraform的terraform_remote_state块中结合查询结构(如lookup())使用,以减少因缺失输出引发的错误。
- 输出正确性检查: 在模块和CI/CD流水线中添加测试,确保远程状态输出始终包含预期的结构和内容。
- 回退机制: 如果远程状态暂时无法访问,可以使用本地缓存的值(例如通过环境变量)作为临时解决方案。
以下是一个带有错误处理的稳健远程状态查询示例:
data "terraform_remote_state" "network" {
backend = "remote"
config = {
organization = "my-org"
workspaces = {
name = "global-infrastructure"
}
}
}
locals {
private_subnet_id = lookup(data.terraform_remote_state.network.outputs.subnets, "private", null)
}
resource "example_vm" "app_server" {
subnet_id = local.private_subnet_id != null ? local.private_subnet_id : var.default_subnet_id
}
在下一部分中,我们将探讨远程后端(Remote Backends),并了解如何以最佳方式对远程状态进行层次化组织。




