CloudFormationによるAWSネットワーク構築④：ALBとEC2をCloudFormationでコード化して、ブラウザからアクセスしてみた

## はじめに
この記事では、AWSのCloudFormationテンプレートを使用して、80番ポートで通信するアプリケーションロードバランサー (ALB) の構成を作成します。

また、本番サーバー (ProductionInstance) の起動時に、httpd パッケージのインストールと httpd サービスの起動を自動化するためのコマンドも設定していきます。

インフラのコード化に興味のある方や、CloudFormationの活用を検討している方は、ぜひお読みください！

## 前回の記事の続きになります。

この記事は過去の記事の続きです。詳しく知りたい方は以下の記事も参考にしてください。

https://qiita.com/free-honda/items/5a8c69df40c631549663

https://qiita.com/free-honda/items/06d092c82d1dcb1e77fe

https://qiita.com/free-honda/items/da70f65d9d93a89abd23

今回は、CloudFormationでの ALB 設定などを追加で行います。

:::note warn
具体的には、以下のリソースを定義し、各構成要素について詳しく解説します。
- **ALBとターゲットグループの設定**
- **サブネットの関連付け**
- **本番サーバー (ProductionInstance) のセキュリティグループ設定**
:::

## ALB周りの追加設定＆Apacheの自動インストール

ここでは、AWSのCloudFormationテンプレートを使用して、80番ポートで通信するアプリケーションロードバランサー (ALB) 構成を作成し、本番サーバー (ProductionInstance) にHTTPリクエストを転送する設定を追加しています。

```yaml
  # ALBのセキュリティグループの作成
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow HTTP access to ALB"
      VpcId: !Ref HondaVpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ホンダ-sg-alb

  # 本番サーバー用セキュリティグループの作成
  ProductionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow HTTP access from ALB and SSH access from anywhere"
      VpcId: !Ref HondaVpc
      SecurityGroupIngress:
        # ALBからのHTTPアクセスを許可
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref ALBSecurityGroup
        # SSHアクセスを任意の場所から許可
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ホンダ-sg-production

  # 本番サーバー用のEC2インスタンスの作成（PrivateSubnet1に配置）
  ProductionInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SubnetId: !Ref PrivateSubnet1
      ImageId: ami-0b6fe957a0eb4c1b9
      KeyName: "honda"
      SecurityGroupIds:
        - !Ref ProductionSecurityGroup
      Tags:
        - Key: Name
          Value: "本番サーバー"
      UserData: 
        Fn::Base64: !Sub |
          #!/bin/bash
          sudo yum install -y httpd
          sudo systemctl start httpd
          sudo systemctl enable httpd

  # ALBの作成
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: Honda-ALB
      Scheme: internet-facing
      Subnets:
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Type: application
      Tags:
        - Key: Name
          Value: ホンダ-alb

  # ALBのリスナーの作成
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref ALBTargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

  # ターゲットグループの作成（80番ポート用）
  ALBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: Honda-TargetGroup
      Port: 80
      Protocol: HTTP
      VpcId: !Ref HondaVpc
      TargetType: instance
      HealthCheckProtocol: HTTP
      HealthCheckPort: "80"
      HealthCheckPath: /
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 5
      UnhealthyThresholdCount: 2
      Tags:
        - Key: Name
          Value: ホンダ-target-group
      Targets:
        - Id: !Ref ProductionInstance          
```

また、インスタンス起動時に httpd パッケージのインストールと httpd サービスの起動を自動化する設定も追加しています。

## 完成したコード

前回のコードと新たに追加した部分を組み合わせた最終的なコードは、以下の通りです。

:::note warn
**複雑なアーキテクチャとなっているため、コードが長くなっていますが、流れをつかむ感じで見ていただければと思います（笑）。**
:::

