Terraform 未部署 api 网关阶段

Posted

技术标签:

【中文标题】Terraform 未部署 api 网关阶段【英文标题】:Terraform not deploying api gateway stage 【发布时间】:2016-12-19 01:16:27 【问题描述】:

我一直在尝试使用 terraform 创建 API 网关端点。除了部署阶段的最后一部分之外,一切似乎都在工作。

运行 terraform apply 后,我进入控制台,发现部署没有发生。我需要手动单击 Deploy Api 才能使其正常工作。

这是 api 网关的 terraform 文件。

variable "region" 
variable "account_id" 

resource "aws_api_gateway_rest_api" "online_tax_test_client_report_endpoint_api" 
  name = "online_tax_test_client_report_endpoint_api"
  description = "The endpoint that test has to hit when new client reports are available."
  depends_on = ["aws_lambda_function.onlinetax_test_endpoint_lambda"]


resource "aws_api_gateway_resource" "test_client_report_resource" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  parent_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.root_resource_id"
  path_part = "test_client_report"


resource "aws_api_gateway_method" "test_client_report_method" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  resource_id = "$aws_api_gateway_resource.test_client_report_resource.id"
  http_method = "POST"
  authorization = "NONE"


resource "aws_api_gateway_integration" "test_client_report_resource_integration" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  resource_id = "$aws_api_gateway_resource.test_client_report_resource.id"
  http_method = "$aws_api_gateway_method.test_client_report_method.http_method"
  type = "AWS"
  integration_http_method = "$aws_api_gateway_method.test_client_report_method.http_method"
  uri = "arn:aws:apigateway:$var.region:lambda:path/2015-03-31/functions/$aws_lambda_function.onlinetax_test_endpoint_lambda.arn/invocations"
  request_templates = 
    "application/json" = "$file("$path.module/generic_request_mapping_template.vm")"
  


resource "aws_api_gateway_method_response" "200" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  resource_id = "$aws_api_gateway_resource.test_client_report_resource.id"
  http_method = "$aws_api_gateway_method.test_client_report_method.http_method"
  status_code = "200"


resource "aws_api_gateway_integration_response" "test_client_report_resource_integration_default_response" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  resource_id = "$aws_api_gateway_resource.test_client_report_resource.id"
  http_method = "$aws_api_gateway_method.test_client_report_method.http_method"
  status_code = "$aws_api_gateway_method_response.200.status_code"
  selection_pattern = ""
  depends_on = ["aws_api_gateway_integration.test_client_report_resource_integration"]


resource "aws_api_gateway_method_response" "500" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  resource_id = "$aws_api_gateway_resource.test_client_report_resource.id"
  http_method = "$aws_api_gateway_method.test_client_report_method.http_method"
  status_code = "500"


resource "aws_api_gateway_integration_response" "test_client_report_resource_integration_error_response" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  resource_id = "$aws_api_gateway_resource.test_client_report_resource.id"
  http_method = "$aws_api_gateway_method.test_client_report_method.http_method"
  status_code = "$aws_api_gateway_method_response.500.status_code"
  selection_pattern = ".*?Error.*"
  depends_on = ["aws_api_gateway_integration.test_client_report_resource_integration"]


resource "aws_lambda_permission" "allow_api_gateway" 
    statement_id = "AllowExecutionFromAPIGateway"
    action = "lambda:InvokeFunction"
    function_name = "$aws_lambda_function.onlinetax_test_endpoint_lambda.arn"
    principal = "apigateway.amazonaws.com"
    source_arn = "arn:aws:execute-api:$var.region:$var.account_id:$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id/*/$aws_api_gateway_integration.test_client_report_resource_integration.integration_http_method$aws_api_gateway_resource.test_client_report_resource.path"
    depends_on = ["aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api"]


#This is the part that doesn't seem to work. 
resource "aws_api_gateway_deployment" "qa5" 
  rest_api_id = "$aws_api_gateway_rest_api.online_tax_test_client_report_endpoint_api.id"
  stage_name = "qa5"
  depends_on = ["aws_api_gateway_method.test_client_report_method"]

编辑

