Setting Up a Load Balancer, Target Group, and Auto Scaling Group on AWS

Load balancing, auto-scaling, and fault tolerance are key components for high availability and performance in modern web infrastructures. AWS provides built-in tools for this, mainly through Elastic Load Balancing (ELB) and Auto Scaling Groups (ASG). In this article, we will walk through the process of setting up a load balancer, target group, and an auto-scaling group on AWS.

Elastic Load Balancer (ELB)

What is it?

ELB automatically distributes incoming application traffic across multiple targets, such as EC2 instances, containers, and IP addresses, in one or more Availability Zones.

How does it help?

Why use it?


Target Groups

What is it?

When configuring a load balancer, you direct the traffic to a target group. The target group routes requests to one or more registered targets based on the health of the targets.

How does it help?

Why use it?


Auto Scaling Groups (ASG)

What is it?

Auto Scaling helps maintain application availability and allows you to scale Amazon EC2 capacity up or down automatically according to conditions you define.

How does it help?

Why use it?


Step-by-step Guide

1. Set Up an Elastic Load Balancer (ELB)

a. Open the AWS Management Console.

b. Navigate to EC2 > Load Balancers.

c. Click Create Load Balancer.

d. Choose your desired type (Application or Network). For this guide, we'll choose Application Load Balancer.

e. Configure Load Balancer settings:

f. Configure Availability Zones by selecting the VPC and the subnets.

g. Click Next.

2. Configure Security Settings

If you added an HTTPS listener, you'd configure SSL certificate details here. Otherwise, proceed to the next step.

3. Configure Security Groups

Select a security group that allows incoming HTTP/HTTPS traffic.

4. Configure Routing (Target Group)

a. Name: Give a unique name to your target group.

b. Target type: Choose "instance".

c. Protocol: HTTP.

d. Port: 80.

e. Health checks: Default is /index.html, but you can adjust as needed.

5. Register Targets

Skip this step for now, as we will register targets via the Auto Scaling Group.

6. Create the Load Balancer.

7. Set Up an Auto Scaling Group (ASG)

a. Navigate to EC2 > Auto Scaling Groups.

b. Click Create Auto Scaling group.

c. Choose Launch Template or Launch Configuration. For this guide, we'll use Launch Configuration.

d. Configure:

e. Configure details like IAM role, monitoring, and advanced details if needed.

f. Configure storage.

g. Configure security groups.

h. Review and create launch configuration.

i. Now, configure the ASG details:

j. Configure scaling policies as needed.

k. Configure Notification and Tags if needed.

l. In Advanced settings, you can configure:

m. Review and Create Auto Scaling group.

n. Once created, edit the ASG and associate the target group under Load balancing.

8. Review and Test

a. Navigate back to Load Balancers and select the one you created.

b. Under the Monitoring tab, you can see traffic and request metrics.

c. Test the load balancer's DNS to ensure it routes traffic to your instances.

Get cloudformation template here

AWSTemplateFormatVersion: '2010-09-09'
Description: Ec2 with load balancer, tg, and asg.

## Parameters
Parameters:
  EC2InstanceSize:
    Default: "t3.micro"
    Description: Instance size for Web Servers.
    Type: String
    AllowedValues:
      - "t3.micro"
      - "t3.small"
      - "t3.medium"
  AllowedIP:
    Description: IPs allowed to connect to load balancer.
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    Type: String
    Default: 0.0.0.0/0
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: Select a VPC for the instance
    Default: vpc-0c130bf7bc1cdfe53
  LoadBalancerSubnetId:
    Type: List<AWS::EC2::Subnet::Id>
    Description: Select a subnet for the load balancer
    Default: subnet-0b3f26e7665831ca4,subnet-05c54afa0760dd5bb
  EC2SubnetId:
    Type: List<AWS::EC2::Subnet::Id>
    Description: Select a subnet for the instance
    Default: subnet-0b3f26e7665831ca4,subnet-05c54afa0760dd5bb
  ImageId:
    Type: String
    Description: ID of the AMI to use for the instance
    Default: ami-01a3d71f30b1cf898
  ArtifactsBucket:
    Description: S3 bucket with artifact files (Lambda functions, templates, html files, etc.). Leave default.
    Type: String
    Default: ee-assets-prod-us-east-1
    AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$
    ConstraintDescription: ArtifactsBucket S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-).
      It cannot start or end with a hyphen (-).
  ArtifactsPrefix:
    Description: Path in the S3 bucket containing artifact files. Leave default.
    Type: String
    Default: modules/5af8175826af40428bb6062dff449ce1/v5
    AllowedPattern: ^[0-9a-zA-Z-/]*$
    ConstraintDescription: ArtifactsPrefix key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-),
      and forward slash (/). Leave default.
