EC2 Image Builderで運用を楽にしてみよう!

記事タイトルとURLをコピーする

こんにちは、エデュケーショナルサービス課の小倉です。

2024年からパーソル&サーバーワークスというグループ会社で中途入社のエンジニア向けにトレーニングを行っています。
そのトレーニングの中で、要件に応じてAWSの構成を考える「RFPチャレンジ」というコンテンツがあります。構成を考える上で、だいたいの人がアクセス数が増えてきたときの対策としてEC2 Auto Scalingを使います。ただ、このEC2 Auto Scalingで利用するAMIの更新(パッチ適用など)については考慮できていなかったり、AMIからEC2作成、パッチ適用、AMI取得、起動テンプレート更新という手順を手動で行ったりというのをよく目にします。AWSではもっと楽にできるEC2 Image Builderという機能があるのでこちらを説明します。

EC2 Image Builderとは

Amazon Machine Image (AMI)やコンテナイメージのカスタマイズやテストを行うことができるフルマネージド型のサービスです。 先の説明にでてきた、AMIからEC2作成、パッチ適用、AMI取得、起動テンプレート更新というのを自動で行うことができます。

[AWS Black Belt Online Seminar] AWS EC2 Image Builder

構成図

今回の検証環境の構成図で、インターネットからHTTPでアクセスできるようにしておきます。 この環境でEC2 Image Builderを使って、EC2 Auto Scalingの起動テンプレートのAMIを更新します。

作業手順

EC2の作成

EC2 Auto Scalingで使用するAMIを作成するため、EC2を起動します。

EC2設定

  • AMI:Amazon Linux 2023
  • ネットワーク:デフォルトVPC
  • パブリック IP の自動割り当て:有効化
  • ファイアウォール:HTTPを許可
  • ユーザーデータ:以下を記入
#!/bin/bash -v
exec > >(tee /var/log/user-data.log || logger -t user-data -s 2> /dev/console) 2>&1
dnf -y update
dnf -y install httpd
echo 'Hello World!' > /var/www/html/index.html
systemctl start httpd.service
systemctl enable httpd

これでEC2を起動し、AMIの取得を行います。AMIを取得した後にはAMI IDを控えておきましょう(あとで使います)。

EC2 Auto Scaling環境の構築

CloudFormationテンプレートを用意しましたので、以下を実行して検証環境を準備してください。 パラメータの入力画面でWebAppImageIdに先ほど取得したAMI IDを入力します。

AWSTemplateFormatVersion: "2010-09-09"
Description: Auto Scaling test
Parameters:
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
  PublicSubnetACIDR:
    Type: String
    Default: "10.0.0.0/24"
  PublicSubnetCCIDR:
    Type: String
    Default: "10.0.1.0/24"
  PrivateSubnetACIDR:
    Type: String
    Default: "10.0.10.0/24"
  PrivateSubnetCCIDR:
    Type: String
    Default: "10.0.20.0/24"
  WebAppImageId:
    Description: Image Id
    Type: String
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: training-dev-vpc-web
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: training-dev-igw
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC
  PublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      CidrBlock: !Ref PublicSubnetACIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: training-dev-subnet-public-a
  PublicSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1c
      CidrBlock: !Ref PublicSubnetCCIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: training-dev-subnet-public-c
  PrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      CidrBlock: !Ref PrivateSubnetACIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: training-dev-subnet-private-a
  PrivateSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1c
      CidrBlock: !Ref PrivateSubnetCCIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: training-dev-subnet-private-c
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: training-dev-rt-public
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: training-dev-rt-private
  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetA
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetCRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetC
      RouteTableId: !Ref PublicRouteTable
  PrivateSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetA
      RouteTableId: !Ref PrivateRouteTable
  PrivateSubnetCRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetC
      RouteTableId: !Ref PrivateRouteTable
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC
      GroupName: training-dev-sg-alb-public
      GroupDescription: ALB Security Group for Training
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: training-dev-sg-alb-public
  SecurityGroupForWebAppInstance:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC
      GroupDescription: Web App Security Group for Training
      GroupName: training-dev-sg-webapp
      SecurityGroupIngress:
        - SourceSecurityGroupId: !Ref ALBSecurityGroup
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
      Tags:
        - Key: Name
          Value: training-dev-sg-webapp
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      VpcId: !Ref VPC
      Name: training-dev-tg-public
      Protocol: HTTP
      Port: 80
      Matcher:
        HttpCode: 200
      Tags:
        - Key: Name
          Value: training-dev-tg-public
  InternetALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: training-dev-alb-public
      Tags:
        - Key: Name
          Value: training-dev-alb-public
      Scheme: internet-facing
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Subnets:
        - !Ref PublicSubnetA
        - !Ref PublicSubnetC
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      LoadBalancerArn: !Ref InternetALB
      Port: 80
      Protocol: HTTP
  LaunchTemplate: 
      Type: AWS::EC2::LaunchTemplate
      Properties: 
        LaunchTemplateName: 20250603-template
        LaunchTemplateData:
          ImageId: !Ref WebAppImageId
          InstanceType: t3.micro
          SecurityGroupIds:
            - !Ref SecurityGroupForWebAppInstance
  ServerGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier:
        - !Ref PrivateSubnetA
        - !Ref PrivateSubnetC
      LaunchTemplate:
        LaunchTemplateId: !Ref LaunchTemplate
        Version: !GetAtt LaunchTemplate.LatestVersionNumber
      MaxSize: '2'
      MinSize: '2'
      TargetGroupARNs:
        - !Ref TargetGroup

