Creating an ALB

As mentioned, ECS provides an orchestrator that takes care of allocating the containers across our Auto Scaling group. It also keeps track of what port each container uses, and integrates with ALB so that our load balancer can correctly route the incoming traffic to all containers running a given service.

ECS supports both the ELB and ALB services, but the ALB gives more flexibility when working with containers. We will demonstrate how to create an ALB using CloudFormation through Troposphere.

We will start by creating a new file and calling it helloworld-ecs-alb-cf-template.py.

We will then put our usual import, and create our template variable, and add a description:

"""Generating CloudFormation template.""" 
 
from troposphere import elasticloadbalancingv2 as elb 
 
from troposphere import ( 
    Export, 
    GetAtt, 
    ImportValue, 
    Join, 
    Output, 
    Ref, 
    Select, 
    Split, 
    Sub, 
    Template, 
    ec2 
) 
 
t = Template() 
 
t.add_description("Effective DevOps in AWS: ALB for the ECS Cluster") 

We are now going to create our security group. No surprise here, we are opening TCP/3000 to the world as we did in Chapter 5, Scaling Your Infrastructure, with the ELB:

t.add_resource(ec2.SecurityGroup( 
    "LoadBalancerSecurityGroup", 
    GroupDescription="Web load balancer security group.", 
    VpcId=ImportValue( 
        Join( 
            "-", 
            [Select(0, Split("-", Ref("AWS::StackName"))), 
                "cluster-vpc-id"] 
        ) 
    ), 
    SecurityGroupIngress=[ 
        ec2.SecurityGroupRule( 
            IpProtocol="tcp", 
            FromPort="3000", 
            ToPort="3000", 
            CidrIp="0.0.0.0/0", 
        ), 
    ], 
)) 

The main difference with what we did previously is that, instead of starting with a parameter section and requesting, yet again, to provide the VPC ID and public subnets, we are taking advantage of the value we just exported before. When we launch this stack, we will call it staging-alb. The block of code inside the ImportValue does the following:

  1. We first get the name of our stack. We will launch that stack under the name staging-alb.
  2. The split function breaks the stack name on the character -, meaning that we end up with ['staging','alb'].
  3. The select function takes the first element of the list, staging.
  4. The join function concatenates that element with the string -cluster-vpc-id. In the end, we get Import("staging-cluster-vpc-id"), which is the name of the key we defined to export the VPC ID when we created our ECS cluster.

We are now going to create our ALB. ALB, being more flexible and feature-rich than ELB, requires a bit more effort when it comes to configuration. ALB works through the intermediary of three different resources. The first one is the ALB resource which handles incoming connections. On the opposite side, we can find the target groups, which are the resources used by the ECS cluster's register to those ALB. Finally, in order to tie them together, we find the listener's resources, as shown in the following diagram:

We will first define our load balancer resource:

t.add_resource(elb.LoadBalancer( 
    "LoadBalancer", 
    Scheme="internet-facing", 
    Subnets=Split( 
        ',', 
        ImportValue( 
            Join("-", 
                 [Select(0, Split("-", Ref("AWS::StackName"))), 
                  "cluster-public-subnets"] 
                 ) 
        ) 
    ), 
    SecurityGroups=[Ref("LoadBalancerSecurityGroup")], 
)) 
We use a very similar series of calls to the ImportValue function to import our subnet as we did just before for the VPC ID.

We are now going to create our target group and configure our health check:

t.add_resource(elb.TargetGroup( 
    "TargetGroup", 
    DependsOn='LoadBalancer', 
    HealthCheckIntervalSeconds="20", 
    HealthCheckProtocol="HTTP", 
    HealthCheckTimeoutSeconds="15", 
    HealthyThresholdCount="5", 
    Matcher=elb.Matcher( 
        HttpCode="200"), 
    Port=3000, 
    Protocol="HTTP", 
    UnhealthyThresholdCount="3", 
    VpcId=ImportValue( 
        Join( 
            "-", 
            [Select(0, Split("-", Ref("AWS::StackName"))), 
                "cluster-vpc-id"] 
        ) 
    ), 
)) 

Next, we will add the listener to connect our target group to our load balancer:

t.add_resource(elb.Listener( 
    "Listener", 
    Port="3000", 
    Protocol="HTTP", 
    LoadBalancerArn=Ref("LoadBalancer"), 
    DefaultActions=[elb.Action( 
        Type="forward", 
        TargetGroupArn=Ref("TargetGroup") 
    )] 
)) 

Lastly, we will want to create two outputs. The first output is the target group. We will export its value so that our application can register to the . The second

t.add_output(Output( 
    "TargetGroup", 
    Description="TargetGroup", 
    Value=Ref("TargetGroup"), 
    Export=Export(Sub("${AWS::StackName}-target-group")), 
)) 
 
t.add_output(Output( 
    "URL", 
    Description="Helloworld URL", 
    Value=Join("", ["http://", GetAtt("LoadBalancer", "DNSName"), ":3000"]) 
)) 
 
print(t.to_json()) 

The file is ready and should look like this: http://bit.ly/2vbhd1r

We can now generate our template and create our stack, as follows:

$ git add helloworld-ecs-alb-cf-template.py
$ git commit -m "Adding a Load balancer template for our helloworld application on ECS"
$ git push
$ python helloworld-ecs-alb-cf-template.py > helloworld-ecs-alb-cf.template
$ aws cloudformation create-stack
--stack-name staging-alb
--capabilities CAPABILITY_IAM
--template-body file://helloworld-ecs-alb-cf.template

As mentioned, it is important to call it staging-alb and that first word is used to import the VPC ID and subnets.

The last stack we need is the creation of our container service.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset