Cloudformation Elasticbeanstalk 指定共享负载均衡器的目标组

Posted

技术标签:

【中文标题】Cloudformation Elasticbeanstalk 指定共享负载均衡器的目标组【英文标题】:Cloudformation Elasticbeanstalk specify target group for shared load balancer 【发布时间】:2021-07-23 02:59:23 【问题描述】:

我有两个 Cloudformation 模板

一个创建 VPC、ALB 和任何其他共享资源等的工具。 创建弹性 beanstalk 环境和相关侦听器规则以使用导入的共享负载平衡器将流量定向到此环境(调用此模板Environment

我面临的问题是Environment 模板创建了一个AWS::ElasticBeanstalk::Environment,该模板随后创建了一个新的CFN 堆栈,其中包含诸如ASG 和目标组(或弹性beantalk 已知的进程)之类的东西。这些资源不是用于创建环境的 AWS 拥有的 CFN 模板的输出。

设置时

- Namespace: aws:elasticbeanstalk:environment
  OptionName: LoadBalancerIsShared
  Value: true

在我的弹性 beanstalk 环境的选项设置中,没有创建负载均衡器,这很好。然后,我尝试将侦听器规则附加到我的负载均衡器侦听器。

  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Priority: 1
      ListenerArn:
        Fn::ImportValue: !Sub '$NetworkStackName-HTTPS-Listener'
      Actions:
        - Type: forward
          TargetGroupArn: WHAT_GOES_HERE
      Conditions:
        - Field: host-header
          HostHeaderConfig:
            Values:
              - mywebsite.com
    DependsOn:
      - Environment

这里的问题是,据我所知,我无权访问由弹性 beanstalk 环境资源创建的目标组的 ARN。如果我创建了一个目标组,那么它不会链接到弹性豆茎并且不存在任何实例。

我找到了this page 声明

Elastic Beanstalk 为您的环境创建的资源具有名称。您可以使用这些名称通过函数获取有关资源的信息,或修改资源的属性以自定义其行为。

但是因为它们在不同的堆栈中(我事先不知道它的名称),而不是模板的输出,所以我不知道如何获取它们。

--

编辑:

Marcin 在他们的回答中向我指出了自定义资源的方向。我稍微扩展了它并让它工作。实现方式在几个方面略有不同

    它在 Node 而不是 Python 中 提供的示例中的 api 调用 describe_environment_resources 返回资源列表,但似乎不是全部。在我的实现中,我抓取了 Auto Scaling 组,并使用物理资源 ID 通过 Cloudformation API 在堆栈中查找它所属的其他资源。
const AWS = require('aws-sdk');
const cfnResponse = require('cfn-response');
const eb = new AWS.ElasticBeanstalk();
const cfn = new AWS.CloudFormation();

exports.handler = (event, context) => 
    if (event['RequestType'] !== 'Create') 
        console.log(event[RequestType], 'is not Create');
        return cfnResponse.send(event, context, cfnResponse.SUCCESS, 
            Message: `$event['RequestType'] completed.`,
        );
    

    eb.describeEnvironmentResources(
         EnvironmentName: event['ResourceProperties']['EBEnvName'] ,
        function (err,  EnvironmentResources ) 
            if (err) 
                console.log('Exception', e);
                return cfnResponse.send(event, context, cfnResponse.FAILED, );
            

            const PhysicalResourceId = EnvironmentResources['AutoScalingGroups'].find(
                (group) => group.Name
            )['Name'];

            const  StackResources  = cfn.describeStackResources(
                 PhysicalResourceId ,
                function (err,  StackResources ) 
                    if (err) 
                        console.log('Exception', e);
                        return cfnResponse.send(event, context, cfnResponse.FAILED, );
                    
                    const TargetGroup = StackResources.find(
                        (resource) =>
                            resource.LogicalResourceId === 'AWSEBV2LoadBalancerTargetGroup'
                    );

                    cfnResponse.send(event, context, cfnResponse.SUCCESS, 
                        TargetGroupArn: TargetGroup.PhysicalResourceId,
                    );
                
            );
        
    );
;

Cloudformation 模板

  LambdaBasicExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSCloudFormationReadOnlyAccess
        - arn:aws:iam::aws:policy/AWSElasticBeanstalkReadOnly
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  GetEBLBTargetGroupLambda:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Description: 'Get ARN of EB Load balancer'
      Timeout: 30
      Role: !GetAtt 'LambdaBasicExecutionRole.Arn'
      Runtime: nodejs12.x
      Code:
        ZipFile: |
          ... code ...
  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Priority: 1
      ListenerArn:
        Fn::ImportValue: !Sub '$NetworkStackName-HTTPS-Listener'
      Actions:
        - Type: forward
          TargetGroupArn:
            Fn::GetAtt: ['GetEBLBTargetGroupResource', 'TargetGroupArn']
      Conditions:
        - Field: host-header
          HostHeaderConfig:
            Values:
              - mydomain.com

我在做这件事时学到的东西,希望能帮助别人

    在 Node 中使用 async 处理程序很困难,因为默认的 cfn-response 库不是异步的,会导致 Cloudformation 创建(和删除)过程在回滚前挂起数小时。 如果您使用ZipFile,cloudformation 会自动包含cfn-response 库。如果您倾向于手动包含该代码(您也可以将其包装在一个 Promise 中并使用异步 lambda 处理程序),则该代码可在 AWS Docs 上找到。 npm 上也有包可以达到同样的效果。 节点 14.x 无法运行,Cloudformation 出现错误。很遗憾,我没有记下它是什么。 提供的示例中使用的策略AWSElasticBeanstalkFullAccess 已不存在,已替换为AdministratorAccess-AWSElasticBeanstalk。 我上面的示例需要较少的许可策略,但我还没有在我的测试中解决这个问题。如果它只能读取特定的弹性豆茎环境等就更好了。

【问题讨论】:

【参考方案1】:

据我所知,我无权访问由弹性 beanstalk 环境资源创建的目标组的 ARN

确实如此。克服这个问题的方法是通过custom resource。事实上,我为我的previous answers 之一开发了完全可用的、非常相似的资源,因此您可以查看它并采用您的模板。该资源返回 EB 负载均衡器的 ARN,但您可以修改它以获取 EB 目标组的 ARN。

【讨论】:

非常感谢这是一个很好的起点。我现在在我的问题中已经解决了一些差异。我打算将它放入您的答案而不是问题,但我认为我最好先问。再次感谢 查看我的代码,我想您可能不知道为什么我的自定义资源没有正确删除?据我所知,lambda 没有对 cloudformation 做出适当的响应,然后最终超时(几个小时),然后堆栈的其余部分删除并留下自定义资源。

以上是关于Cloudformation Elasticbeanstalk 指定共享负载均衡器的目标组的主要内容,如果未能解决你的问题,请参考以下文章

VPC 内部的 CloudFormation?

扩大 Cloudformation 模板

Cloudformation + OpsWorks

SAM 模板和 Cloudformation 模板的区别

CloudFormation 嵌套堆栈名称

CloudFormation 的超时配置