添加图表:

    digraph 
        compound = "true"
        newrank = "true"
        subgraph "root" 
            "[root] module.lambda.aws_api_gateway_deployment.qa5" [label = "aws_api_gateway_deployment.qa5", shape = "box"]
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" [label = "aws_api_gateway_integration.sbr_client_report_resource_integration", shape = "box"]
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" [label = "aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response", shape = "box"]
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" [label = "aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response", shape = "box"]
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" [label = "aws_api_gateway_method.sbr_client_report_method", shape = "box"]
            "[root] module.lambda.aws_api_gateway_method_response.200" [label = "aws_api_gateway_method_response.200", shape = "box"]
            "[root] module.lambda.aws_api_gateway_method_response.500" [label = "aws_api_gateway_method_response.500", shape = "box"]
            "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource" [label = "aws_api_gateway_resource.sbr_client_report_resource", shape = "box"]
            "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api" [label = "aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api", shape = "box"]
            "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role" [label = "aws_iam_role.onlinetax_sbr_endpoint_role", shape = "box"]
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" [label = "aws_iam_role_policy.publish_to_sns_policy", shape = "box"]
            "[root] module.lambda.aws_iam_role_policy.write_to_cloudwatch_policy" [label = "aws_iam_role_policy.write_to_cloudwatch_policy", shape = "box"]
            "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda" [label = "aws_lambda_function.onlinetax_sbr_endpoint_lambda", shape = "box"]
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" [label = "aws_lambda_permission.allow_api_gateway", shape = "box"]
            "[root] module.lambda.provider.aws" [label = "provider.aws", shape = "diamond"]
            "[root] module.sns.aws_sns_topic.online_tax_qa5_sbr_client_report" [label = "aws_sns_topic.online_tax_qa5_sbr_client_report", shape = "box"]
            "[root] module.sns.provider.aws" [label = "provider.aws", shape = "diamond"]
            "[root] provider.aws (disabled)" [label = "provider.aws (disabled)", shape = "diamond"]
            "[root] module.lambda.aws_api_gateway_deployment.qa5" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_deployment.qa5" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_deployment.qa5" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda"
            "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_method_response.200"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_default_response" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_method_response.500"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_integration_response.sbr_client_report_resource_integration_error_response" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_method_response.200" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.aws_api_gateway_method.sbr_client_report_method"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_method_response.500" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api" -> "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda"
            "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" -> "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role"
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_iam_role_policy.publish_to_sns_policy" -> "[root] module.sns.aws_sns_topic.online_tax_qa5_sbr_client_report"
            "[root] module.lambda.aws_iam_role_policy.write_to_cloudwatch_policy" -> "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role"
            "[root] module.lambda.aws_iam_role_policy.write_to_cloudwatch_policy" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda" -> "[root] module.lambda.aws_iam_role.onlinetax_sbr_endpoint_role"
            "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_api_gateway_integration.sbr_client_report_resource_integration"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_api_gateway_resource.sbr_client_report_resource"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_api_gateway_rest_api.online_tax_sbr_client_report_endpoint_api"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.aws_lambda_function.onlinetax_sbr_endpoint_lambda"
            "[root] module.lambda.aws_lambda_permission.allow_api_gateway" -> "[root] module.lambda.provider.aws"
            "[root] module.lambda.provider.aws" -> "[root] provider.aws (disabled)"
            "[root] module.sns.aws_sns_topic.online_tax_qa5_sbr_client_report" -> "[root] module.sns.provider.aws"
            "[root] module.sns.provider.aws" -> "[root] provider.aws (disabled)"
        

图表还有我在上面的 tf 文件中没有提供的其他资源。它只有 API GW 有问题。顺便说一句,我可以从控制台测试 API,它工作正常。我无法从我的本地邮箱或邮递员执行它。

知道我做错了什么吗?

【问题讨论】:

这是第一次部署的情况,还是将来发生变化时的部署?后者在 GH 上有一个未解决的问题:github.com/hashicorp/terraform/issues/6613 我猜即使是第一次部署也没有用。我销毁了整个堆栈并再次应用它。仍然看不到部署。当 terraform plan 列出所有需要应用的更改时,部署资源会列在最顶部。这是否意味着首先部署? 它绝对不会首先运行,因为它至少依赖于 2 个资源(aws_api_gateway_rest_apiaws_api_gateway_method),而这又可能依赖于其他东西。我必须运行你的 TF 才能看到,但不幸的是,这必须等到今晚。如果您可以将terraform graph 的输出编辑到您的问题中,可能会很有趣? 【参考方案1】:

TF 不部署 API,此链接可能对您有所帮助:https://medium.com/coryodaniel/til-forcing-terraform-to-deploy-a-aws-api-gateway-deployment-ed36a9f60c1a

我已经通过添加变量 deploy_at 来修复我的问题:

resource "aws_api_gateway_deployment" "api_ingest_deployment" 
  depends_on = ["aws_api_gateway_method.xxx",
                "aws_api_gateway_integration.yyy",
                "aws_api_gateway_integration.zzz",
                "aws_api_gateway_integration.www",
  ]
  rest_api_id = "$aws_api_gateway_rest_api.foo.id"
  stage_name = "$var.environment"

  variables 
    deployed_at = "$timestamp()"
  

缺点是如果这样做,它总是会部署,即使没有变化

【讨论】:

实际上,我刚刚也检查了这个 GitHub 问题 github.com/hashicorp/terraform/issues/6613 这样做:资源 "aws_api_gateway_deployment" "default" ... stage_description = "$md5(file("api_gateway.tf" ))" ... 更聪明,会迫使你部署更少 我在这个问题上浪费了几个小时。谢谢你告诉我! Antonio 的回答帮助了我,这篇文章的解决方案似乎“更好”(解决方法,但有效)。应该是可接受的答案吗?【参考方案2】:

当我收到此错误时,这里没有其他解决方案对我有用:

BadRequestException: Active stages pointing to this deployment must be moved or deleted

This is the solution 对我有用:

resource "aws_api_gateway_deployment" "api_deployment" 
  rest_api_id       = aws_api_gateway_rest_api.api.id
  stage_name        = "default"
  stage_description = "Deployed at $timestamp()"

  lifecycle 
    create_before_destroy = true
  

在 Terraform 0.12.24 上测试

【讨论】:

谢谢,您的解决方案在 TF 0.12.24 上也对我有用【参考方案3】:

来自aws_api_gateway_deployment:

resource "aws_api_gateway_deployment" "example" 
  rest_api_id = aws_api_gateway_rest_api.example.id

  triggers = 
    # NOTE: The configuration below will satisfy ordering considerations,
    #       but not pick up all future REST API changes. More advanced patterns
    #       are possible, such as using the filesha1() function against the
    #       Terraform configuration file(s) or removing the .id references to
    #       calculate a hash against whole resources. Be aware that using whole
    #       resources will show a difference after the initial implementation.
    #       It will stabilize to only change when resources change afterwards.
    redeployment = sha1(jsonencode([
      aws_api_gateway_resource.example.id,
      aws_api_gateway_method.example.id,
      aws_api_gateway_integration.example.id,
    ]))
  

  lifecycle 
    create_before_destroy = true
  

您需要定义应该触发新部署的触发器,我在没有id 的情况下使用它,它工作得很好。

【讨论】:

【参考方案4】:

通常代码更改是在 lambda 级别。因此,您可以将 lambda 代码版本作为变量插入,并将其添加到您有 api 部署的同一模块中。这样它只会在 lambda 代码更改时部署。

【讨论】:

【参考方案5】:

您需要注意几件事。

    正确提及依赖项以确保在执行集成和方法块之后执行部署块(尤其是当您有任何授权方时)。

    在变量中添加时间戳函数,以便在所有依赖块执行完毕后立即部署。

      resource "aws_api_gateway_deployment" "mydeployment" 
      depends_on =["aws_api_gateway_method.mymethod","aws_api_gateway_integration.myintegration"]
      rest_api_id = "$aws_api_gateway_rest_api.myapi.id"
      stage_name = "dev"
      variables = 
         deployed_at = "$timestamp()"
      
    
    

【讨论】:

【参考方案6】:

如果您使用的是 swagger 模板和 terraform ver >= 0.12,那么您可以为 MD5 计算提供 swagger 文件,如下所示。这很完美。

resource "aws_api_gateway_deployment" "deploy_stage" 
  rest_api_id = aws_api_gateway_rest_api.product_api.id
  stage_name  = var.stage_name
  stage_description = md5(file("swagger_api.yml"))

【讨论】:

【参考方案7】:

遇到同样的问题。 遇到以下问题:

    lifecycle create_before_destroy = false

我不得不将其设置为 false,因为我有一个 options 方法被添加到与 get 相同的 uri 中。当我尝试使用打开的标志运行构建时,出现以下错误

创建 API 网关部署时出错:BadRequestException:没有为方法定义集成

    之后我开始遇到问题

BadRequestException:必须移动或删除指向此部署的活动阶段

经过调查,我发现这与我的 terraform 脚本中发生的自定义域映射有关。手动删除映射并运行 Jenkins Job 后解决了这个问题。

    我做的最后一件事是在应用 terraform 计划和 terraform 之前在我的 jenkins 文件中使用以下脚本。我知道这是一个 hack,但这是我能想到的最好的方法。

/usr/local/bin/terraform destroy -target aws_api_gateway_base_path_mapping. -auto-approve

这解决了这个问题。我查看了多个博客,他们提到将生命周期标志设置为 true。但我不能这样做,因为它造成了上述问题。

【讨论】:

以上是关于Terraform 未部署 api 网关阶段的主要内容,如果未能解决你的问题,请参考以下文章

Terraform 无法将创建的集成附加到 API 网关的路由中

AWS API 网关 CORS [关闭]

API Gateway 日志未随 terraform 一起显示

CloudFormation 不会在更新时部署到 API 网关阶段

Terraform 获取 api 网关的 ip 地址

Terraform:如何从对象列表创建 API 网关端点和方法?