如何使用CloudFormation创建新版本的Lambda函数?

时间:2017-01-03 21:00:08

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

我正在尝试使用CloudFormation创建新版本的Lambda函数。

我想拥有相同Lambda函数的多个版本,以便我可以(a)将别名指向不同版本 - 如DEV和PROD - 以及(b)能够回滚到早期版本

这是我的Lambda版本的定义:

LambdaVersion:
  Type: AWS::Lambda::Version
  Properties:
    FunctionName:
      Ref: LambdaFunction

运行“aws cloudformation create-stack”时会创建一个版本,但后续的“aws cloudformation update-stack”命令不会执行任何操作。没有创建新的Lambda版本。

我正在尝试在将新的zip文件上传到S3然后运行“update-stack”之后创建一个新版本的Lambda函数。我可以使用CloudFormation做到吗? AWS :: Lambda :: Version是否真的坏了(如https://github.com/hashicorp/terraform/issues/6067#issuecomment-211708071所述)或者我没有得到什么?

更新1/11/17 亚马逊支持的官方回复: “...对于要发布的任何新版本,您需要定义一个附加(原文如此) AWS :: Lambda :: Version资源......”

AWS CloudFormation / Lambda团队,如果您正在阅读此内容 - 这是不可接受的。解决它。

12 个答案:

答案 0 :(得分:19)

我有一个类似的用例(需要使用CloudFormation来管理在CloudFront中使用@edge的lambda函数,对于该函数,总是需要特定的lambda函数版本,而不是$LATEST)并且我的搜索使我找到了首先讨论这个问题,但经过一番挖掘后,我很高兴地发现现在支持使用AWS无服务器应用程序模型的新AutoPublishAlias功能进行自动lambda版本控制(基本上是一个可选的额外高级别设置)构建您的CloudFormation模板。)

在此宣布:https://github.com/awslabs/serverless-application-model/issues/41#issuecomment-347723981

详见:

基本上,您在AutoPublishAlias定义中包含AWS::Serverless::Function

MyFunction:
  Type: "AWS::Serverless::Function"
  Properties:
    # ...
    AutoPublishAlias: MyAlias

然后在CloudFormation模板的其他位置,您可以将最新发布的版本引用为!Ref MyFunction.Version(yaml语法)。

答案 1 :(得分:16)

AWS :: Lambda :: Version无效。您必须为每个Lambda版本添加新资源。如果要为每个Cloudformation更新发布新版本,则必须破解系统。

我解决了这个问题,创建了一个为每个部署触发的Lambda支持的自定义资源。在这个Lambda中,我正在为参数。

中给出的Lambda函数创建一个新版本

对于Lambda的来源,您可以查看http://serverless-arch-eu-west-1.s3.amazonaws.com/serverless.zip

以下是使用此部署Lambda函数的示例Cloudformation(您可能需要进行一些修改):

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters": {
    "DeploymentTime": {
      "Type": "String",
      "Description": "It is a timestamp value which shows the deployment time. Used to rotate sources."
    }
  },
  "Resources": {
    "LambdaFunctionToBeVersioned": {
      "Type": "AWS::Lambda::Function",
       ## HERE DEFINE YOUR LAMBDA AS USUAL ##
    },
    "DeploymentLambdaRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "lambda.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/",
        "ManagedPolicyArns": [
          "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
        ],
        "Policies": [
          {
            "PolicyName": "LambdaExecutionPolicy",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "lambda:PublishVersion"
                  ],
                  "Resource": [
                    "*"
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    "DeploymentLambda": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Role": {
          "Fn::GetAtt": [
            "DeploymentLambdaRole",
            "Arn"
          ]
        },
        "Handler": "serverless.handler",
        "Runtime": "nodejs4.3",
        "Code": {
          "S3Bucket": {
            "Fn::Sub": "serverless-arch-${AWS::Region}"
          },
          "S3Key": "serverless.zip"
        }
      }
    },
    "LambdaVersion": {
      "Type": "Custom::LambdaVersion",
      "Properties": {
        "ServiceToken": {
          "Fn::GetAtt": [
            "DeploymentLambda",
            "Arn"
          ]
        },
        "FunctionName": {
          "Ref": "LambdaFunctionToBeVersioned"
        },
        "DeploymentTime": {
          "Ref": "DeploymentTime"
        }
      }
    }
  }
}

