amazon-web-services - 使用 CloudFormation 和 SAM 部署时如何确保使用最新的 lambda 层版本?

标签 amazon-web-services aws-lambda aws-cloudformation aws-sam

我们使用 CloudFormation 和 SAM 来部署 Lambda (Node.js) 函数。我们所有的 Lambda 函数都有一个通过 Globals 设置的层。当我们对层代码进行重大更改时,我们会在部署过程中遇到错误,因为新的 Lambda 函数会使用旧层部署到生产环境中,并且几秒钟后(在我们的示例中约为 40 秒)它开始使用新层。例如,假设我们向层添加一个新类,并将其导入到函数代码中,然后我们会收到一个错误,在部署期间显示 NewClass is not found 几秒钟(发生这种情况是因为新函数代码仍然使用旧层,没有 NewClass )。

是否可以确保新的 lambda 函数始终与最新的层版本一起推出?

示例 CloudFormation 模板:

    Globals:
      Function:
        Runtime: nodejs14.x
        Layers:
          - !Ref CoreLayer
    
    Resources:
      CoreLayer:
        Type: AWS::Serverless::LayerVersion
        Properties:
          LayerName: core-layer
          ContentUri: packages/coreLayer/dist
          CompatibleRuntimes:
            - nodejs14.x
        Metadata:
          BuildMethod: nodejs14.x
    
      ExampleFunction:
        Type: AWS::Serverless::Function
        Properties:
          FunctionName: example-function
          CodeUri: packages/exampleFunction/dist

示例 CloudFormation 部署事件,您可以看到新层 ( CoreLayer123abc456 ) 在更新 Lambda 函数之前创建,因此它应该可以在新函数代码中使用,但由于某些原因,Lambda 使用旧层版本进行更新和部署几秒钟:

<表类=“s-表”> <标题> 时间戳 逻辑ID 状态 状态原因 <正文> 2022-05-23 16:26:54 堆栈名称 更新完成 - 2022-05-23 16:26:54 CoreLayer789def456 DELETE_SKIPPED - 2022-05-23 16:26:53 v3uat-farthing UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - 2022-05-23 16:26:44 示例函数 更新完成 - 2022-05-23 16:25:58 示例函数 UPDATE_IN_PROGRESS - 2022-05-23 16:25:53 CoreLayer123abc456 创建_完成 - 2022-05-23 16:25:53 CoreLayer123abc456 CREATE_IN_PROGRESS 资源创建已启动 2022-05-23 16:25:50 CoreLayer123abc456 CREATE_IN_PROGRESS - 2022-05-23 16:25:41 堆栈名称 UPDATE_IN_PROGRESS 用户启动

变更集示例:


    {
      "resourceChange": {
        "logicalResourceId": "ExampleFunction",
        "action": "Modify",
        "physicalResourceId": "example-function",
        "resourceType": "AWS::Lambda::Function",
        "replacement": "False",
        "moduleInfo": null,
        "details": [
          {
            "target": {
              "name": "Environment",
              "requiresRecreation": "Never",
              "attribute": "Properties"
            },
            "causingEntity": "ApplicationVersion",
            "evaluation": "Static",
            "changeSource": "ParameterReference"
          },
          {
            "target": {
              "name": "Layers",
              "requiresRecreation": "Never",
              "attribute": "Properties"
            },
            "causingEntity": null,
            "evaluation": "Dynamic",
            "changeSource": "DirectModification"
          },
          {
            "target": {
              "name": "Environment",
              "requiresRecreation": "Never",
              "attribute": "Properties"
            },
            "causingEntity": null,
            "evaluation": "Dynamic",
            "changeSource": "DirectModification"
          },
          {
            "target": {
              "name": "Code",
              "requiresRecreation": "Never",
              "attribute": "Properties"
            },
            "causingEntity": null,
            "evaluation": "Static",
            "changeSource": "DirectModification"
          },
          {
            "target": {
              "name": "Layers",
              "requiresRecreation": "Never",
              "attribute": "Properties"
            },
            "causingEntity": "CoreLayer123abc456",
            "evaluation": "Static",
            "changeSource": "ResourceReference"
          }
        ],
        "changeSetId": null,
        "scope": [
          "Properties"
        ]
      },
      "hookInvocationCount": null,
      "type": "Resource"
    }

我不明白为什么 target.name: Layers 数组中有 2 个 details 项。其中一个具有 causingEntity: CoreLayer123abc456 ,这是由于新创建的层而预期的,另一个具有 causingEntity: null ,不知道为什么会出现这个。

最初发布在 AWS re:Post here

编辑:

经过几次测试,发现问题是由变更集中的变更顺序引起的。看起来更改是一一应用的。例如,对于以下变更集,它会在仍然使用旧层的同时更新旧功能代码,然后使用最新版本更新功能层,因为 Layers 更改项位于 Code 更改项之后。


    {
      "resourceChange":{
        "logicalResourceId":"ExampleFunction",
        "action":"Modify",
        "physicalResourceId":"example-function",
        "resourceType":"AWS::Lambda::Function",
        "replacement":"False",
        "moduleInfo":null,
        "details":[
          {
            "target":{
              "name":"Layers",
              "requiresRecreation":"Never",
              "attribute":"Properties"
            },
            "causingEntity":null,
            "evaluation":"Dynamic",
            "changeSource":"DirectModification"
          },
          {
            "target":{
              "name":"Code",
              "requiresRecreation":"Never",
              "attribute":"Properties"
            },
            "causingEntity":null,
            "evaluation":"Static",
            "changeSource":"DirectModification"
          },
          {
            "target":{
              "name":"Layers",
              "requiresRecreation":"Never",
              "attribute":"Properties"
            },
            "causingEntity":"CoreLayer123abc456",
            "evaluation":"Static",
            "changeSource":"ResourceReference"
          }
        ],
        "changeSetId":null,
        "scope":[
          "Properties"
        ]
      },
      "hookInvocationCount":null,
      "type":"Resource"
    }

但在某些部署中,顺序是相反的,例如:


    {
      "resourceChange":{
        ...
        "details":[
          ...
          {
            "target":{
              "name":"Layers",
              "requiresRecreation":"Never",
              "attribute":"Properties"
            },
            "causingEntity":"CoreLayer123abc456",
            "evaluation":"Static",
            "changeSource":"ResourceReference"
          },
          {
            "target":{
              "name":"Code",
              "requiresRecreation":"Never",
              "attribute":"Properties"
            },
            "causingEntity":null,
            "evaluation":"Static",
            "changeSource":"DirectModification"
          }
        ],
        ...
    }

在这种情况下,它会使用最新的层版本更新旧函数,然后使用更新的版本更新函数代码。因此,在几秒钟内,旧代码将被最新的层版本调用。

那么是否可以仅一步应用所有这些更改?类似于 Atomicity in databases

最佳答案

我通过使用建议的 Lambda 版本解决了这个问题 here 。对于每个部署,我都会创建一个新的 Lambda 版本,以便新旧 Lambda 使用正确的核心层。

重新发布我在原始帖子中的评论以供引用:

I added a lambda version:

ExampleFunctionVersion:
  Type: AWS::Lambda::Version
  DeletionPolicy: Delete
  Properties:
    FunctionName: !Ref ExampleFunction

and replaced all function references with !Ref ExampleFunctionVersion.

I also tried AutoPublishAlias: live, it worked too but I had to add an AWS::Lambda::Version resource to be able to set DeletionPolicy: Delete

关于amazon-web-services - 使用 CloudFormation 和 SAM 部署时如何确保使用最新的 lambda 层版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72393388/

相关文章:

c# - 如何禁用 .NET Core http 客户端中的 SSL 证书检查?

windows - 如何在预先创建的 VPC 中启动实例并且还应该为其配置公共(public) IP?

amazon-web-services - 由于小写,CloudFormation 无法找到 RDS 子网组

python - 如何将 AWS EventBridge 与 Python Lambda 和 Boto 结合使用?

amazon-web-services - 通过cloudformation脚本获取子网的AZ

amazon-web-services - 如何在 lambda 中获取当前执行角色?

amazon-web-services - AWS Elastic Beanstalk Docker 来自 ECR 错误 "No Docker image specified in Dockerrun.aws.json"

aws-lambda - 如何使用参数覆盖从输入工件动态分配代码参数中的 s3bucket 和 s3key 值?

amazon-web-services - 获取 Cloudformation 错误 : Embedded stack was not successfully created

json - 如何使用控制台在 aws SNS 中发送 json 消息正文