bor*_*ris 34 amazon-web-services aws-cloudformation aws-lambda
我正在尝试使用CloudFormation创建一个新版本的Lambda函数.
我想拥有相同Lambda函数的多个版本,以便我可以(a)指向不同版本的别名 - 比如DEV和PROD - 以及(b)能够回滚到早期版本
这是我的Lambda版本的定义:
LambdaVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName:
Ref: LambdaFunction
Run Code Online (Sandbox Code Playgroud)
运行"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团队,如果您正在阅读此内容 - 这是不可接受的.修理它.
Rob*_*ers 21
我有一个类似的用例(需要使用CloudFormation来管理在CloudFront中使用@edge的lambda函数,对于该函数,总是需要特定的lambda函数版本而不是$LATEST)并且我的搜索首先让我得到这个问题,但是更多挖掘我很高兴地发现现在支持自动lambda版本化,具有AutoPublishAliasAWS无服务器应用程序模型的新功能(基本上是CloudFormation模板的一组可选的更高级别构造).
在此公布:https://github.com/awslabs/serverless-application-model/issues/41#issuecomment-347723981
详情见:
基本上你AutoPublishAlias在你的AWS::Serverless::Function定义中包括:
MyFunction:
Type: "AWS::Serverless::Function"
Properties:
# ...
AutoPublishAlias: MyAlias
Run Code Online (Sandbox Code Playgroud)
然后在CloudFormation模板的其他位置,您可以将最新发布的版本作为!Ref MyFunction.Version(yaml语法)引用.
Çağ*_*ürk 18
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"
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
(免责声明:此代码是我的书的一部分,有关Lambda和API Gateway的更多信息,请查看:https://www.amazon.com/Building-Serverless-Architectures-Cagatay-Gurturk/dp/1787129195)
小智 15
这个帖子已经过时了。我在这里更新它,以便其他人可以看到截至 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
Run Code Online (Sandbox Code Playgroud)
变成这样:
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
Run Code Online (Sandbox Code Playgroud)
在Transform:允许AWS::Serverless::Function这反过来又支持拉姆达版本一个CloudFormation模板内。
不要让上面过时的“最佳答案” - 专为该人的书而设计 - 像我一样把你扔进兔子洞。
别客气。
wjo*_*dan 10
该AWS::Lambda::Version资源仅代表单个已发布的Lambda函数版本 - 它不会在每次更新代码时自动发布新版本.要实现此目的,您有两种选择:
您可以实现自己的自定义资源,以调用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
Run Code Online (Sandbox Code Playgroud)
您可以使用模板预处理器(如嵌入式Ruby)(或者只是在每次部署时手动更新模板),在代码更新时通过更改AWS::Lambda::Version资源的逻辑ID,在每次更新代码时发布新版本.
例:
# 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
Run Code Online (Sandbox Code Playgroud)
要在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
Run Code Online (Sandbox Code Playgroud)
答案更新于2018年2月
您可以使用AWS SAM(无服务器应用程序模型),它sam package和sam deploy命令来更新LAMBDA.它们aws cloudformation package与aws cloudformation deploy命令类似,但也允许您自动更新Lambda版本.
SAM可以打包您的代码(或者使用您创建的ZIP包),将其上传到S3,然后$LATEST从中更新Lambda 的版本.(如果这就是你所需要的,也可以在aws cloudformation没有SAM的情况下完成;代码示例与下面相同,但仅使用CloudFormation标准声明).然后,使用SAM,如果进行了相应配置,您还可以自动发布版本并更新别名以指向它.它还可以选择使用AWS CodeDeploy逐渐将流量从先前版本移动到新版本,并在出现错误时回滚.所有这些都在Safe Lambda部署中进行了解释.
从技术上说,这个想法是,每次更新堆栈,你需要你AWS::Lambda::Function的Code指向新的S3包.这将确保在更新堆栈时,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
...
Run Code Online (Sandbox Code Playgroud)
跑:
$ sam package --template-file template.yaml --output-template-file packaged.yaml --s3-bucket my-bucket
Run Code Online (Sandbox Code Playgroud)
这将源目录内容打包为ZIP(如果Code不是ZIP),在新的自动生成密钥下将其上传到S3,并生成最终的CloudFormation模板packaged.yaml,为您提供正确的Code引用; 像这样:
...
MyFunction:
Properties:
Code:
S3Bucket: my-bucket
S3Key: ddeeaacc44ddee33ddaaee223344
...
Run Code Online (Sandbox Code Playgroud)
现在您可以使用packaged.yamlSAM 生成,来创建函数版本:
sam deploy --template-file packaged.yaml --stack-name my-stack [--capabilities ...]
Run Code Online (Sandbox Code Playgroud)
这将更新Lambda的$LATEST版本,如果AutoPublishAlias已定义,则将其作为新版本发布,并更新Alias以指向新发布的版本.
有关完整的模板代码,请参阅SAM GitHub仓库中的示例.
正在寻找与从 S3 部署的 Lambda 函数配合使用的类似功能。
我的用例是这样的:
对此不满意,我寻找替代方案并遇到了这个问题。没有一个答案完全适合我,所以我采取了一些想法并改编了这里的答案,并用 Python 编写了我自己的版本。
这段代码改编自 @wjordan 的答案,因此这个想法和原始答案归功于他。差异是:
您需要一个随机数参数。当代码需要重新发布到 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21132 次 |
| 最近记录: |