(免责声明:此代码是我的书的一部分,有关Lambda& API Gateway的更多信息,请查看:https://www.amazon.com/Building-Serverless-Architectures-Cagatay-Gurturk/dp/1787129195

答案 2 :(得分:8)

AWS::Lambda::Version资源仅代表一个已发布的Lambda函数版本 - 它不会在每次更新代码时自动发布新版本。要实现此目的,您有两种选择:

1。自定义资源

您可以在每次更新时实施自己的Custom Resource {/ 3}}。

对于这种方法,每次更新堆栈时仍需要更改至少一个参数,以便触发将触发PublishVersion操作的自定义资源的更新。 (不过,您不必实际更新模板。)

这是一个完整的,有效的例子:

PublishVersion

Description: Publish a new version of a Lambda function whenever the code is updated.
Parameters:
  Nonce:
    Description: Change this string when code is updated.
    Type: String
    Default: "Test"
Resources:
  MyCustomResource:
    Type: Custom::Resource
    Properties:
      ServiceToken: !GetAtt MyFunction.Arn
      Nonce: !Ref Nonce
  MyFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          exports.handler = function(event, context) {
            return response.send(event, context, response.SUCCESS, {Result: '${Nonce}'});
          };
      Runtime: nodejs4.3
  LambdaDeploy:
    Type: Custom::LambdaVersion
    Properties:
      ServiceToken: !GetAtt LambdaDeployFunction.Arn
      FunctionName: !Ref MyFunction
      Nonce: !Ref Nonce
  LambdaDeployFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: "index.handler"
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var AWS = require('aws-sdk');
          var response = require('cfn-response');
          exports.handler = (event, context) => {
            console.log("Request received:\n", JSON.stringify(event));
            if (event.RequestType == 'Delete') {
              return response.send(event, context, response.SUCCESS);
            }
            var lambda = new AWS.Lambda();
            lambda.publishVersion({FunctionName: event.ResourceProperties.FunctionName}).promise().then((data) => {
              return response.send(event, context, response.SUCCESS, {Version: data.Version}, data.FunctionArn);
            }).catch((e) => {
              return response.send(event, context, response.FAILED, e);
            });
          };
      Runtime: nodejs4.3
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: {Service: [lambda.amazonaws.com]}
          Action: ['sts:AssumeRole']
      Path: /
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
      - PolicyName: PublishVersion
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action: ['lambda:PublishVersion']
            Resource: '*'
Outputs:
  LambdaVersion:
    Value: !GetAtt LambdaDeploy.Version
  CustomResourceResult:
    Value: !GetAtt MyCustomResource.Result

2。模板预处理器