Resources:
  ## Configure ALB: security group, load balancer, route 53 endpoint
  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VpcId
      GroupDescription: Load Balancer Security Group
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref AllowedIP
      Tags:
        - Key: Name
          Value: !Join ["-" , [!Ref 'AWS::StackName', 'load-balancer']]

  AppLoadBlancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      SecurityGroups: 
        - !Ref LoadBalancerSecurityGroup
      Subnets: !Split [',', !Join [',', !Ref LoadBalancerSubnetId]]
      Tags:
        - Key: Name
          Value: !Join ["-" , [!Ref 'AWS::StackName', 'application-load-balancer']]

  AppLoadBlancerTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      Port: 80
      Protocol: HTTP
      UnhealthyThresholdCount: 10
      VpcId: !Ref VpcId
      Tags:
        - Key: Name
          Value: !Join ["-" , [!Ref 'AWS::StackName', 'target-group']]

  AppLoadBlancerListenerHttp:
    Type: AWS::ElasticLoadBalancingV2::Listener
    DependsOn: [ AppLoadBlancerTargetGroup ]
    Properties:
      LoadBalancerArn: !Ref AppLoadBlancer
      Port: 80
      Protocol: HTTP
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref AppLoadBlancerTargetGroup

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VpcId
      GroupDescription: EC2 Instance Security Group
      Tags:
        - Key: Name
          Value: !Join ["-" , [!Ref 'AWS::StackName', 'ec2']]
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          SourceSecurityGroupId: 
            !Ref LoadBalancerSecurityGroup

  ##  Configure the EC2 IAM role along with supporting resources
  EC2InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Join ["-" , [!Ref 'AWS::StackName', EC2Role]]
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - "sts:AssumeRole"
            Principal:
              Service:
                - "ec2.amazonaws.com"
                - "ssm.amazonaws.com"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
      Policies:
        - PolicyName: inline-policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: "Allow"
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                  - "logs:DescribeLogStreams"
                Resource: "arn:aws:logs:*:*:*"
              -
                Action:
                  - s3:ListBucket
                Effect: Allow
                Resource:
                  - !Join ['', ['arn:aws:s3:::', !Ref 'ArtifactsBucket']]
              -
                Action:
                  - s3:GetObject
                Effect: Allow
                Resource:
                  - !Join ['', ['arn:aws:s3:::', !Ref 'ArtifactsBucket', /, !Ref 'ArtifactsPrefix', /*]]

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
      - Ref: EC2InstanceRole

  LaunchConfiguration:
    Type: AWS::AutoScaling::LaunchConfiguration
    Properties:
      ImageId: !Ref ImageId
      SecurityGroups:
      - !GetAtt EC2SecurityGroup.GroupId
      InstanceType: !Ref EC2InstanceSize
      IamInstanceProfile:
        Ref: EC2InstanceProfile
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install -y httpd
          systemctl start httpd
          systemctl enable httpd
          echo "Hello from CloudFormation" > /var/www/html/index.html

  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: !Join ["-" , [!Ref 'AWS::StackName', LaunchTemplate]]
      LaunchTemplateData:
        ImageId: !Ref ImageId
        SecurityGroupIds:
          - !GetAtt EC2SecurityGroup.GroupId
        InstanceType: !Ref EC2InstanceSize
        IamInstanceProfile:
          Arn: !GetAtt EC2InstanceProfile.Arn
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            yum update -y
            yum install -y httpd
            systemctl start httpd
            systemctl enable httpd
            echo "Hello from CloudFormation" > /var/www/html/index.html

            # Fetch metadata
            INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
            AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)
            REGION=$(echo $AZ | sed 's/[a-z]$//')

            # Create web page
            cat <<EOF > /var/www/html/index.html
            <html>
            <head>
                <title>EC2 Metadata</title>
                <style>
                    body {
                        font-family: Arial, sans-serif;
                        height: 100vh;
                        margin: 0;
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        background-color: #f4f4f4;
                    }

                    .content {
                        text-align: center;
                        padding: 20px;
                        background-color: #fff;
                        border-radius: 8px;
                        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                    }
                </style>
            </head>
            <body>
                <div class="content">
                    <h1>EC2 Instance Metadata</h1>
                    <p><strong>Instance ID:</strong> $INSTANCE_ID</p>
                    <p><strong>Availability Zone:</strong> $AZ</p>
                    <p><strong>Region:</strong> $REGION</p>
                </div>
            </body>
            </html>
            EOF

  AutoScalingGroup:
    DependsOn: AppLoadBlancer
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier: !Split [',', !Join [',', !Ref EC2SubnetId]]
      #LaunchConfigurationName: !Ref LaunchConfiguration
      LaunchTemplate:
        LaunchTemplateId: !Ref LaunchTemplate
        Version: !GetAtt [LaunchTemplate, LatestVersionNumber]
      MinSize: '2'
      MaxSize: '2'
      TargetGroupARNs:
      - !Ref AppLoadBlancerTargetGroup
      DesiredCapacity: '2'
      HealthCheckType: ELB
      HealthCheckGracePeriod: 240
      Tags:
       -
        Key: Name
        Value: !Join ["-" , [!Ref 'AWS::StackName', 'asg']]
        PropagateAtLaunch: true

In Conclusion:

All these components together form a resilient and scalable architecture. While each can be used individually, their combined use ensures that web applications and services are always available, even if some components fail, and can scale up or down based on real-time demand.

Remember to monitor your infrastructure and adjust configurations as needed based on your application's demands and performance metrics.

© Waqar Ahmed.RSS