仅当代码更改时才为 Lambda 创建新的 archive_file?

2023-11-30

我正在用 TypeScript 编写 Lambda 函数。跑步时terraform apply in github actions我想构建 Lambda(这需要安装依赖项,然后对所有内容进行 Web 打包),对其进行压缩,然后将其部署到 AWS。触发器为null_resource曾经是时间戳,但这意味着即使没有任何更改,它也会执行所有这些步骤(构建、压缩、部署)。

所以我将触发器更改为 lambda 子目录中所有文件的哈希值

resource "null_resource" "build_lambda_function" {
  triggers = {
    # timestamp = timestamp()
    dir_sha1 = sha1(join("", [for f in fileset(path.root, "${local.lambda_path_prefix}/${var.lambda_dir}/**"): filesha1(f)]))
  }

  provisioner "local-exec" {
    command     = "npm ci && npm run build"
    working_dir = "${local.lambda_path_prefix}/${var.lambda_dir}"
  }
}

这就是我创建 zip 并部署它的方式

data "archive_file" "lambda_function_zip" {
  type        = "zip"
  source_dir  = "${local.lambda_path_prefix}/${var.lambda_dir}/dist"
  output_path = "${local.lambda_path_prefix}/${var.lambda_dir}.zip"
  depends_on = [
    null_resource.build_lambda_function
  ]
}

resource "aws_lambda_function" "lambda_function" {
  function_name    = var.lambda_name
  source_code_hash = data.archive_file.lambda_function_zip.output_base64sha256
  filename         = data.archive_file.lambda_function_zip.output_path
  ...
}

我第一次在 gh-actions 上运行它时效果很好(因为触发了空资源),但在第二次运行时它失败了。由于没有发生任何变化,所以没有构建 lambda。不dist文件夹已创建,因此archive_file抛出一个错误

错误归档目录:无法归档丢失的目录:./../lambda/testlambda/dist

我想要的有可能吗?


存档文件将在您的本地文件系统中查找并在您每次执行 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.

为了实现这一结果,我们必须创建一个持久的数据存储。

有几种解决方案...

  1. 使用 Lambda 的 Docker 映像。我还没有测试过这个,但从技术上讲它应该可以工作,因为你只需推送一个新图像,你的 lambda 就会不断寻找latest. 这是一个例子我已经设法找到了。无论latest当涉及到图像标签时好还是不好……那是另一个话题了。在这种情况下,ECR 是您的持久数据存储。

  2. 手动重新创建一切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 上的元数据

enter image description here

这是我的 Lambda 地形状态:

enter image description here

现在,当我运行另一个地形计划时:

No changes. Your infrastructure matches the configuration.

当我编辑requirements.txt或我的python源代码时(有S3更改,但我将这些更改排除在屏幕截图之外):

enter image description here

Run terraform apply: enter image description here

删除后运行后续 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,它仍然保持一致。

同样,这没有使用持久数据存储,因此这可能是问题所在。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅当代码更改时才为 Lambda 创建新的 archive_file? 的相关文章

