如何从 CloudFormation 中的 Elastic Beanstalk 环境中提取负载均衡器名称

Posted

技术标签:

【中文标题】如何从 CloudFormation 中的 Elastic Beanstalk 环境中提取负载均衡器名称【英文标题】:How To Extract Load Balancer Name from Elastic Beanstalk Environment in CloudFormation 【发布时间】:2019-01-24 14:54:23 【问题描述】:

我使用以下代码 sn-p 在 CloudFormation 中创建了 Elastic Beanstalk 和 CloudWatch 警报:

        "ElasticBeanstalkEnvironment": 
        "Type": "AWS::ElasticBeanstalk::Environment",
        "Properties": 
            "ApplicationName": "my-app",
            "EnvironmentName": "my-eb",
            "SolutionStackName": "64bit Amazon Linux 2018.03 v3.0.1 running Tomcat 8 Java 8",
            "OptionSettings": [
                
                    "Namespace": "aws:elb:loadbalancer",
                    "OptionName": "CrossZone",
                    "Value": "true"
                ,
                
                    "Namespace": "aws:elb:listener:80",
                    "OptionName": "ListenerProtocol",
                    "Value": "HTTP"
                ,
                
                    "Namespace": "aws:elb:listener:80",
                    "OptionName": "InstancePort",
                    "Value": "80"
                ,
                etc...
            ]
        ,
        "CloudWatchBacken500XXAlarm": 
            "Type": "AWS::CloudWatch::Alarm",
            "Properties" : 
                "AlarmActions": ["arn:aws:sns:us-east-1:12345678:mysnstopic"],
                "Namespace": "AWS/ELB",
                "Dimensions": [
                    "Name": "LoadBalancerName",
                    "Value" : 
                        "Fn::GetAtt": [
                            "ElasticBeanstalkEnvironment",
                            "EndpointURL"  
                        ]
                    
                  ],
                "MetricName": "HTTPCode_Backend_5XX",
                "Statistic": "Sum",
                "Period": "60",
                "EvaluationPeriods": "1",
                "ComparisonOperator": "GreaterThanOrEqualToThreshold",
                "Threshold": "1"
                
        

您可以看到 CloudWatch 警报配置为在 Elastic Beanstalk 的负载均衡器收到 5XX 错误时发出警报。但是我无法获得看起来像这样的负载均衡器名称属性:

awseb-e-a-AWSEBLoa-AY8LC6V30OAW

取而代之的是 Fn::GetAtt("EndpointURL") 属性返回负载均衡器的 DNSName,它看起来像这样:

awseb-e-a-AWSEBLoa-AY8LC6V30OAW-175133046.us-east-1.elb.amazonaws.com

这将无法正确创建 CloudWatch 警报,因为它期望获取负载均衡器名称而不是 DNSName。

获取负载均衡器名称的最佳方法是什么?我不想将负载均衡器创建为外部资源,例如“AWS::ElasticLoadBalancing::LoadBalancer”,或者尝试使用一些子字符串方法从 DNSName 字符串中提取名称字符串。

【问题讨论】:

【参考方案1】:

如果您有权访问环境名称,则可以执行DescribeEnvironmentResources API 调用。响应将包含有关您环境的负载均衡器的信息。

【讨论】:

他如何将 api 调用集成到 cloudformation 中?【参考方案2】:

好的,我找到了一个解决方案,它完全是 hack,我已经能够使用从 - Fn::GetAtt("EndpointURL") 返回的 DNSName 字符串上的多个 Split/Select/Join 调用从端点提取 LoadBalancerName。这是代码:

"CloudWatchBackend500XXAlarm": 
"Type": "AWS::CloudWatch::Alarm",
"Properties" : 
    "AlarmDescription": "Elastic Beanstalk Has Received 5XX Backend Connection Errors",
    "AlarmActions": ["arn:aws:sns:us-east-1:1234567890:mysnstopic"],
    "Namespace": "AWS/ELB",
    "Dimensions": [
        
            "Name": "LoadBalancerName",
            "Value": 
                "Fn::Join": ["", [
                    "Fn::Select": [
                        "0",
                        
                            "Fn::Split": ["AWSEBLoa-",
                                
                                    "Fn::GetAtt": [
                                        "ElasticBeanstalkEnvironment",
                                        "EndpointURL"
                                    ]
                                
                            ]
                        
                    ]
                ,
                "AWSEBLoa-",
                
                    "Fn::Select": [
                        "0",
                        
                            "Fn::Split": ["-",
                                
                                    "Fn::Select": [
                                        "1",
                                        
                                            "Fn::Split": ["AWSEBLoa-",
                                                
                                                    "Fn::GetAtt": [
                                                        "ElasticBeanstalkEnvironment",
                                                        "EndpointURL"
                                                    ]
                                                
                                            ]
                                        
                                    ]
                                
                            ]
                        
                    ]
                
            ]]
        
        
    ],                  
    "MetricName": "HTTPCode_Backend_5XX",
    "Statistic": "Sum",
    "Period": "60",
    "EvaluationPeriods": "1",
    "ComparisonOperator": "GreaterThanOrEqualToThreshold",
    "Threshold": "1"

