CloudFormation Wait Condition基于ELB的In-Service主机

时间:2017-02-06 09:08:05

标签: amazon-web-services amazon-elb amazon-cloudformation

任何人都有以下任何例子(首选窗口),

目前我有一个CF模板,它创建了我的AutoScaling组,LoadBalancer以及ELB下健康主机上的一些警报,并正在工作,

我想要做的是在创建警报之前有一个等待条件,这样只有在主机被标记为“服务中”但ELB时才会创建警报。

我知道如何让等待条件正常工作但是我无法弄清楚如何根据ELB下的“使用中”状态让它工作。

任何人都有任何建议或例子吗?我一直在网上搜索一些例子,但除了通常的AWS文档页面和其他一些例外,我还没找到我需要的东西。

我确实找到了一个关于如何验证实例运行状况的片段 - 但我无法弄清楚是否或如何将其用于等待条件。

verify_instance_health:
commands:
ELBHealthCheck:
command: !Sub
'until ; do state=$(aws --region ${AWS::Region} elb describe-instance-health
--load-balancer-name ${ElasticLoadBalancer}
--instances $(curl -s http://169.254.169.254/latest/meta-data/instance-id)
--query InstanceStates[0].State); sleep 10; done'

干杯

1 个答案:

答案 0 :(得分:0)

您可以使用Custom Resource使用DescribeInstanceHealth API监控实例来完成此操作,在EC2实例达到InService状态时完成(例如,使用instanceInService waiter来自AWS SDK for JavaScript)。

这是一个完整的示例,使用cfn-init在EC2实例上配置nginx,在TCP端口80上添加ELB运行状况检查,以及等待EC2的自定义资源InService在完成堆栈之前,实例在ELB中为InService

Launch Stack

Description: Wait until instance enters the InService state.
Parameters:
  ImageId:
    Description: Image ID to launch EC2 instances.
    Type: AWS::EC2::Image::Id
    # amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
    Default: ami-9be6f38c
  InstanceType:
    Description: Instance type to launch EC2 instances.
    Type: String
    Default: m3.medium
    AllowedValues: [ m3.medium, m3.large, m3.xlarge, m3.2xlarge ]
  AvailabilityZones:
    Description: Availability Zones for ELB.
    Type: List<AWS::EC2::AvailabilityZone::Name>
Resources:
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow inbound traffic from Load Balancer
  SecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      FromPort: 80
      ToPort: 80
      GroupName: !Ref InstanceSecurityGroup
      SourceSecurityGroupName: !GetAtt LoadBalancer.SourceSecurityGroup.GroupName
      SourceSecurityGroupOwnerId: !GetAtt LoadBalancer.SourceSecurityGroup.OwnerAlias
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      SecurityGroups: [!Ref InstanceSecurityGroup]
      UserData:
        "Fn::Base64": !Sub |
          #!/bin/bash
          /opt/aws/bin/cfn-init -v \
            --stack ${AWS::StackName} \
            --region ${AWS::Region} \
            --resource Instance
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages: {yum: {nginx: []}}
          services:
            sysvinit:
              nginx:
                enabled: true
                ensureRunning: true
                files: [/etc/nginx/nginx.conf]
                sources:
                - /usr/share/nginx/html
                - /etc/nginx/conf.d
                - /etc/nginx/default.d
  LoadBalancer:
    Type: AWS::ElasticLoadBalancing::LoadBalancer
    Properties:
      AvailabilityZones: !Ref AvailabilityZones
      Listeners:
      - LoadBalancerPort: 80
        InstancePort: 80
        Protocol: HTTP
      Instances: [!Ref Instance]
      HealthCheck:
        Target: TCP:80
        HealthyThreshold: 2
        UnhealthyThreshold: 5
        Interval: 5
        Timeout: 2
  InService:
    Type: Custom::InService
    Properties:
      ServiceToken: !GetAtt InServiceFunction.Arn
      Instances:
      - InstanceId: !Ref Instance
      LoadBalancerName: !Ref LoadBalancer
  InServiceFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          var AWS = require('aws-sdk');
          exports.handler = (event, context) => {
            console.log("Request received:\n", JSON.stringify(event));
            var physicalId = event.PhysicalResourceId || 'none';
            var success = data => response.send(event, context, response.SUCCESS, data, physicalId);
            var failed = e => response.send(event, context, response.FAILED, e, physicalId);
            if (event.RequestType == 'Create') {
              var elb = new AWS.ELB();
              var elbParams = event.ResourceProperties;
              delete elbParams.ServiceToken;
              elb.waitFor('instanceInService', elbParams).promise().
                then((data)=> success({}), (e)=> failed(e));
            } else {
              success({});
            }
          };
      Runtime: nodejs4.3
      Timeout: 300
  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: ELBPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
              - 'elasticloadbalancing:DescribeInstanceHealth'
              Resource: ['*']
Outputs:
  URL:
    Value: !Sub "http://${LoadBalancer.DNSName}"