您可以使用Launch Stack之类的模板预处理器(或者只是在每次部署时手动更新模板),通过更改AWS::Lambda::Version资源{{3}来在代码的每次更新时发布新版本每当你的代码更新时。

示例:

# template.yml
Description: Publish a new version of a Lambda function whenever the code is updated.
<%nonce = rand 10000%>
Resources:
  LambdaVersion<%=nonce%>:
    Type: AWS::Lambda::Version
    Properties:
      FunctionName: !Ref MyFunction
  MyCustomResource:
    Type: Custom::Resource
    Properties:
      ServiceToken: !GetAtt MyFunction.Arn
      Nonce: <%=nonce%>
  MyFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          exports.handler = function(event, context) {
            return response.send(event, context, response.SUCCESS, {Result: '<%=nonce%>'});
          };
      Runtime: nodejs4.3
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: {Service: [lambda.amazonaws.com]}
          Action: ['sts:AssumeRole']
      Path: /
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Outputs:
  LambdaVersion:
    Value: !GetAtt LambdaVersion<%=nonce%>.Version
  CustomResourceResult:
    Value: !GetAtt MyCustomResource.Result

要在通过template.yml模板预处理器传递erb时创建/更新堆栈,请运行:

aws cloudformation [create|update]-stack \
  --stack-name [stack_name] \
  --template-body file://<(ruby -rerb -e "puts ERB.new(ARGF.read).result" < template.yml) \
  --capabilities CAPABILITY_IAM

答案 3 :(得分:8)

此帖子已过时。我在这里对其进行更新,以便其他人可以看到自2020年6月9日起版本Lambda的正确解决方案,而无需额外的自定义版本Lambda。

此:

Description: Lambda Example
Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Code:
        ZipFile: |
          'Example Code';
      Runtime: nodejs12.x
      Timeout: 5

成为这个:

Description: Lambda Example
Transform: AWS::Serverless-2016-10-31
Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      AutoPublishAlias: live
      Handler: index.handler
      InlineCode: |
        'Example Code';
      Runtime: nodejs12.x
      Timeout: 5

Transform:允许AWS::Serverless::Function在CloudFormation模板中,而CloudFormation模板又支持lambda版本控制。

别让上面标有日期的“最佳答案”(为那个人而建)像我一样把你扔到兔子洞里。

不客气。

答案 4 :(得分:7)

于2018年2月更新了答案

您可以使用AWS SAM (Serverless Application Model)及其sam packagesam deploy命令更新Lambda 。它们类似于aws cloudformation packageaws cloudformation deploy命令,但也允许您自动更新Lambda版本。

SAM可以打包您的代码(或者使用您创建的ZIP包),将其上传到S3,然后从中更新Lambda的$LATEST版本。 (如果这就是您所需要的,也可以使用aws cloudformation完成此操作,不使用SAM;代码示例与下面相同,但仅使用CloudFormation的标准声明)。然后,使用SAM,如果进行了相应配置,您还可以自动发布版本并更新别名以指向它。它还可以选择使用AWS CodeDeploy逐渐将流量从先前版本移动到新版本,并在出现错误时回滚。所有这些都在Safe Lambda deployments中解释。

从技术上讲,我们的想法是每次更新堆栈时,都需要AWS::Lambda::Function Code指向S3中的 new 包。这将确保在您更新堆栈时,将从新包中更新Lambda的$ LATEST版本。然后,您还可以自动发布新版本并将Alias切换到该版本。

为此,创建一个SAM模板,类似于CloudFormation模板的(超集)。它可能包含特定于SAM的声明,例如下面AWS::Serverless::Function的声明。将Code指向源代码目录(或预先打包的ZIP),并设置AutoPublishAlias属性。

...

MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      ...  # all usual CloudFormation properties are accepted 
      AutoPublishAlias: dev  # will publish a Version and create/update Alias `dev` to point to it
      Code: ./my/lambda/src
...

执行命令

$ sam package --template-file template.yaml --output-template-file packaged.yaml --s3-bucket my-bucket

这将源目录内容打包为ZIP(如果Code已经不是ZIP),在新的自动生成密钥下将其上传到S3,并生成最终的CloudFormation模板到packaged.yaml,为您提供适当的Code引用;像这样:

...
MyFunction:
    Properties:
      Code:
        S3Bucket: my-bucket
        S3Key: ddeeaacc44ddee33ddaaee223344
...

现在,您可以将生成的packaged.yaml与SAM一起使用,以创建函数版本:

sam deploy --template-file packaged.yaml --stack-name my-stack [--capabilities ...]

这将更新Lambda的$LATEST版本,如果已定义AutoPublishAlias,则将其作为新版本发布,并更新Alias以指向新发布的版本。

有关完整的模板代码,请参阅examples in SAM GitHub repo

答案 5 :(得分:2)

寻找类似于从S3部署的Lambda函数的东西。

我的用例是:

  • 您有一个从S3存储桶位置创建Lambda函数的云形态模板
  • 您需要更新此功能,以便在本地进行代码更改并将更改推送到S3
  • 您现在想要将这些更改推送到Lambda,以便您尝试更新堆栈,并且cloudformation表示没有更新更新,因此您必须使用AWS Lambda控制台手动更新代码。

对此并不满意我寻找替代方案并遇到了这个问题。 这些答案都没有对我有用,所以我在这里采取了一些想法并调整了答案,并用Python编写了我自己的版本。

这段代码改编自@wjordan的答案,因此他对这个想法和原始答案表示赞赏。不同之处是:

  • 这是用Python编写的
  • 适用于从S3存储桶部署的Lambda代码
  • 更新代码并发布新版本

您需要一个nonce参数。当需要将代码重新发布到Lambda时,可以更改此参数的值。这是为了确保cloudformation将更新您的自定义资源。更新自定义资源后,它将运行最终更新Lambda代码的Python代码。

希望这有助于某人。

Description: Publish a new version of a Lambda function whenever the code is updated.
Parameters:
  Nonce:
    Description: Change this string when code is updated.
    Type: String
    Default: "Test"
Resources:
  MyCustomResource:
    Type: Custom::Resource
    Properties:
      ServiceToken: !GetAtt MyFunction.Arn
      Nonce: !Ref Nonce
  MyFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        S3Bucket: BucketContainingYourLambdaFunction
        S3Key: KeyToYourLambdaFunction.zip
      Runtime: "python3.6"
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: {Service: [lambda.amazonaws.com]}
          Action: ['sts:AssumeRole']
      Path: /
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  LambdaDeployCustomResource:
    Type: Custom::LambdaVersion
    Properties:
      ServiceToken: !GetAtt LambdaDeployFunction.Arn
      FunctionName: !Ref MyFunction
      S3Bucket: BucketContainingYourLambdaFunction
      S3Key: KeyToYourLambdaFunction.zip
      Nonce: !Ref Nonce
  LambdaDeployFunction:
    Type: AWS::Lambda::Function
    DependsOn: LambdaDeployFunctionExecutionRole
    Properties:
      Handler: "index.handler"
      Role: !GetAtt LambdaDeployFunctionExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          import boto3
          import json
          import logging
          import cfnresponse
          import time
          from botocore.exceptions import ClientError

          def handler(event, context):
            logger = logging.getLogger()
            logger.setLevel(logging.INFO)
            logger.info (f"Input parameters from cloud formation: {event}")
            responseData = {}
            if (event["RequestType"] == 'Delete'):
              logger.info("Responding to delete event...")
              cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)

            try:            
              lambdaClient = boto3.client('lambda')
              s3Bucket = event['ResourceProperties']['S3Bucket']
              s3Key = event['ResourceProperties']['S3Key']
              functionName = event['ResourceProperties']['FunctionName']
              logger.info("Updating the function code for Lambda function '{}' to use the code stored in S3 bucket '{}' at key location '{}'".format(functionName, s3Bucket, s3Key))
              logger.info("Sleeping for 5 seconds to allow IAM permisisons to take effect")
              time.sleep(5)             
              response = lambdaClient.update_function_code(
                FunctionName=functionName,
                S3Bucket='{}'.format(s3Bucket),
                S3Key='{}'.format(s3Key),
                Publish=True)
              responseValue = "Function: {}, Version: {}, Last Modified: {}".format(response["FunctionName"],response["Version"],response["LastModified"])
              responseData['Data'] = responseValue
              cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, response["FunctionArn"])
            except ClientError as e:
              errorMessage = e.response['Error']['Message']
              logger.error(errorMessage)
              cfnresponse.send(event, context, cfnresponse.FAILED, responseData)
      Runtime: "python3.6"
      Timeout: "30"
  LambdaDeployFunctionExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: 
            Service: lambda.amazonaws.com
          Action: 
            - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
      - PolicyName: ReadS3BucketContainingLambdaCode
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action: 
              - s3:GetObject              
            Resource: ArnOfS3BucketContainingLambdaCode/*
      - PolicyName: UpdateCodeAndPublishVersion
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action: 
              - lambda:UpdateFunctionCode
              - lambda:PublishVersion
            Resource: '*'
Outputs:
  LambdaVersion:
    Value: !GetAtt LambdaDeploy.Version
  CustomResourceResult:
    Value: !GetAtt MyCustomResource.Result 

答案 6 :(得分:1)

不幸的是,使用CloudFormation无法做到这一点。您需要在CloudFormation模板中为每个版本添加新的AWS::Lambda::Version部分。

最接近的解决方案是创建.erb模板并让它生成包含所有版本的CloudFormation模板。

答案 7 :(得分:0)

  1. 我们可以制作一个Lambda部署包;
  2. 通过Lambda 将版本打包为Cloud Formation参数之一,例如 “LambdaPakcageNameWithVersion”;
  3. 使用 “LambdaPakcageNameWithVersion”作为Lambda代码的s3键;
  4. 新的 运行aws-cli命令时将部署Lamdba包 更新云形式堆栈或运行CI / CD管道。
  5.   MyLambda:
        Type: AWS::Lambda::Function
        Properties:
          Role: LambdaRole
          Code:
            S3Bucket: LambdaPackageS3Bucket
            S3Key: !Sub "${LambdaPakcageNameWithVersion}"
          FunctionName: LambdaFunctionName
          Handler: lambda_function.lambda_handler
          Runtime: python3.6
          Timeout: 60

答案 8 :(得分:0)

这有点麻烦,并且取决于使用gitlab-ci(或类似工具),但是我发现将提交哈希(通过模板的参数)传递到cloudformation模板中非常有用。

(有点像@Jerry的答案,但是使用提交哈希。)

在这种情况下,您可以执行以下操作:

您的模板中具有用于提交哈希的参数,例如:

$categories = get_the_category();

if ( ! empty( $categories ) ) {
    echo esc_html( $categories[0]->name );   
}

然后您可以在lambda资源中引用它,如下所示:

AWSTemplateFormatVersion: '2010-09-09'
Description: Template for Lambda Sample.
Parameters:
  ciCommitSha:
    Type: String
  s3Bucket:
    Type: String
  ...

您的ci管道然后需要看起来像(假设您将cloudformation模板称为stack-template.yaml):

  CFNLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: cfn_trigger_fn
      Description: lambda which gets triggered by cloudformation
      Runtime: python3.7
      Code:
        S3Bucket: !Ref s3Bucket
        S3Key: !Join [ ".", [ !Ref ciCommitSha, "zip"]]
      Handler: function.handler
      ...

您也可以使用此技术在EC2元数据上触发cfn-init。

答案 9 :(得分:0)

我使用CI / CD,一个蚂蚁脚本和git版本解决了这个问题,为每个提交在S3存储桶中创建了一个唯一的zip名称。

CI / CD调用ant脚本,以将git版本替换为lambda代码zip文件和cloudformation模板的名称。这些参考是在将代码和cloudformation脚本复制到S3之前进行的。这与SAM的工作方式类似,但是与简单的旧Cloudformation堆栈以及可能需要在多个帐户中部署的重要的堆栈集一起使用。在撰写本文时,SAM与CF堆栈集不兼容

有两个文件:ant文件和一个属性文件,该文件告诉ant文件要压缩哪个lambda源目录。

首先构建build.xml ant文件:

<project basedir="." name="AWS Lambda Tooling Bucket Zip" default="ziplambdas">
    <!-- this ant file is responsible for zipping up lambda source code that needs to be placed on an S3 bucket for deployment.
        It reads a file `lambda-zip-build.properties` that contains a list of lambda folders and the corresponding zip names.
        This allows a lambda to include source code and any required library packages into a single zip for deployment.
        For further information refer to the comments at the top of the zip properties file.
    -->

    <property name="ant.home" value="${env.ANT_HOME}" />
    <taskdef resource="net/sf/antcontrib/antlib.xml">
        <classpath path="${ant.home}/lib/ant-contrib-1.0b3.jar" />
    </taskdef>

    <!-- <available file=".git" type="dir" property="git.present"/> -->
    <available file="../../.git" type="dir" property="git.present"/>

    <!-- get the git revision to make a unique filename on S3. This allows the zip key to be replaced, forcing an update if CloudFormation is deployed. Clunky,
         AWS Support raised but advice was to use SAM, which is not compatible with StackSets ... *sigh* -->
    <target name="gitrevision" description="Store git revision in ${repository.version}" if="git.present">
        <exec executable="git" outputproperty="git.revision" failifexecutionfails="false" errorproperty="">
            <arg value="describe"/>
            <arg value="--tags"/>
            <arg value="--always"/>
            <arg value="HEAD"/>
        </exec>
        <condition property="repository.version" value="${git.revision}" else="unknown">
            <and>
                <isset property="git.revision"/>
                <length string="${git.revision}" trim="yes" length="0" when="greater"/>
            </and>
        </condition>
        <echo>git revision is ${git.revision} </echo>
    </target>

    <target name="replace.git.revision.in.files" depends="gitrevision" description="replace the git marker text in cloudformation files and zip properties file">
        <replace dir="." token="@git.revision@" value="${git.revision}" summary="yes"/>
    </target>

    <property file="lambda.zip.build.properties"/>

    <!-- zip the lambda code into a unique zip name based on the git revision -->
    <target name="ziplambdas" description="Create Zip files based on the property list" depends="replace.git.revision.in.files">
        <property file="lambda.zip.build.properties" prefix="zipme." />
        <propertyselector property="zip.list" match="^zipme\.(.*)" select="\1"/>

        <foreach list="${zip.list}" delimiter="," target="zip" param="folder"/>
    </target>

    <target name="zip">
        <propertycopy property="zip.path" from="${folder}" />
        <basename property="zip.file" file="${zip.path}" />
        <echo message="${folder} is being zipped to ${zip.path}"/>
        <zip destfile="${zip.path}">
            <zipfileset dir="${folder}">
               <exclude name="**/${zip.file}"/>
            </zipfileset> 
        </zip>
    </target>

</project>

lambda.zip.build.properties文件如下所示:

# This property file contains instructions for CI/CD Build Process to zip directories containing lambda code to place on the S3  bucket.
# Lambda source code when deployed by CloudFormation must be available inside a Zip file in a S3 bucket.
# CI/CD runs an ant task that reads this file to create the appropriate zip files referenced by the CloudFormation scripts. 
# 
# Each property key value pair below contains a key of the top level directory containing the lambda code (in python, javascript or whatever), 
# and a value of the path to the zip file that should be deployed to S3. The @git.revision@ tag is substituted with the actual git revision before copying to S3.
# This allows the lambda S3key to change for each deployment and forces a lambda code update. 
#
# for example: myproject/lambda/src=myproject/lambda/my-src-@git.revision@.zip
#              ^^ Directory    ^^ Zip File
#
###################################################################################################################################################################################
myproject/lambda/src=myproject/lambda/lambda-code-@git.revision@.zip
# place your key value pairs above here...

然后是CloudFormation模板:

Resources:
  MyLambda:
    Type: AWS::Lambda::Function
    Properties:
    # git.revision is placed when code is zipped up by CI/CD and placed on S3 bucket. It allows a unique name for each commit and thereby forces
    # lambda code to be replaced on cloudformation stackset redeployment.
      Code:
        S3Bucket: mybucket
        S3Key: myproject/lambda/lambda-code-@git.revision@.zip
      Handler: autotag-costcentre.lambda_handler
      MemorySize: 128
      Runtime: python3.7
      Timeout: 10
      .... etc