10分くらい経過したら環境ができあがります。

EC2 Image Builderの設定

EC2 Image Builderのパイプラインを作成することで、AMIからEC2作成、パッチ適用、AMI取得、起動テンプレート更新を行うことができます。

1.EC2 Image Builderのコンソール画面を表示し、[イメージパイプラインを作成] をクリック
2.パイプラインの詳細を指定するの画面で、パイプライン名の入力、スケジュールオプションは手動を選択し、[次へ] をクリック
3.レシピを選択の画面で、まずは以下の赤で囲んであるところを選択、入力を行います。AMI IDは最初に作成したEC2から取得したAMIのIDを入力します。
4.下にスクロールして、コンポーネントの設定を行います。ビルドコンポーネントではAMIを作成するときに実行する内容を定義、テストコンポーネントではビルドした後に正常に稼働するかのテストを定義します。
今回は検証なのでセキュリティパッチを適用するだけを設定します。まず、[ビルドコンポーネントを追加] - [Amazon管理] をクリックします。画面右上の検索窓に update と入力し、結果に表示される update-linux にチェックを入れ、[レシピに追加] をクリックします。
同様にテストコンポーネントも追加します。
今回は再起動が正常に行われるかのテストを設定します。[テストコンポーネントを追加] - [Amazon管理] をクリックします。画面右上の検索窓で reboot と入力し、結果に表示される reboot-test-linux にチェックを入れ、[レシピに追加] をクリックします。
あとは変更せずに一番下までスクロールして、[次へ] をクリックします。

5.イメージ作成プロセスを定義するの画面で、デフォルトワークフローを選択して、[次へ] をクリックします。
6.インフラストラクチャ設定を定義するの画面で、サービスデフォルトを使用してインフラストラクチャ設定を作成する を選択して、[次へ] をクリックします。
7.ディストリビューション設定を定義するの画面で、新しいディストリビューション設定を作成する を選択と名前を入力し、起動テンプレートのAMIの更新を設定します。
起動テンプレート設定をクリックして、設定を表示します。[起動テンプレート設定を追加] をクリックし、CloudFormationで作成した起動テンプレートを選択します(テンプレートのまま実行すると 20250603-template で作成されています)。
あとは変更せずに一番下までスクロールして、[次へ] をクリックします。

8.確認の画面が表示されるので、内容を確認して [パイプラインの作成] をクリックします。

これで、パイプラインの作成が終わりました。
画面右上の [アクション] - [パイプラインの実行] をクリックするとAMIの更新を行うことができます。完了まで20分くらいかかりました。
起動テンプレートのバージョンを確認するとAMIが更新されていることが確認できます。
起動テンプレートのAMIが更新された後にAuto Scaling グループのインスタンスの更新を行うことで、最新のAMIでEC2を起動しなおすことができます。古いブログですが、こちらでインスタンスの更新について説明をしています。 blog.serverworks.co.jp

これで、設定は完了です。今後はこのEC2 Image Builderのパイプラインを実行するだけでAMIを更新することができるようになりました。

まとめ

EC2 Image Builderについて紹介しました。最初の設定はちょっと面倒かもしれないですが、このサービスを使うことでAMIのパッチ適用などが楽になる可能性があります。
すべては要件次第ではありますが、設計をする時に運用面も考慮できるとよりよくなると考えています。

小倉 大(記事一覧)

アプリケーションサービス部エデュケーショナルサービス課 札幌在住

AWSトレーニングの講師をしています。

最近は7歳の息子と遊ぶのが楽しいです!

Twitter: @MasaruOgura