如何通过CloudFormation更新AWS Lambda函数代码而非替换函数
1. 理解问题根源
当你在SAM模板中指定FunctionName属性时,CloudFormation会把这个名称作为Lambda资源的唯一标识。如果该名称的函数已经存在(且不是当前CloudFormation栈创建的),CloudFormation会默认尝试创建新函数,自然就会触发“函数名已存在”的错误——它根本不知道要去更新现有函数,而是默认走创建流程。
要实现只更新代码不替换函数,核心是让CloudFormation正确识别并管理现有函数,或者绕开创建逻辑直接更新代码。
2. 方案一:将现有Lambda导入CloudFormation栈(推荐,规范持久化管理)
这是最标准的做法,让CloudFormation正式接管现有函数的生命周期,后续就能正常通过模板更新代码:
步骤1:匹配现有函数的模板配置
编写SAM模板时,确保FunctionName和现有函数完全一致,同时Runtime、Role、Handler等核心属性也和现有函数匹配,比如:AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Parameters: TargetLambdaName: Type: String Default: "MyExistingLambda" Resources: TargetLambda: Type: AWS::Serverless::Function Properties: FunctionName: !Ref TargetLambdaName Runtime: python3.9 Role: arn:aws:iam::123456789012:role/MyLambdaExecutionRole Handler: src/main.lambda_handler CodeUri: ./lambda-src/步骤2:创建导入变更集
用AWS CLI告诉CloudFormation要把现有函数导入到指定栈中:aws cloudformation create-change-set \ --stack-name MyLambdaManagementStack \ --change-set-name ImportExistingLambda \ --change-set-type IMPORT \ --resources-to-import "[{\"ResourceType\":\"AWS::Lambda::Function\",\"LogicalResourceId\":\"TargetLambda\",\"ResourceIdentifier\":{\"FunctionName\":\"MyExistingLambda\"}}]" \ --template-body file://template.yaml步骤3:执行变更集完成导入
确认变更集内容无误后,执行它完成导入:aws cloudformation execute-change-set \ --stack-name MyLambdaManagementStack \ --change-set-name ImportExistingLambda步骤4:正常更新代码
之后就可以用常规的打包+部署流程更新代码了:# 打包代码到S3 aws cloudformation package \ --template-file template.yaml \ --s3-bucket my-deployment-bucket \ --output-template-file packaged.yaml # 部署更新 aws cloudformation deploy \ --template-file packaged.yaml \ --stack-name MyLambdaManagementStack \ --parameter-overrides TargetLambdaName=MyExistingLambda此时CloudFormation会对比打包后的S3代码路径,只要代码有更新,就会自动替换现有Lambda的代码包,不会触发函数替换。
3. 方案二:直接用CLI更新代码(适合临时快速更新)
如果不想让CloudFormation接管整个函数,只是临时更新代码,可以跳过模板部署,直接用AWS CLI操作:
步骤1:打包代码获取S3路径
先通过package命令把代码上传到S3,并从输出的模板中提取代码包的S3路径:aws cloudformation package \ --template-file template.yaml \ --s3-bucket my-deployment-bucket \ --output-template-file packaged.yaml打开
packaged.yaml,找到CodeUri对应的S3地址(比如s3://my-deployment-bucket/abc123/lambda-code.zip)。步骤2:直接更新Lambda代码
用CLI命令把S3上的代码包更新到现有函数:aws lambda update-function-code \ --function-name MyExistingLambda \ --s3-bucket my-deployment-bucket \ --s3-key abc123/lambda-code.zip
4. 关键注意事项
- 方案一中,后续不要修改
Runtime、Role、FunctionName这类会触发资源替换的属性,除非你确实需要替换函数。只要这些属性和现有函数一致,CloudFormation只会更新代码。 - 方案二虽然快捷,但无法通过CloudFormation跟踪函数的配置变更,适合临时的代码迭代场景。
内容的提问来源于stack exchange,提问作者Phoenix

