0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人開発で IaC を導入して感じたメリットと構築プロセス(CloudFormation)

Last updated at Posted at 2025-12-09

はじめに

今年度の文化祭で、研究室のメンバー4人と一緒にクイズラリーアプリを開発しました。その中で私は、正答率の集計などを行う バックエンド API をデプロイするためのインフラ構築を担当しました。

昨年度も露店アプリのインフラを担当しており、AWS やネットワークの基礎には慣れてきたため、今回はより運用しやすく再利用可能な構成を目指し、AWS CloudFormation(IaC)を用いてインフラをコード化することに挑戦しました。

とはいえ、CloudFormation をいきなり一人で書くのはハードルが高かったため、AI と相談しながらテンプレートを少しずつ拡張していく形で進めました。本記事では、その際の学びのメモと構成まとめを紹介します。

今回構築したアーキテクチャ

今回作成したアーキテクチャは以下のとおりです。

ALBの導入について

文化祭当日はアクセスが一時的に集中する可能性があったため、ALB(Application Load Balancer)を前段に置き、リクエストのルーティングを分散できる構成を採用しました。
AWS の仕様上、ALB は複数の Availability Zone に跨って配置されますが、今回は 個人開発でコストを抑えるため、EC2 は AZ1 に 1 台のみ配置しています。
ターゲットが 1 台でも ALB は問題なく動作し、可用性だけ確保できるため、この構成が最適と判断しました。

EC2の設定について

EC2(仮想サーバ)については以下のように技術選定を行いました。

Web サーバ:nginx

  • 並列処理が得意で軽量
  • 文化祭規模のアクセスなら十分
  • Apache と大差はないが、チームメンバーがこちらに慣れていたため採用

インスタンス:t3.micro

  • 小さめのインスタンスでも十分動作
  • t2 と比べ 最大 30% のコストパフォーマンス改善
  • CPU クレジット不足時でも性能低下が起きにくい
  • 無料枠ではないが、短期間の文化祭用途なら問題なし

参考にしたテンプレート

ベースにしたのは以下の CloudFormation 入門動画で紹介されているテンプレートです。(ファイルダウンロード):

  • 使用したテンプレート(1-ec2-template.yml):

内容としては「SSH 接続可能な EC2 インスタンスを 1 台作成する」最小構成です。

AWSTemplateFormatVersion: '2010-09-09'
Description: Create an EC2 instance with a security group for SSH access
Resources:
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0440d3b780d96b29d
      InstanceType: t2.micro
      SecurityGroups:
        - !Ref InstanceSecurityGroup

構成を少しずつ拡張していく

以下では、実際に CloudFormation を書き換えながら進めた内容を段階ごとにまとめています。

1. EC2の基本設定(t3.micro へ変更)

まず、インスタンスタイプを t3.micro に変更しました。

-       InstanceType: t2.micro
+       InstanceType: t3.micro

2. HTTP(ポート80)アクセスを許可するセキュリティグループへ変更

HTTPアクセス用のセキュリティグループルール(ポート80)を追加しました。
(nginxをWebサーバーとして使うため、HTTPアクセス(ポート80)を許可する必要があるため)

  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH and HTTP access
      VpcId: !Ref MyVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
+       - IpProtocol: tcp # nginxをWebサーバーとして使うため、HTTPアクセス(ポート80)を許可
+         FromPort: 80
+         ToPort: 80
+         CidrIp: 0.0.0.0/0
  MyInstance:

3. Web 公開のための EC2 セットアップとネットワーク構成の追加

ALB(Application Load Balancer)を使って EC2 上の Web アプリを公開するために、
まず EC2 側の準備と、ALB が動作するための VPC ネットワーク構成を追加しました。

ここでは、以下の 2 点をまとめて実装しています:

  • EC2 起動時に nginx を自動インストールする UserData (インスタンス起動時に実行されるスクリプト) の追加

  • ALB 用の VPC / サブネット / ルート を構成するネットワークリソースの追加 (ALBを使うには、VPCと複数のアベイラビリティゾーンにサブネットが必要)

+ MyVPC:
+   Type: AWS::EC2::VPC
+   Properties:
+     CidrBlock: 10.0.0.0/16
+     EnableDnsHostnames: true
+     EnableDnsSupport: true
+
+ MyInternetGateway:
+   Type: AWS::EC2::InternetGateway
+
+ AttachGateway:
+   Type: AWS::EC2::VPCGatewayAttachment
+   Properties:
+     VpcId: !Ref MyVPC
+     InternetGatewayId: !Ref MyInternetGateway
+
+ PublicSubnet1: # NATを使うコスト削減のため、パブリックに設定
+   Type: AWS::EC2::Subnet
+   Properties:
+     VpcId: !Ref MyVPC
+     CidrBlock: 10.0.1.0/24
+     AvailabilityZone: !Select [0, !GetAZs ""]
+     MapPublicIpOnLaunch: true
+
+ PublicSubnet2:
+   Type: AWS::EC2::Subnet
+   Properties:
+     VpcId: !Ref MyVPC
+     CidrBlock: 10.0.2.0/24
+     AvailabilityZone: !Select [1, !GetAZs ""]
+     MapPublicIpOnLaunch: true
+
+ PublicRouteTable:
+   Type: AWS::EC2::RouteTable
+   Properties:
+     VpcId: !Ref MyVPC
+
+ PublicRoute:
+   Type: AWS::EC2::Route
+   DependsOn: AttachGateway
+   Properties:
+     RouteTableId: !Ref PublicRouteTable
+     DestinationCidrBlock: 0.0.0.0/0
+     GatewayId: !Ref MyInternetGateway
+
+ SubnetRouteTableAssociation1:
+   Type: AWS::EC2::SubnetRouteTableAssociation
+   Properties:
+     SubnetId: !Ref PublicSubnet1
+     RouteTableId: !Ref PublicRouteTable
+
+ SubnetRouteTableAssociation2:
+   Type: AWS::EC2::SubnetRouteTableAssociation
+   Properties:
+     SubnetId: !Ref PublicSubnet2
+     RouteTableId: !Ref PublicRouteTable

EC2インスタンスのセキュリティグループをVPC対応に更新

  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-07faa35bbd2230d90
      InstanceType: t3.micro
+     SubnetId: !Ref PublicSubnet1
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup

ALB用のセキュリティグループとALB本体を追加

          systemctl start nginx
          systemctl enable nginx
          echo "<h1>Welcome to nginx on AWS!</h1>" > /usr/share/nginx/html/index.html


+ ALBSecurityGroup:
+   Type: AWS::EC2::SecurityGroup
+   Properties:
+     GroupDescription: Enable HTTP access for ALB
+     VpcId: !Ref MyVPC
+     SecurityGroupIngress:
+       - IpProtocol: tcp
+         FromPort: 80
+         ToPort: 80
+         CidrIp: 0.0.0.0/0
+
+ MyALB:
+   Type: AWS::ElasticLoadBalancingV2::LoadBalancer
+   Properties:
+     Type: application
+     Subnets:
+       - !Ref PublicSubnet1
+       - !Ref PublicSubnet2
+     SecurityGroups:
+       - !Ref ALBSecurityGroup

4. ALB を経由して EC2 にアクセスできるようにする

ALB が EC2 に正しくトラフィックを転送できるようにするための設定を追加しました。

4-1. EC2 へのアクセスを「ALB 経由のみに限定」

まず、EC2 の 80 番ポートは ALB からのみアクセス許可 するようにセキュリティグループを更新しました。

        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
-         CidrIp: 0.0.0.0/0
+         SourceSecurityGroupId: !Ref ALBSecurityGroup

この設定により、

  • インターネット → EC2 への直接アクセスは禁止

  • インターネット → ALB → EC2 のみ許可となり、安全性が大きく向上します。

4-2. ターゲットグループの作成(EC2 を登録)

ALB がトラフィックを転送する先として、ターゲットグループを作成しました。

+ MyTargetGroup:
+   Type: AWS::ElasticLoadBalancingV2::TargetGroup
+   Properties:
+     Port: 80
+     Protocol: HTTP
+     VpcId: !Ref MyVPC
+     HealthCheckPath: /
+     Targets:
+       - Id: !Ref MyInstance

4-3. HTTP(80番)リスナーを作成

ALB が受けた HTTP リクエストをターゲットグループへ転送するためのリスナーを追加します。

+ MyALBListener:
+   Type: AWS::ElasticLoadBalancingV2::Listener
+   Properties:
+     LoadBalancerArn: !Ref MyALB
+     Port: 80
+     Protocol: HTTP
+     DefaultActions:
+       - Type: forward
+         TargetGroupArn: !Ref MyTargetGroup

4-4. ALB の DNS 名を出力

デプロイ後、ブラウザで ALB にアクセスする際に必要となる ALB の DNS 名を CloudFormation の Outputs に出力できるようにしました。

+ Outputs:
+   ALBDNSName:
+     Description: DNS name of the Application Load Balancer
+     Value: !GetAtt MyALB.DNSName

5. HTTPS(443番)対応と独自ドメインの設定