随机推荐

  • Jquery - 如何在动态创建后添加事件

    我动态创建一个 div 然后将其附加到容器中 var str div class dimsdiv div fpdiv append str 现在我什至需要为这些 div 添加悬停 我尝试只引用它 但后来发现我需要考虑 on 我尝试过这个 之
  • 关于派生类初始化中的基类

    伙计们 我看到几个案例 例如 class Derived public Base public Derived Base 什么情况或者有什么原则我们应该在 Derived ctor 初始化列表中显式初始化 Base 谢谢 如果您想使用参数调
  • PHP 正则表达式确定相对或绝对路径

    我正在使用 cURL 来提取远程站点的内容 我需要检查所有 href 属性并确定它们是相对路径还是绝对路径 然后获取链接的值并将其路径设置为 href http www website com index php url ABSOLUTE
  • 在 django 中将多个查询集转换为 json

    我问了一个今天早些时候的相关问题 在本例中 我有 4 个查询集结果 action count Action objects filter complete False onhold False annotate action count C
  • 我正在开发一款需要播放背景音乐的游戏 我想知道是否有办法隐藏音乐的进度条 只显示带有音量滑块的播放和停止按钮 现在我已经调整了宽度 以便仅显示播放按钮 但是当我将其更改为更大的宽度以显示滑块时 进度条又回来了 我想完全摆脱进度条 不幸的是
  • Sklearn One Hot Encoding 生成非表格输出

    我有一个这样的数据集 Entity Year Mean 0 Afghanistan 2016 0 99 1 Africa 2016 0 99 2 Albania 2016 0 99 3 Algeria 2016 0 99 4 America
  • 如何通过 Zend_Service_Amazon_S3 访问 Amazon s3 私有存储桶对象

    我在 Amazon S3 上创建了一个存储桶 并将一些图像保存在该存储桶中的一个文件夹中 所有图像都是私有的 我正在使用 Zend 的 Zend Service Amazon S3 类 如何访问私有图像 您可以通过像这样创建私有 url 来
  • 应用程序未在本机反应中注册

    I have a react native application and I changed the package name of the application using https www npmjs com package re
  • 为什么不在 C++ 中的所有内容都使用指针呢?

    假设我定义了一些类 class Pixel public Pixel x 0 y 0 int x int y 然后使用它编写一些代码 我为什么要执行以下操作 Pixel p p x 2 p y 5 来自 Java 世界的我总是这样写 Pix
  • 从另一个线程访问上下文

    我开始将一些 PC Java 应用程序迁移到 Android 环境 作为 Android 平台的完全新手 当我尝试使用时发现一个问题Service参考作为上下文Toast信息 这是我的相关部分Service code public clas
  • 我正在尝试使用 Firebase 为 Java 桌面应用程序构建后端

    几天来我一直在尝试使用 Java 不是 Android 和 Firebase 进行简单的用户身份验证 在开始使用 Firebase 的用户身份验证类之前 我尝试使用 Java 在 Firebase 参考上进行简单的保存和检索 但没有成功 没
  • 时间延迟重定向?

    我有一个网站 可以滑动到 HTML 中名为博客的 部分 我希望用户只需查看该页面一两秒 然后重定向到我的博客引擎 请建议延迟重定向 如果我可以根据博客李的点击延迟时间进行重定向 li class tile icon add favourit
  • 台风未注入财产(无故事板)

    我无法使用 XIB 将属性注入到视图控制器中initWithNibName bundle Example 这是我的装配 implementation AppAssembly ViewControllerC viewControllerC r
  • Android java:将巨大的列表插入数据库SQL时出现OutOfMemory

    我正在开发一个使用 ORM greendao 的 Android 项目 它允许我一次 在一个事务中 将多个实体 显然是对象 插入到数据库中 实际操作中有一个方法 插入或替换InTx 它接受一个集合作为参数 给定一个对象列表 问题是我的列表有
  • 如果 Spring MVC 控制器方法没有返回值,返回什么?

    我正在使用 jQuery 的 getJSON 对我的简单 Spring MVC 后端进行异步调用 大多数 Spring 控制器方法如下所示 RequestMapping value someURL method RequestMethod
  • 在Windows中的Python 3.6中安装mysqlclient

    我想在我的 Windows 系统上安装 MySqlclient 我目前使用的是Python 3 6 在浏览了 Stackoverflow 上的各种帖子后 我找不到正确的方法 这是我到目前为止所做的 1 使用pip安装pip install
  • 流畅的 NHibernate - HasManyToMany NHibernate.MappingException:集合映射中的重复列

    我是一名 NHibernate 新手 尝试使用 Fluent NHibernate 配置现有数据库 问题在于多对多映射 在此示例中以图书馆和书籍为代表 我想这应该是非常基本的东西 但我得到以下例外 FluentNHibernate Cfg
  • Mysqli准备语句(预防SQL注入)

    在停止使用已弃用的 mysql 函数后 我切换到 mysqli 但后来 我注意到未准备好的语句对于 SQL 注入是不安全的 然后 我再次更改了我的代码 我所拥有的是以下函数 用于检查变量是否 ID存在于数据库中并打印值title对于该行 f
  • Pandas DataFrame 日期系列到列表的转换

    我有一个名为 signal data 的数据框 其数据如下 Pressure DateTime Temp 3025 2016 04 01 00 17 00 TTY 3019 2016 04 01 00 17 00 TTY 3019 2016
  • 仅当代码更改时才为 Lambda 创建新的 archive_file?

    我正在用 TypeScript 编写 Lambda 函数 跑步时terraform apply in github actions我想构建 Lambda 这需要安装依赖项 然后对所有内容进行 Web 打包 对其进行压缩 然后将其部署到 AW