结果是一个具有唯一名称lambda-code-0f993c3.zip的zip文件和一个带有S3Key引用该唯一名称的Cloudformation模板。

S3Key: myproject/lambda/lambda-code-0f993c3.zip

从S3位置部署模板,这将强制每次刷新现有的lambda代码。

答案 10 :(得分:0)

为我工作以下内容:

"LambdaAlias": {
            "Type": "AWS::Lambda::Alias",
            "DeletionPolicy" : "Retain",
            "Properties": {
                "FunctionName": {
                    "Ref": "LambdaFunction"
                },
                "FunctionVersion": {
                    "Fn::GetAtt": ["LambdaVersion","Version"]
                },
                "Name": "MyAlias"
            }

答案 11 :(得分:0)

我对该文件夹进行校验和,并将其附加到 lambda 的 S3Key

- lambda_src_version=$(find ${Lambda1} -type f -print0  | xargs -0 sha1sum | sha1sum )
- lambda_src_version =$(echo ${lambda_src_version//[[:blank:]]/})
- export S3Key="lambda_functions/${stage}/cloudformation-${lambda_src_version}.zip"
- zip - -r . -x '*.git*' | aws s3 cp - s3://${S3Bucket}/${S3Key}
- sam deploy --template-file cloudformation.yml --stack-name XXX --parameter-overrides Lambda1Bucket=${S3Bucket} Lambda1CodeZip="${S3Key}"

// cloudformation.yml 片段

Parameters:      
  Lambda1CodeZip:
    Type: String
  Lambda1Bucket:
    Type: String 

Type: 'AWS::Lambda::Function'
    Properties: 
      Code:
        S3Bucket: !Sub ${Lambda1Bucket}
        S3Key: !Sub ${Lambda1CodeZip}