Webサイトを安全に公開するために、HTTPS (ポート443) 対応と、独自のドメイン名でアクセスできるようにRoute 53の設定を追加しました。

前提

  • ACM (AWS Certificate Manager) でSSL証明書は発行済みであること。
  • Route 53 でドメイン(ホストゾーン)は作成済みであること。

テンプレートを汎用的に使うため、証明書のARNやドメイン名は Parameters で外から渡せるようにしました。

AWSTemplateFormatVersion: '2010-09-09'
  Description: Create an EC2 instance with ALB (HTTPS & DNS support)
  
+ Parameters:
+   DomainName:
+     Type: String
+     Description: "The domain name (e.g., example.com)"
+   HostedZoneId:
+     Type: String
+     Description: "The Route 53 Hosted Zone ID"
+   CertificateArn:
+     Type: String
+     Description: "The ARN of the ACM Certificate"

5-1. ALB のセキュリティグループに HTTPS(443番)を追加

HTTPS通信(ポート443)を通すために、ALBのセキュリティグループにルールを追加しました。

ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP and HTTPS access for ALB
      VpcId: !Ref MyVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
+       - IpProtocol: tcp
+         FromPort: 443
+         ToPort: 443
+         CidrIp: 0.0.0.0/0

5-2. ALBリスナーの設定変更

  1. HTTPSリスナーの追加: ポート443で受け付けて、証明書を使って復号し、ターゲットグループへ転送する。
  2. HTTPリスナーの修正: ポート80に来たアクセスは、そのまま通すのではなく「HTTPSへリダイレクト」させる(常時SSL化)。
MyALBListener: # 既存のHTTPリスナーを「リダイレクト用」に変更
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref MyALB
      Port: 80
      Protocol: HTTP
      DefaultActions:
-       - Type: forward
-         TargetGroupArn: !Ref MyTargetGroup
+       - Type: redirect
+         RedirectConfig:
+           Protocol: HTTPS
+           Port: 443
+           StatusCode: HTTP_301

+ MyALBListenerHTTPS: # 新規追加:HTTPS用リスナー
+   Type: AWS::ElasticLoadBalancingV2::Listener
+   Properties:
+     LoadBalancerArn: !Ref MyALB
+     Port: 443
+     Protocol: HTTPS
+     Certificates:
+       - CertificateArn: !Ref CertificateArn
+     DefaultActions:
+       - Type: forward
+         TargetGroupArn: !Ref MyTargetGroup

Route 53 に A レコード(ALB エイリアス)を追加

取得しているドメイン(例: example.com)へのアクセスを、ALBへ流すためのAレコード(エイリアスレコード)を作成しました。
(※エイリアスレコード:ALB や S3 など、選択した AWS リソースにトラフィックをルーティングできるレコード)

+ MyDNSRecord:
+   Type: AWS::Route53::RecordSet
+   Properties:
+     HostedZoneId: !Ref HostedZoneId
+     Name: !Ref DomainName
+     Type: A
+     AliasTarget:
+       HostedZoneId: !GetAtt MyALB.CanonicalHostedZoneID
+       DNSName: !GetAtt MyALB.DNSName

おわりに

今回の文化祭アプリのインフラ構築では、CloudFormation を使って段階的に環境を作り上げていく中で、IaC のメリットを強く実感しました。特に良かったのは、次の 2 点です。

まず、AI と一緒に“バイブコーディング”で開発できることです。
AWS コンソールだけで作業していると、ALB や EC2、VPC といった情報が画面ごとに分散していて、全体像を AI と共有しづらいという課題があります。その点、CloudFormation はすべてが一つの YAML テンプレートとして表現されるため、AI に相談しながら「どこをどう変更すると構成がどう変わるか」を効率よく進められました。インフラでもここまで AI の恩恵を受けられるのは、IaC ならではだと感じました。

もうひとつは、削除と再構築のしやすさが、コスト削減に直結したことです。
文化祭の本番は短期間である一方、EC2 や ALB を起動しっぱなしにすると当然料金が発生し続けます。今回は 9 月に構築を終えた後、いったん CloudFormation スタックごと削除し、本番前の 1 週間で再構築する運用にしました。その結果、無駄なインフラ費用を大きく抑えることができました。この “必要なときだけサッと立て直せる” という点は、実開発でも非常に心強いメリットだと思います。

今回の取り組みを通じて、IaC の再現性・安全性・拡張性に加えて、学習効率とコスト最適化という、実践的な価値も体験できました。今回得た知識や経験を土台に、これからも少しずつインフラの理解を深めていきたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?