即上面的代码能够从“awseb-k-3-AWSEBLoa-11B26NY4PQB9A-739614614.us-east-1.elb.amazonaws.com”和CloudWatch 警报完美运行。我想我必须调整代码以使用内部负载平衡器,即在 DNSName 的开头使用“internal-”格式化,但我现在很好。

我已经向 AWS 提交了一个请求,要求他们添加一个 CloudFormation 方法来返回 LoadBalancer 名称,而不仅仅是 DNSName。

【讨论】:

【参考方案3】:

使用 ebextensions 会更容易创建警报 - 因为获取 ELB 名称就像 Value: "Ref" : "AWSEBLoadBalancer"

创建一个扩展名为 .config 的文件(比如 BackendErrors.config),并将其放在一个名为“.ebextensions”的文件夹中。完整的ebextension如下:

Resources:
  CloudWatchBacken500XXAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: "Elastic Beanstalk Has Received 5XX Backend Connection Errors"
      AlarmName:  "Fn::Join" : ["", [ "Ref" : "AWSEBEnvironmentName" , "-Backend-5XX-Alarm." ]]
      AlarmActions:
        - "arn:aws:sns:us-east-1:123456789012:mysnstopic"
      Namespace: AWS/ELB
      Dimensions:
        - Name: LoadBalancerName
          Value:  "Ref" : "AWSEBLoadBalancer" 
      MetricName: HTTPCode_Backend_5XX
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 1
      ComparisonOperator: GreaterThanOrEqualToThreshold

.ebextensions 文件夹应该在您的应用程序源包的顶层创建:

~/workspace/my-application/
|-- .ebextensions
|   |-- BackendErrors.config

【讨论】:

【参考方案4】:

几年后来到这里,亚马逊现在似乎添加了该属性:

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html

引用:

LoadBalancerFullName

负载均衡器的全名。例如,app/my-load-balancer/50dc6c495c0c9188。

所以你现在可以这样做了:

  Dimensions:
    - Name: LoadBalancer
      Value: !GetAtt YourALBRef.LoadBalancerFullName

【讨论】:

问题是如何提取 Elastic Beanstalk 创建的负载均衡器 ARN。【参考方案5】:

如果上面的代码的作用不明显: 它提取 -xxxxxxxx.region.elb.amazonaws.com 之前的名称部分

这对于经典负载均衡器来说已经足够了,因为它们只有一个名称,而 Cloudwatch 能够通过它们的名称来监控这些负载均衡器。

对于应用程序负载均衡器,情况就不同了: ApplicationLoadbalancers 除了他们的名字之外,他们确实有自己的arn,格式为:

arn:aws:elasticloadbalancing:REGION:ACCOUNT:loadbalancer/XXXXX/my-load-balancer/DDDDDDDD

XXXXX 是一个区域相关的字符串(我在我们找到 application,在欧洲找到 app)和 DDDDDDDD 是任意数字。

Cloudwatch 需要这个 loadBalancerFullName 来监控这个 LB。 很遗憾,如果你有一个应用程序负载均衡器,你就不能使用这个技巧。

【讨论】:

以上是关于如何从 CloudFormation 中的 Elastic Beanstalk 环境中提取负载均衡器名称的主要内容,如果未能解决你的问题,请参考以下文章

如何将 RDS 快照恢复到 cloudformation?

从 CloudFormation 模板中的 DropDownList 中选择多个值

AWS CloudFormation:如何从另一个AWS账户为Lambda代码指定存储桶?

从 lambda 函数中检索 cloudformation 堆栈名称

如何指定安全组中的所有端口 - CloudFormation

如何从无服务器 cli 设置 Cloudformation 完全访问权限