存档文件将在您的本地文件系统中查找并在您每次执行 terraform 计划时运行。有一个depends_on
除了说在之后进行存档之外什么也不做null_resource
. If null_resource
没有被触发,它仍然会说“好吧,我完成了!”和你的archive_file
会跑。
正如上面的评论所提到的,大多数人每次都会使用触发器进行重建,例如timestamp()
。作为工程师/开发人员,我们需要以下内容:
Only build and deploy my lambda if code has changed, otherwise I don't want to waste time watching this happen.
为了实现这一结果,我们必须创建一个持久的数据存储。
有几种解决方案...
-
使用 Lambda 的 Docker 映像。我还没有测试过这个,但从技术上讲它应该可以工作,因为你只需推送一个新图像,你的 lambda 就会不断寻找latest
. 这是一个例子我已经设法找到了。无论latest
当涉及到图像标签时好还是不好……那是另一个话题了。在这种情况下,ECR 是您的持久数据存储。
-
手动重新创建一切archive_file
正在使用 Bash 或类似的工具进行操作。这是一个工作示例。
拉姆达.tf
data "aws_s3_object" "s3_archive" {
bucket = "mybucket"
key = "lambda/build.zip"
depends_on = [
null_resource.build # wait until our upload script is done
]
}
resource "aws_lambda_function" "lambda_function" {
function_name = "Pokemon"
s3_bucket = "mybucket"
s3_key = "lambda/build.zip"
source_code_hash = data.aws_s3_object.s3_archive.metadata.Sha # this is our custom metadata tag which has the same value as data.archive_file.lambda_function_zip.output_base64sha256 would have
runtime = "python3.9"
handler = "handler.handler"
role = aws_iam_role.role.arn
depends_on = [
null_resource.build # don't make lambda until after our upload.sh script
]
}
resource "null_resource" "build" {
triggers = {
requirements = filesha256("./requirements.txt") # change this file, we run script
source_code = filesha256("./handler.py") # change this file, we run script
}
provisioner "local-exec" {
command = "./upload.sh" # run upload.sh script
interpreter = [
"bash", "-c"
]
}
}
resource "aws_iam_role" "role" {
name = "lambda_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
handler.py (我知道你正在使用 Node,但无论如何把它放在这里)
import requests
def handler(event, context):
r = requests.get('https://pokeapi.co/api/v2/pokemon/1/').json()
print(r)
return "Hello World!"
这就是事情变得有点令人讨厌的地方,Windows 上的 Bash 让我的生活变得艰难......
上传.sh
mkdir -p ./build # create build directory
cp handler.py ./build # copy handler.py code to build directory
cp requirements.txt ./build # copy requirements.txt code to build directory (this is like your package.json)
pip install --target ./build -r requirements.txt # this is like your npm install command (install dependencies into build directory)
'C:/Program Files/7-Zip/7z.exe' a -r build.zip ./build/* # I'm on windows so cannot use `zip` like Linux/Mac but basically .zip the entire build directory
# On Linux/Mac you can use zip -r -q build.zip ./build/*
SHA=$(sha256sum build.zip | cut -f1 -d \ | xxd -r -p | base64) # Generate a sha256 base64 encoded string (this is what lambda requires based on TF docs)
echo $SHA # Echo for debugging purposes
# Copy .zip to s3 and append metadata `sha` including our sha256 base64 encoded value so we can use it
# to detect if the .zip differs to what our Lambda function has as it's source_code_hash
aws s3 cp ./build.zip s3://mybucket/lambda/build.zip --metadata sha=$SHA
制定计划并应用后,这是我在 S3 中的 build.zip 上的元数据
这是我的 Lambda 地形状态:
现在,当我运行另一个地形计划时:
No changes. Your infrastructure matches the configuration.
当我编辑requirements.txt或我的python源代码时(有S3更改,但我将这些更改排除在屏幕截图之外):
Run terraform apply:
删除后运行后续 terraform 计划ALL从我的桌面构建文件原因为何不:
No changes. Your infrastructure matches the configuration.
显然这是一个非常极端的解决方案,因此如果您不介意每次都重建构建资产,那么只需使用archive_file
数据源。如果这是一个大问题,请使用我上面写的内容 - 我不知道有任何其他解决方案,而且我见过的每个 GitHub 问题目前都是“抱歉,事情就是这样”。
EDIT:
只是为了补充我的答案,您可以避免一起使用 S3 并按照 Lambda 文档计算 Terraform 内的 SHA
# The filebase64sha256() function is available in Terraform 0.11.12 and later
# For Terraform 0.11.11 and earlier, use the base64sha256() function and the file() function:
# source_code_hash = "${base64sha256(file("lambda_function_payload.zip"))}"
source_code_hash = filebase64sha256("lambda_function_payload.zip")
filebase64sha256
需要 .zip 存在不过在运行 Terraform 之前。不过,您可能想从 Artifactory/S3/Hard Drive 等持久存储中获取此文件,但我相信新的 .zip 不起作用。
您仍然需要使用 bash/python 脚本进行归档和压缩prior运行 Terraform 但可以使用此方法避免 S3。
EDIT 2
您也可以使用 Terraform 数据源:
data "external" "build_archive" {
program = ["python3", "/scripts/build_archive.py"]
query = {
directory = "./my_source_code"
name = "my_source_code"
}
}
它看起来像 .zip 档案将日期和时间作为元数据记住,这样它们的 SHA 就会不断变化。也许数据源是不可能的,但我将把它留在这里以引发其他人的进一步调查。
通过我的尝试,我让数据资源返回计算出的sha
但即使使用也经历了持续的漂移.tar.gz
排除元数据的档案。拉姆达无法上传.tar.gz
所以我假设AWS使用我的重新计算了SHA.zip
存档并忽略我的source_code_hash
价值。如果我单独对 .tar.gz 进行 Sha'd,它仍然保持一致。
同样,这没有使用持久数据存储,因此这可能是问题所在。