多Git仓库通过Terraform向同一API Gateway Dev阶段部署Lambda的问题
解决方案:多仓库共享API Gateway Stage的Terraform实践
针对多Git仓库部署Lambda到同一API Gateway dev 阶段的问题,核心思路是拆分资源管理边界,将共享的Stage资源独立管理,业务仓库仅负责自身API变更与Deployment生成,具体实现如下:
1. 独立管理API Gateway核心资源
创建单独的「API Gateway基础设施仓库」,专门负责管理rest_api和dev Stage资源,彻底避免多仓库重复创建/删除Stage:
# 定义API Gateway主资源 resource "aws_api_gateway_rest_api" "my_api" { name = "MySharedAPI" # 可添加描述、版本等自定义配置 } # 唯一的dev Stage资源 resource "aws_api_gateway_stage" "dev" { rest_api_id = aws_api_gateway_rest_api.my_api.id stage_name = "dev" deployment_id = var.latest_deployment_id # 接收外部传入的最新部署ID # 可选:配置访问日志、缓存、环境变量等 access_log_settings { destination_arn = aws_cloudwatch_log_group.api_access_log.arn format = "{\"requestId\":\"$context.requestId\",\"ip\":\"$context.identity.sourceIp\",\"method\":\"$context.httpMethod\",\"path\":\"$context.resourcePath\",\"status\":\"$context.status\"}" } } # 输出API基础信息,供业务仓库引用 output "api_rest_api_id" { value = aws_api_gateway_rest_api.my_api.id } output "root_resource_id" { value = aws_api_gateway_rest_api.my_api.root_resource_id } output "dev_stage_name" { value = aws_api_gateway_stage.dev.stage_name }
该仓库需配置Terraform远程状态(如S3+DynamoDB)存储状态,确保其他业务仓库可读取输出信息。
2. 业务仓库(Lambda)改造
每个业务仓库不再创建aws_api_gateway_stage资源,仅负责自身API路径、Lambda集成及对应Deployment的生成:
# 读取API基础设施仓库的远程状态 data "terraform_remote_state" "api_core" { backend = "s3" config = { bucket = "your-terraform-state-bucket" key = "path/to/api-infra/terraform.tfstate" region = "cn-north-1" # 替换为你的AWS区域 } } # 创建业务专属API路径 resource "aws_api_gateway_resource" "user_service" { rest_api_id = data.terraform_remote_state.api_core.outputs.api_rest_api_id parent_id = data.terraform_remote_state.api_core.outputs.root_resource_id path_part = "user" } # 配置Lambda集成 resource "aws_api_gateway_integration" "user_lambda" { rest_api_id = data.terraform_remote_state.api_core.outputs.api_rest_api_id resource_id = aws_api_gateway_resource.user_service.id http_method = aws_api_gateway_method.user_get.http_method type = "AWS_PROXY" uri = aws_lambda_function.user_handler.invoke_arn } # 生成当前业务变更的Deployment resource "aws_api_gateway_deployment" "user_deployment" { depends_on = [ aws_api_gateway_integration.user_lambda, aws_api_gateway_method.user_get ] rest_api_id = data.terraform_remote_state.api_core.outputs.api_rest_api_id # 触发器:每次API资源变更时强制生成新Deployment triggers = { resource_change = sha1(jsonencode([ aws_api_gateway_resource.user_service, aws_api_gateway_integration.user_lambda ])) } } # 输出当前Deployment ID,用于更新Stage output "deployment_id" { value = aws_api_gateway_deployment.user_deployment.id }
3. 更新Stage指向最新Deployment
业务仓库部署完成后,将输出的deployment_id传入基础设施仓库的var.latest_deployment_id变量,执行terraform apply即可更新dev Stage到最新的API快照:
- 手动方式:复制业务仓库输出的Deployment ID,修改基础设施仓库的变量值后执行部署。
- 自动化方式:通过CI/CD工具(如GitHub Actions),在业务仓库部署完成后自动触发基础设施仓库的部署,传递最新的Deployment ID作为变量。
替代方案:无仓库拆分的临时解决(不推荐)
如果暂时无法拆分仓库,可通过数据资源引用已存在的Stage,并用AWS CLI更新Deployment ID,但会导致Terraform状态与实际资源不一致,仅作为临时过渡方案:
# 引用已存在的dev Stage data "aws_api_gateway_stage" "dev" { rest_api_id = data.aws_api_gateway_rest_api.my_api.id stage_name = "dev" } # 创建Deployment后,用CLI更新Stage resource "null_resource" "update_stage" { depends_on = [aws_api_gateway_deployment.deployment] provisioner "local-exec" { command = <<EOT aws apigateway update-stage \ --rest-api-id ${data.aws_api_gateway_rest_api.my_api.id} \ --stage-name dev \ --patch-operations op=replace,path=/deploymentId,value=${aws_api_gateway_deployment.deployment.id} EOT } }
关键注意事项
- 权限控制:确保业务仓库的Terraform有读取基础设施仓库远程状态的权限,基础设施仓库有修改API Gateway Stage的权限。
- Deployment唯一性:每个业务仓库的Deployment必须设置
triggers,避免重复使用旧的Deployment快照。 - 状态一致性:优先采用仓库拆分方案,确保Terraform状态与实际云资源一致,避免手动操作带来的风险。
内容的提问来源于stack exchange,提问作者PackedUp
相关产品推荐
相关产品推荐

