🤖

[CloudFormation] テスト用 web サーバと ALB を作成

2021/08/10に公開

この記事でやること

・EC2 インスタンス(Web サーバ)をデプロイ
・ALB をデプロイ
・EC2 インスタンスと ALB 用に Security Group を作成しアタッチ

使用するテンプレート

AWSTemplateFormatVersion: 2010-09-09

Parameters:
  ImageId:
    Type: String
  AllowIP:
    Type: String
  PrivateSubnetId:
    Type: String
  VPCId:
    Type: String
  PublicSubnet1Id:
    Type: String
  PublicSubnet2Id:
    Type: String

Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: t2.micro
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      SubnetId: !Ref PrivateSubnetId
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-EC2
      UserData: 
        !Base64 |
          #!/bin/bash
          amazon-linux-extras install nginx1.12 -y
          systemctl start nginx
          systemctl enable nginx

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${AWS::StackName}-EC2-SG
      GroupDescription: Used Web Server
      VpcId: !Ref VPCId
      SecurityGroupIngress: 
        - 
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref ALBSecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-EC2-SG
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${AWS::StackName}-ALB-SG
      GroupDescription: Used ALB
      VpcId: !Ref VPCId
      SecurityGroupIngress:
        - 
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref AllowIP
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-ALB-SG
 
  TargetGroup: 
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties: 
      VpcId: !Ref VPCId
      Name: !Sub ${AWS::StackName}-TG
      Protocol: HTTP
      Port: 80
      HealthCheckProtocol: HTTP
      HealthCheckPath: /
      HealthCheckPort: traffic-port
      HealthyThresholdCount: 5
      UnhealthyThresholdCount: 2
      HealthCheckTimeoutSeconds: 5
      HealthCheckIntervalSeconds: 30
      Matcher: 
        HttpCode: 200
      Targets: 
        - Id: !Ref EC2Instance
          Port: 80
  InternetALB: 
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties: 
      Name: !Sub ${AWS::StackName}-ALB
      Scheme: internet-facing
      LoadBalancerAttributes: 
        - Key: deletion_protection.enabled
          Value: false
        - Key: idle_timeout.timeout_seconds
          Value: 4000
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Subnets: 
        - !Ref PublicSubnet1Id
        - !Ref PublicSubnet2Id
  ALBListenerHTTP: 
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties: 
      Port: 80
      Protocol: HTTP
      DefaultActions: 
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      LoadBalancerArn: !Ref InternetALB

Outputs:
  HTTPWebSiteURL:
    Value: !GetAtt InternetALB.DNSName

※ Parameters セクションの値はハードコードしても問題ありません
 このテンプレートではテンプレートの汎用性のために Paramaters セクションにしてます

テンプレートの展開確認

下記リソースが展開されます

出力では ALB の URL が表示されます

アクセスすると HTTP で nginx の welcome ページが表示されます

各リソースの説明

EC2Instance:
  Type: AWS::EC2::Instance
  Properties:
    ImageId: !Ref ImageId
    InstanceType: t2.micro
    SecurityGroupIds:
      - !Ref EC2SecurityGroup
    SubnetId: !Ref PrivateSubnetId
    Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-EC2
    UserData: 
      !Base64 |
        #!/bin/bash
        amazon-linux-extras install nginx1.12 -y
        systemctl start nginx
        systemctl enable nginx

EC2 インスタンス(Web サーバ)を作成します
 ※今回はテスト用のため EC2 インスタンスは 1台としています

・SecurityGroupIds: EC2 インスタンにアタッチする Security Group のID を指定します
 → 今回は下記で作成するものを !Ref で指定します
 ※リスト形式で記載する必要があるため注意

・UserData: EC2 インスタンスを起動するときに実行するコマンドを記載します
 → 今回は Web サーバを構築するため nginx をインストールし、起動しています

EC2SecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupName: !Sub ${AWS::StackName}-EC2-SG
    GroupDescription: Used Web Server
    VpcId: !Ref VPCId
    SecurityGroupIngress: 
      - 
        IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        SourceSecurityGroupId: !Ref ALBSecurityGroup
    Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-EC2-SG
ALBSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupName: !Sub ${AWS::StackName}-ALB-SG
    GroupDescription: Used ALB
    VpcId: !Ref VPCId
    SecurityGroupIngress:
      - 
        IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: !Ref AllowIP
    Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-ALB-SG

EC2 インスタンスと ALB 用に Security Group を作成します

・VpcId: Security Group を作成する VPC の ID を指定します

・SecurityGroupIngress: Security Group のインバウンドルールを指定します
 → 今回は下記ルールで各 Security Group のインバウンドルールを作成します

・ALB 用の Security Group:ユーザが指定した IP アドレスからの Port 80 通信
 ・EC2 インスタンス 用の Security Group:ALB 用の Security Group からの Port 80 通信

TargetGroup: 
  Type: AWS::ElasticLoadBalancingV2::TargetGroup
  Properties: 
    VpcId: !Ref VPCId
    Name: !Sub ${AWS::StackName}-TG
    Protocol: HTTP
    Port: 80
    HealthCheckProtocol: HTTP
    HealthCheckPath: /
    HealthCheckPort: traffic-port
    HealthyThresholdCount: 5
    UnhealthyThresholdCount: 2
    HealthCheckTimeoutSeconds: 5
    HealthCheckIntervalSeconds: 30
    Matcher: 
      HttpCode: 200
    Targets: 
      - Id: !Ref EC2Instance
        Port: 80

ALB で使用するターゲットグループを作成します
 ※ヘルスチェックの設定に関しては細かいのでここでは割愛します

・VpcId: ターゲットグループを作成する VPC の ID を指定します

・Targets: ターゲットの ID とポートを指定します
 → 今回は 作成した EC2 インスタンスを !Ref で指定します

InternetALB: 
  Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  Properties: 
    Name: !Sub ${AWS::StackName}-ALB
    Scheme: internet-facing
    LoadBalancerAttributes: 
      - Key: deletion_protection.enabled
        Value: false
      - Key: idle_timeout.timeout_seconds
        Value: 4000
    SecurityGroups:
      - !Ref ALBSecurityGroup
    Subnets: 
      - !Ref PublicSubnet1Id
      - !Ref PublicSubnet2Id

ALB を作成します

・Scheme: ALB を内部/外部用にするかを指定します
 → デフォルトでは internet-facing となっているため今回は指定しなくても問題ありません

・LoadBalancerAttributes: ALB の属性を設定します
 → 今回は削除保護を無効化、アイドルタイムアウトを 4000秒にしています

・SecurityGroups: ALB にアタッチする Security Group の ID を指定します
 → 今回は上記で作成するものを !Ref で指定します
 ※リスト形式で記載する必要があるため注意

・Subnets: EC2 インスタンスをデプロイするサブネットの ID を指定します
 ※ALB では 2つ以上のサブネットにデプロイする必要があります
 ※リスト形式で記載する必要があるため注意

ALBListenerHTTP: 
  Type: AWS::ElasticLoadBalancingV2::Listener
  Properties: 
    Port: 80
    Protocol: HTTP
    DefaultActions: 
      - TargetGroupArn: !Ref TargetGroup
        Type: forward
    LoadBalancerArn: !Ref InternetALB

ALB で使用するリスナーを作成します

・Port: リスナーの受信ポートを指定します

・Protocol: リスナーの受信プロトコルを指定します

・DefaultActions: リスナーがアクセスされた際の動作を指定します
 → 今回は上記で作成したターゲットグループにフォワードします

・LoadBalancerArn: リスナーを設定する ALB の ARN を指定します
 → 今回は上記で作成した ALB の ARN を !Ref で指定します

Outputs:
  HTTPWebSiteURL:
    Value: !GetAtt InternetALB.DNSName

Web サーバのアクセス用の URL を出力します
ALB の URL を出力する場合、組み込み関数の !GetAtt を使用し .DNSName で取得します

上記以外の説明

テンプレートの詳細で上記で解説していないものに関して、
[CloudFormation] SSM アクセスができる EC2 インスタンスを作成で使用したテンプレートを編集しているのでこちらの記事も併せて確認ください

参考

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html

Discussion