如何通过CloudFormation在现有Elastic Beanstalk环境创建并部署新版本
解决方案:用CloudFormation管理现有Elastic Beanstalk应用版本部署
核心问题分析
- 应用版本更新无变更集:
AWS::ElasticBeanstalk::ApplicationVersion资源仅当SourceBundle的S3Key变化时,才会被CloudFormation识别为需要更新的资源。如果每次部署用同一个S3文件名,CloudFormation会认为没有变更,不会生成新版本。 - 现有环境无法纳入栈:直接在模板中定义
AWS::ElasticBeanstalk::Environment会触发新环境创建,导致冲突。需要用导入资源或自定义资源的方式关联现有环境。
方法一:将现有环境导入CloudFormation栈(推荐)
这种方式能让CloudFormation完全管理环境的版本更新,步骤如下:
1. 准备匹配现有环境的模板
确保模板中myEnvironment的所有属性和现有环境完全一致(比如SolutionStackName、环境变量、实例配置等),示例模板:
Resources: myAppVersion: Type: AWS::ElasticBeanstalk::ApplicationVersion Properties: ApplicationName: app-ebs SourceBundle: S3Bucket: my-bucket-name S3Key: sample-v1.war # 每次部署修改这里的文件名(比如加版本号/哈希) VersionLabel: !Sub "app-version-${AWS::StackName}-${AWS::Timestamp}" # 自动生成唯一版本标签 myEnvironment: Type: AWS::ElasticBeanstalk::Environment Properties: ApplicationName: app-ebs EnvironmentName: App-ebs-env VersionLabel: !Ref myAppVersion SolutionStackName: 64bit Amazon Linux 2 v4.3.12 running Tomcat 8.5 Corretto 8 # 补充现有环境的其他属性,比如环境变量、InstanceType等,必须和现有环境一致
2. 导入现有环境到栈
- 打开CloudFormation控制台,选择目标栈,点击导入资源
- 选择
AWS::ElasticBeanstalk::Environment类型,输入现有环境名称App-ebs-env - 按照向导完成导入,确保模板属性和现有环境匹配,无冲突
3. 后续部署流程
每次部署新包时:
- 将新的WAR包上传到S3,使用新的文件名(比如
sample-v2.war) - 更新模板中的
S3Key为新文件名 - 执行CloudFormation更新栈操作,此时会自动创建新的应用版本,并将现有环境更新到该版本
方法二:用Lambda自定义资源更新现有环境(无需导入)
如果不想将环境纳入CloudFormation管理,可以用Lambda函数调用Elastic Beanstalk API来更新环境版本:
1. 完整模板示例
Resources: myAppVersion: Type: AWS::ElasticBeanstalk::ApplicationVersion Properties: ApplicationName: app-ebs SourceBundle: S3Bucket: my-bucket-name S3Key: sample-v1.war # 每次部署修改文件名 VersionLabel: !Sub "app-version-${AWS::StackName}-${AWS::Timestamp}" UpdateEnvLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: UpdateEBSEnvironment PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - elasticbeanstalk:UpdateEnvironment Resource: !Sub "arn:aws:elasticbeanstalk:${AWS::Region}:${AWS::AccountId}:environment/app-ebs/App-ebs-env" - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*" UpdateEnvLambda: Type: AWS::Lambda::Function Properties: Runtime: python3.11 Role: !GetAtt UpdateEnvLambdaRole.Arn Handler: index.lambda_handler Code: ZipFile: | import boto3 import cfnresponse def lambda_handler(event, context): eb_client = boto3.client('elasticbeanstalk') try: if event['RequestType'] in ['Create', 'Update']: version_label = event['ResourceProperties']['VersionLabel'] eb_client.update_environment( ApplicationName='app-ebs', EnvironmentName='App-ebs-env', VersionLabel=version_label ) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) except Exception as e: print(f"Error: {str(e)}") cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)}) UpdateEnvironmentResource: Type: Custom::UpdateEBSEnvironment Properties: ServiceToken: !GetAtt UpdateEnvLambda.Arn VersionLabel: !Ref myAppVersion
2. 部署流程
- 每次上传新WAR包到S3,修改模板中的
S3Key - 更新CloudFormation栈,此时会创建新的应用版本,触发Lambda函数调用API更新现有环境到新版本
关键注意事项
- 唯一版本标识:每次部署必须修改
S3Key,或者显式指定唯一的VersionLabel,否则CloudFormation不会创建新的应用版本 - 权限配置:方法二中的Lambda角色必须拥有
elasticbeanstalk:UpdateEnvironment权限,且资源范围限定到目标环境 - 环境属性匹配:方法一中导入环境时,模板属性必须和现有环境完全一致,否则导入会失败
内容的提问来源于stack exchange,提问作者Chuck
相关产品推荐
相关产品推荐

