Terraform Lambda source_code_hash使用相同的代码更新

时间:2018-10-05 09:15:53

标签: aws-lambda terraform

我已经使用Terraform成功部署了AWS Lambda:

resource "aws_lambda_function" "lambda" {
  filename                       = "dist/subscriber-lambda.zip"
  function_name                  = "test_get-code"
  role                           = <my_role>
  handler                        = "main.handler"
  timeout                        = 14
  reserved_concurrent_executions = 50
  memory_size                    = 128
  runtime                        = "python3.6"
  tags                           = <my map of tags>
  source_code_hash               = "${base64sha256(file("../modules/lambda/lambda-code/main.py"))}"
  kms_key_arn                    = <my_kms_arn>
  vpc_config {
    subnet_ids         = <my_list_of_private_subnets>
    security_group_ids = <my_list_of_security_groups>
  }
  environment {
    variables = {
      environment = "dev"
    }
  }
}

现在,当我运行terraform plan命令时,它说我的lambda资源需要更新,因为source_code_hash已更改,但是我没有更新lambda Python代码库(版本位于以下文件夹中)相同的回购):

  ~ module.app.module.lambda.aws_lambda_function.lambda
  last_modified:                     "2018-10-05T07:10:35.323+0000" => <computed>
  source_code_hash:                  "jd6U44lfe4124vR0VtyGiz45HFzDHCH7+yTBjvr400s=" => "JJIv/AQoPvpGIg01Ze/YRsteErqR0S6JsqKDNShz1w78"

我想是因为它每次都会压缩我的Python源,并且源会更改。如果Python代码没有变化,如何避免这种情况?如果我不更改Python代码库,我的假设是否连贯(我的意思是,为什么哈希会发生变化)?

4 个答案:

答案 0 :(得分:3)

这对我有用,并且在代码未更改时也不会触发Lambda函数的更新

data "archive_file" "lambda_zip" {                                                                                                                                                                                   
  type        = "zip"                                                                                                                                                                                                
  source_dir  = "../dist/go"                                                                                                                                                                                         
  output_path = "../dist/lambda_package.zip"                                                                                                                                                                         
}                                                                                                                                                                                                                    


resource "aws_lambda_function" "aggregator_func" {                                                                                                                                                                   
  description      = "MyFunction"                                                                                                                                                                       
  function_name    = "my-func-${local.env}"                                                                                                                                                                  
  filename         = data.archive_file.lambda_zip.output_path                                                                                                                                                        
  runtime          = "go1.x"                                                                                                                                                                                         
  handler          = "main"                                                                                                                                                                                    
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256                                                                                                                                                
  role             = aws_iam_role.function_role.arn                                                                                                                                                                  


  timeout = 120                                                                                                                                                                                                      
  publish = true                                                                                                                                                                                                     

  tags = {                                                                                                                                                                                                           
    environment = local.env                                                                                                                                                                                                                                                                                                                                                                    
  }                                                                                                                                                                                                                  
}                              

答案 1 :(得分:1)

这是因为您只是对 main.py 进行哈希处理,而是上传 dist / subscriber-lambda.zip 。 Terraform将哈希值与文件上传到lambda时计算得出的哈希值进行比较。由于哈希是在两个不同的文件上完成的,因此最终会得到不同的哈希值。尝试在完全相同的文件上运行哈希。

答案 2 :(得分:1)

I'm going to add my answer to contrast to the one @ODYN-Kon provided.

The source code hash field in resource "aws_lambda_function" is not compared to some hash of the zip you upload. Instead, the hash is merely checked against the Terraform saved state from the last time it ran. So, the next time you run Terraform, it computes the hash of the actual python file to see if it has changed. If it has, it assumes that the zip has been changed and the Lambda function resource needs to be run again. The source_code_hash can have any value you want to give it or it can be omitted entirely. You could set it to a constant of some arbitrary string, and then it would never change unless you edit your Terraform configuration.

Now, the problem there is that Terraform assumes you updated the zip file. Assuming you only have one directory or one file in the zip archive, you can use the Terraform data source archive_file to create the zip file. I have a case where I cannot use that because I need a directory and a file (JS world: source + node_modules/). But here is how you can use that:

data "archive_file" "lambdaCode" {
  type = "zip"
  source_file = "lambda_process_firewall_updates.js"
  output_path = "${var.lambda_zip}"
}

Alternativly, you can archive an entire directory, if you replace the "source_file" statement with source_dir = "node_modules"

Once you do this, you can reference the hash code of the zip archive file for insertion into resource "aws_lambda_function" "lambda" { block as "${data.archive_file.lambdaCode.output_base64sha256}" for the field source_hash. Then, anytime the zip changes, the lambda function gets updated. And, the data source archive file knows that anytime the source_file changes it must regenerate the zip.

Now, I haven't drilled down to a root cause in your case, but hopefully given some help to get to a better place. You can check the saved state of Terraform via: tf state list - which lists the items of saved state. You can find the one that matches your lambda function block and then execute tf state show <state-name>. For example, for one I am working on:

tf state show aws_lambda_function.test-lambda-networking gives about 30 lines of output, including:

source_code_hash = 2fKX9v/duluQF0H6O9+iRnID2gokhfpXIXpxyeVBUM0=

You can compare the hash via command line commands. Example on MacOS: sha256sum my-lambda.zip, where sha256sum was installed by brew install coreutils.

As mentioned, the use of archive_file doesn't work when you have multiple elements of the zip which are not isolated to a single directory. I think that probably happens a lot, so I wish the Hashicorp guys would extend archive_file to support multiple. I even went looking at the Go code, but that is a rainy day project. One variation I use is to take the source_code_hash to be "${base64sha256(file("my-lambda.zip"))}". But that still requires me to run tf twice.

答案 3 :(得分:1)

正如其他人所说,应该在文件名和哈希中使用您的zip。

我要提到的是,如果在lambda定义中使用错误的哈希函数,您也会遇到类似的娱乐问题。例如filesha256(.zip)也会每次都重新创建您的lambda。如source_code_hash here

所述,您必须使用filebase64sha256(“ file.zip”)(terraform 0.11.12+)或base64sha256(file(“ file.zip”))