Build Elastic Beanstalk ALB environment using CloudFormation

Build Elastic Beanstalk ALB environment using CloudFormation.

In the following pages, we have introduced the minimum configuration for Elastic Beanstalk.

あわせて読みたい
Introduction to Elastic Beanstalk with CloudFormation 【Introduction to Elastic Beanstalk with CloudFormation】 Elastic Beanstalk will be covered. With Elastic Beanstalk, you can quickly deploy and manage applic...

This time, we will expand on the above to create an ALB configuration with Elastic Beanstalk.

Environment

Diagram of Elastic Beanstalk ALB environment using CloudFormation.

Within the VPC, create an Elastic Beanstalk environment.
Specifically, we will create a web server environment configured with an ALB and Auto Scaling group.
Choose Python 3.8 as the platform.

Create two subnets in the VPC, one in each of the two AZs.
They will be public and private subnets respectively.

Automatically build a Python script to run on an EC2 instance.
Specifically, after creating the script with CodeBuild, place it in an S3 bucket.
The trigger to run this CodeBuild is a CloudFormation custom resource.

The timing of when to start building Elastic Beanstalk is controlled by CloudFormation’s WaitCondition.
In concrete terms, we will ensure that the build of Elastic Beanstalk starts after CodeBuild completes placing the source bundle in the S3 bucket.

CloudFormation template files

The above configuration is built with CloudFormation.
The CloudFormation templates are placed at the following URL

https://github.com/awstut-an-r/awstut-fa/tree/main/143

Explanation of key points of template files

(Reference) VPC

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCidrBlock

  IGW:
    Type: AWS::EC2::InternetGateway

  IGWAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW

  EIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  NATGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt EIP.AllocationId
      SubnetId: !Ref PublicSubnet1

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref CidrIp1
      VpcId: !Ref VPC
      AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone1}"

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref CidrIp2
      VpcId: !Ref VPC
      AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone2}"

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref CidrIp3
      VpcId: !Ref VPC
      AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone1}"

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref CidrIp4
      VpcId: !Ref VPC
      AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone2}"

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC

  RouteToInternet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW

  PublicSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC

  RouteToNATGateway:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway

  PrivateSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable
Code language: YAML (yaml)

Define the VPCs, subnets, etc. that will serve as the foundation for ALB and Auto Scaling groups.

A particularly key resource is the NAT gateway.

In this configuration, the Auto Scaling group will be created on a private subnet.
This means that the EC2 instances managed in Elastic Beanstalk will be created in the private subnet.
In Elastic Beanstalk, there are some things to keep in mind when creating EC2 instances on private subnets.
That is, reachability to the Internet.

Private Subnet – Instances use a NAT device to access the internet.

Using Elastic Beanstalk with Amazon VPC

Place a NAT gateway on the public subnet as described above.
Then define a route for this gateway in the route table for the private subnet.

Elastic Beanstalk

Resources:
  Application:
    Type: AWS::ElasticBeanstalk::Application
    Properties:
      ApplicationName: !Sub "${Prefix}-application"

  ApplicationVersion:
    Type: AWS::ElasticBeanstalk::ApplicationVersion

    Properties:
      ApplicationName: !Ref Application
      SourceBundle:
        S3Bucket: !Ref BucketName
        S3Key: !Ref SourceBundleName

  Environment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      ApplicationName: !Ref Application
      CNAMEPrefix: !Ref Prefix
      EnvironmentName: !Sub "${Prefix}-env"
      TemplateName: !Ref ConfigurationTemplate
      Tier:
        Name: WebServer
        Type: Standard
      VersionLabel: !Ref ApplicationVersion

  ConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName: !Ref Application
      OptionSettings:
        - Namespace: aws:autoscaling:asg
          OptionName: MaxSize
          Value: !Ref MaxSize
        - Namespace: aws:autoscaling:asg
          OptionName: MinSize
          Value: !Ref MinSize
        - Namespace: aws:autoscaling:launchconfiguration
          OptionName: IamInstanceProfile
          Value: !Ref InstanceProfile
        - Namespace: aws:ec2:instances
          OptionName: InstanceTypes
          Value: !Ref InstanceType
        - Namespace: aws:ec2:instances
          OptionName: SupportedArchitectures
          Value: !Ref InstanceArchitecture
        - Namespace: aws:ec2:vpc
          OptionName: VPCId
          Value: !Ref VPC
        - Namespace: aws:ec2:vpc
          OptionName: Subnets
          Value: !Join
            - ","
            - - !Ref PrivateSubnet1
              - !Ref PrivateSubnet2
        - Namespace: aws:ec2:vpc
          OptionName: ELBSubnets
          Value: !Join
            - ","
            - - !Ref PublicSubnet1
              - !Ref PublicSubnet2
        - Namespace: aws:elasticbeanstalk:environment
          OptionName: EnvironmentType
          Value: !Ref EnvironmentType
        - Namespace: aws:elasticbeanstalk:environment
          OptionName: ServiceRole
          Value: !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/aws-elasticbeanstalk-service-role"
        - Namespace: aws:elasticbeanstalk:environment
          OptionName: LoadBalancerType
          Value: !Ref LoadBalancerType
      SolutionStackName: !Ref SolutionStackName

  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref InstanceRole

  InstanceRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier
Code language: YAML (yaml)

This page focuses on how to create an ALB environment using Elastic Beanstalk.
For basic information about Elastic Beanstalk, please see the following pages.