```yaml
Resources:
  # VPCの作成
  HondaVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: ホンダ-vpc

  # パブリックサブネットの作成
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.0.0/20
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: ホンダ-subnet-public1-ap-northeast-1a

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.16.0/20
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: ホンダ-subnet-public2-ap-northeast-1c

  # プライベートサブネットの作成
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.128.0/20
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: ホンダ-subnet-private1-ap-northeast-1a

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.144.0/20
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: ホンダ-subnet-private2-ap-northeast-1c

  PrivateSubnet3:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.160.0/20
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: ホンダ-subnet-private3-ap-northeast-1a

  PrivateSubnet4:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.176.0/20
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: ホンダ-subnet-private4-ap-northeast-1c

  # インターネットゲートウェイの作成
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: ホンダ-igw

  # インターネットゲートウェイをVPCにアタッチ
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref HondaVpc
      InternetGatewayId: !Ref InternetGateway

  # パブリックルートテーブルの作成とパブリックサブネットとの関連付け
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref HondaVpc
      Tags:
        - Key: Name
          Value: ホンダ-rtb-public

  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

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

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

  # Elastic IP の作成
  ElasticIP1:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: ホンダ-eip-ap-northeast-1a

  # NATゲートウェイの作成
  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      SubnetId: !Ref PublicSubnet1
      AllocationId: !GetAtt ElasticIP1.AllocationId
      Tags:
        - Key: Name
          Value: ホンダ-nat-public1-ap-northeast-1a

  # プライベートルートテーブルの作成と各サブネットとの関連付け
  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref HondaVpc
      Tags:
        - Key: Name
          Value: ホンダ-rtb-private1-ap-northeast-1a

  PrivateRoute1:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable1

  # 踏み台サーバー（Bastion）用のセキュリティグループの作成
  BastionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow SSH access"
      VpcId: !Ref HondaVpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ホンダ-sg-bastion

  # Elastic IP の作成（別のElastic IP）
  ElasticIP2:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: ホンダ-eip-ap-northeast-1c

  # 踏み台サーバーのEC2インスタンスの作成
  BastionInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SubnetId: !Ref PublicSubnet1
      ImageId: ami-0b6fe957a0eb4c1b9
      KeyName: "honda"
      SecurityGroupIds:
        - !Ref BastionSecurityGroup
      Tags:
        - Key: Name
          Value: "踏み台サーバー"

  # ALBのセキュリティグループの作成
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow HTTP access to ALB"
      VpcId: !Ref HondaVpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ホンダ-sg-alb

  # 本番サーバー用セキュリティグループの作成
  ProductionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow HTTP access from ALB and SSH access from anywhere"
      VpcId: !Ref HondaVpc
      SecurityGroupIngress:
        # ALBからのHTTPアクセスを許可
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref ALBSecurityGroup
        # SSHアクセスを任意の場所から許可
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ホンダ-sg-production

  # 本番サーバー用のEC2インスタンスの作成（PrivateSubnet1に配置）
  ProductionInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SubnetId: !Ref PrivateSubnet1
      ImageId: ami-0b6fe957a0eb4c1b9
      KeyName: "honda"
      SecurityGroupIds:
        - !Ref ProductionSecurityGroup
      Tags:
        - Key: Name
          Value: "本番サーバー"
      UserData: 
        Fn::Base64: !Sub |
          #!/bin/bash
          sudo yum install -y httpd
          sudo systemctl start httpd
          sudo systemctl enable httpd

  # ALBの作成
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: Honda-ALB
      Scheme: internet-facing
      Subnets:
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Type: application
      Tags:
        - Key: Name
          Value: ホンダ-alb

  # ALBのリスナーの作成
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref ALBTargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

  # ターゲットグループの作成（80番ポート用）
  ALBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: Honda-TargetGroup
      Port: 80
      Protocol: HTTP
      VpcId: !Ref HondaVpc
      TargetType: instance
      HealthCheckProtocol: HTTP
      HealthCheckPort: "80"
      HealthCheckPath: /
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 5
      UnhealthyThresholdCount: 2
      Tags:
        - Key: Name
          Value: ホンダ-target-group
      Targets:
        - Id: !Ref ProductionInstance
```

非常に長くなっていますが、基本的にはシンプルで簡単なコードで書いています（そこまで、難しくありません！）。

## 実際にスタックを実行してみた

CloudFormationのサービス画面からスタックの作成に進み、作成した``yamlファイル``をアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/1f238e06-6895-82e7-2628-fa85366f6ac7.png)

スタック名は任意で設定できます。ここでは私の名前「``honda``」としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/1c75259d-d21d-c09a-f4ca-e962527617fb.png)

画面遷移後のスタックオプション設定については、個々の設定に依存するため、私は設定せずに進めていきます。

最後に確認を行い、問題がなければ最下部までスクロールし、「``送信``」をクリックして完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/0f0a08f4-d6e4-cf96-b900-11e27e0176db.png)

スタックを実行後、イベントタブで成功したことが確認できました（しばらく時間がかかります）。

![スクリーンショット 2024-11-11 18.02.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/2046964e-fcc2-de4d-4fb5-4d280b127f71.png)


## ブラウザからALBのDNS名にアクセスしてみた

CloudFormationでスタックを実行した後、EC2サービス画面で踏み台サーバーと本番サーバーが作成されたことを確認しました。

![スクリーンショット 2024-11-11 18.11.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/6cfcd764-93ce-6d12-c62d-beb24f5276b1.png)

踏み台サーバーへのアクセス方法については、前回の記事で詳細に紹介しているので、参考にしてください。

https://qiita.com/free-honda/items/da70f65d9d93a89abd23#%E8%B8%8F%E3%81%BF%E5%8F%B0%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%8B%E3%82%89%E6%9C%AC%E7%95%AA%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%ABssh%E6%8E%A5%E7%B6%9A%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F

次に、ALBのDNS名からブラウザにアクセスしてみます。

![スクリーンショット 2024-11-11 18.11.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/de06d52a-365f-ba35-43f3-94171147b15e.png)

私の場合、Chromeブラウザで通常アクセスした際にはhttpsで接続されましたので、不要な「s」を削除してアクセスしてみてください。

```bash
http://honda-alb-1423201187.ap-northeast-1.elb.amazonaws.com/
```

これにより、設定したALBが正しく機能し、Apacheが動作していることを確認できたため、検証は大成功です！

![スクリーンショット 2024-11-11 18.09.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/182f7e20-275b-f68c-7ad4-df8e7bb13579.png)

## まとめ

本記事では、CloudFormationを使ってALBの構成と本番サーバーのセットアップを行い、ブラウザからALBを経由してApacheのデフォルトテストサイトにアクセスできることを確認しました。

:::note warn
**これにより、インフラのコード化の一環としてALBとEC2インスタンスの設定が自動化され、簡単に確認できる環境が整いました。**
:::

次回は、さらなるカスタマイズや、実際のアプリケーションをALBに接続する方法について触れていきます。

## 関連記事

今回と似た記事として、インフラのコード化に関する記事も参考にしてみてください。

https://qiita.com/free-honda/items/5a8c69df40c631549663

https://qiita.com/free-honda/items/e972710ed65c5c4afb4e

https://qiita.com/free-honda/items/4cadfd1bafa6c71c85fb