あわせて読みたい
Introduction to Elastic Beanstalk with CloudFormation 【Introduction to Elastic Beanstalk with CloudFormation】 Elastic Beanstalk will be covered. With Elastic Beanstalk, you can quickly deploy and manage applic...

ConfigurationTemplate is an important resource for creating ALBs using Elastic Beanstalk.
Configure the settings for the ALB with the OptionSettings property.
The following are important parameters.

In the namespace aws:autoscaling:asg, set MaxSize and MinSize.
This specifies the maximum and minimum EC2 instances to create in the Auto Scaling group.
In this case, specify “2” for both parameters.

In the namespace aws:ec2:vpc, set Subnets and ELBSubnets.
The former specifies the subnet where the Auto Scaling group will be created, and the latter specifies the subnet associated with the ELB.
In this configuration, we will create the Auto Scaling group on a private subnet, so we specify two private subnets in the former.
And since we need to associate a public subnet to the ELB, we specify two public subnets in the latter.

In the namespace aws:elasticbeanstalk:environment, set two settings: EnvironmentType and LoadBalancerType.
You can create an ALB by specifying “LoadBalanced” for the former and “application” for the latter.

(Reference) CodeBuild Project

Resources:
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: NO_ARTIFACTS
      Cache:
        Type: NO_CACHE
      Environment:
        ComputeType: !Ref ProjectEnvironmentComputeType
        EnvironmentVariables:
          - Name: BUCKET_NAME
            Type: PLAINTEXT
            Value: !Ref BucketName
          - Name: SOURCE_BUNDLE_NAME
            Type: PLAINTEXT
            Value: !Ref SourceBundleName
          - Name: SOURCE_FILE_NAME
            Type: PLAINTEXT
            Value: !Ref SourceFileName
        Image: !Ref ProjectEnvironmentImage
        ImagePullCredentialsType: CODEBUILD
        Type: !Ref ProjectEnvironmentType
        PrivilegedMode: true
      LogsConfig:
        CloudWatchLogs:
          Status: DISABLED
        S3Logs:
          Status: DISABLED
      Name: !Ref Prefix
      ServiceRole: !GetAtt CodeBuildRole.Arn
      Source:
        Type: NO_SOURCE
        BuildSpec: !Sub |
          version: 0.2

          phases:
            pre_build:
              commands:
                - |
                  cat << EOF > $SOURCE_FILE_NAME
                  import datetime
                  import subprocess

                  def application(environ, start_response):
                      result = subprocess.run(
                        ['ec2-metadata', '-i'],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        encoding='utf-8'
                      )
                      start_response("200 OK", [
                          ("Content-Type", "text/html")
                      ])
                      return [bytes(result.stdout, 'utf-8')]
                  EOF
            build:
              commands:
                - zip $SOURCE_BUNDLE_NAME -r * .[^.]*
            post_build:
              commands:
                - aws s3 cp $SOURCE_BUNDLE_NAME s3://$BUCKET_NAME/
      Visibility: PRIVATE

  CodeBuildRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: PutS3ObjectPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:PutObject
                Resource:
                  - !Sub "arn:aws:s3:::${BucketName}/*"
Code language: YAML (yaml)

Use CodeBuild to build the application to run on Elastic Beanstalk and place it in an S3 bucket.

The contents of the application to be executed, which returns the ID of the EC2 instance on which the application is to be executed.

Architecting

Use CloudFormation to build this environment and check its actual behavior.

Create CloudFormation stacks and check the resources in the stacks

Create CloudFormation stacks.
For information on how to create stacks and check each stack, please see the following page.

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

After reviewing the resources in each stack, information on the main resources created in this case is as follows

  • CodeBuild project: fa-141
  • S3 bucket: fa-141
  • Elastic Beanstalk application: fa-143-application
  • Elastic Beanstalk environment: fa-143-env

Check the creation status of each resource from the AWS Management Console.

Check the working status of your CodeBuild project.

Detail of CodeBuild 1.

CodeBuild is running automatically.
This means that the project was automatically started by a Lambda function tied to a CloudFormation custom resource.
This has resulted in a source bundle being built to run on Elastic Beanstalk.

Check the S3 bucket.

Detail of S3 1.

object is located.
This is the source bundle built by the CodeBuild project.
This file is executed on Elastic Beanstalk.

Operation Check

Now that you are ready, check Elastic Beanstalk.

First, check the Elastic Beanstalk application.

Detail of Elastic Beanstalk 1.

Indeed, an application has been created.
The Elastic Beanstalk environment is created within the framework of the application.

Check the Elastic Beanstalk environment.

Detail of Elastic Beanstalk 2.

The environment has been successfully created.

Check the log at the time of environment creation.

Detail of Elastic Beanstalk 3.

You can see that ALB has indeed been built.
And you can also see that two EC2 instances have been created in the Auto Scaling group.

Access this application.

$ curl http://fa-143.ap-northeast-1.elasticbeanstalk.com
instance-id: i-04435211511b2387b

$ curl http://fa-143.ap-northeast-1.elasticbeanstalk.com
instance-id: i-03162d9ad59a56328Code language: Bash (bash)

It is indeed possible to access the two instances under the ALB.

In this way, an ALB environment can be built using Elastic Beanstalk.

Finally, we will review the security groups.
Two security groups are automatically created by Elastic Beanstalk.

  • For ALB
  • For EC2 instances

Check each of the following.

Detail of VPC 1.
Detail of VPC 2.

The first one is for ALB.
This content allows HTTP communication (80/tcp) from all senders.

The second one is for an EC2 instance.
This content allows HTTP communication (80/tcp) from the security group for ALB.

Summary

ALB configuration was created in Elastic Beanstalk.