【初心者向け】AWS CloudFormationでEC2を作成した時に困ったこと

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

みなさんこんにちは。ネコが好きなマネージドサービス部の塩野です。
いきなりでアレなんですけど、最近ちょっとだけ悩んでいることがありまして・・・

インスタやYoutubeでネコの動画を見ていると、無限に時間が溶けるの、なんとかなりませんかね・・(><)

それでは本題に入っていきましょう。今回はAWS CloudFormationでEC2リソースを作成しようとしたときに個人的に困ったことをいくつか記事にまとめてみました。

想定読者

  • AWS CloudFormationでEC2リソースを作成したい人
  • デプロイしたいイメージの最新版 ami の ID を毎回探してきてテンプレートにセットするのがめんどくさい人
  • とりあえず試してみようとインターネットでテンプレートを見つけてきて、試したけどなぜか動かなくて困っている人

AWS CloudFormationの概要

この記事を読んでいる人は、AWS CloudFormation が何かというのはご存じの人が多いと思いますが、改めてどういう機能なのか公式サイトから紐解いていきます。

AWS CloudFormation によって、AWS 関連リソースおよびサードパーティーリソースの集合体を Infrastructure as Code として扱うことでモデリングし、高速かつ安定的にプロビジョニングし、ライフサイクル全体にわたって管理することが容易になります。必要なリソースとその依存関係を CloudFormation テンプレートに記述すれば、1 つのスタックとして一括で起動し、設定できます。

aws.amazon.com

例えばLinuxのマシンを1台プライベートサブネットの環境で構築したくて、それをGUIでポチポチやってたら、慎重な人でも最初の数回は気を付けながら作業していても、回数をこなす毎に設定忘れとか余計なところをさわってミスしたとかあるでしょうし、やる人によっては初見の勘違いなどによる設定ミスなどによって同じものを作ろうとしていても全然別のものができていたなんてことがあると思います。そういう面倒なことをテンプレートを作って毎回同じものを同じ品質でつくろうよというのがInfrastructure as Codeのコンセプトであり、AWS CloudFormation の超ざっくりとした機能概要ということです。

標準テンプレートでEC2を作った時にハマったポイントとその時の作成の流れ

1.よくあるEC2作成テンプレートを少しだけ加工してNameタグをつけたものです。コードの途中にある <amiのIDをここに入力> の部分には、AWSマネジメントコンソールのEC2の画面内にあるAMI カタログからamiのIDをコピーして貼り付けたものをテキストファイルに「ec2-instance.yaml」という名前で保存します。

ec2-instance.yaml

AWSTemplateFormatVersion: 2010-09-09
Description: A simple EC2 instance
Resources:
  MyEC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: <amiのIDをここに入力>
      InstanceType: t2.micro
      Tags:
        - Key: "Name"
          Value: "TestInstance"

2.AWSマネジメントコンソールからAWS CloudFormationを開き、「新しいリソースを使用」を選択します。

3.テンプレートファイルのアップロードから、先ほど保存した「ec2-instance.yaml」を選択し、次へをクリックします。

4.任意のスタック名を入力します。ここでは「ec2-instance」としておきます。

5.そのまま次へをクリックして次の画面に進みます。

6.送信ボタンをクリックしてCloudFormationを実行します。

すると、下記の通りエラーでCloudFormationの作成が失敗しました。CloudFormationの作成が失敗した理由として、私の環境はデフォルトVPCを削除しているため、テンプレートの構成要素としては必須でないNetworkインターフェイスの作成場所を見つけることができずに失敗している状況になります。

それではダメだった部分を改修して正しく動くコードに直したいと思います。

改修後のコード

AWSTemplateFormatVersion: 2010-09-09
Description: A simple EC2 instance
Resources:
  MyEC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: <amiのIDをここに入力>
      InstanceType: t2.micro
      Tags:
        - Key: "Name"
          Value: "TestInstance"
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeleteOnTermination: true
          DeviceIndex: "0"
          SubnetId: <サブネットID>

先ほどのコードの下に「NetworkInterfaces」のセクションが追加されて、サブネットIDを指定するようなコードに変わりました。 サブネットIDはAWSマネジメントコンソールのVPCの画面内にあるサブネットのメニューから調べて入力します。 今度はインスタンスの作成に成功したと思いますが、必須項目でなくてもAWSの環境次第で必要になる項目があるということは注意が必要なようです。

必須項目を設定する際に楽をするポイント

テンプレートでEC2を作るときにサブネットIDや ami id を毎回探すのってやっぱり面倒じゃないですか? 私はめんどくさがりなので、正直なところ毎回「めんどくさいなぁ・・」と思いながら入力していました。

こうしためんどくさいを自動的に入力する機能が実は標準で備わっていて、 テンプレート内でパラメーターを使用するとこういっためんどくさい部分をある程度自動的に任せることができるようになります。

docs.aws.amazon.com

このパラメーターは下記の3つのパターンから選択してコードを作ることができます。

  • 設定画面でユーザーが自由入力したものを適用する
  • 設定画面でユーザーが選択したものを適用する
  • AWSから提供されているAWS 固有のパラメータを使用する

例えば、インスタンスの名前を自由入力形式で入力したいときは下記のようなコードになります。

Parameters:
  InstanceName:
    Description: "Imput instance name"
    Type: "String"

また、インスタンスタイプを選択式でユーザーが入力したいときは下記のようなコードになります。

Parameters:
  InstanceType:
    Description: "Select instance type"
    AllowedValues:
      - "t2.micro"
      - "t2.small"
    Type: "String"

次に、VPCやサブネットなどの情報を選択式でユーザーが入力したいときは下記のようなコードになります。

Parameters:
  SubnetId:
    Description: "Select subnet "
    Type: "AWS::EC2::Subnet::Id"

最後に、インスタンスIDなどの情報を自動的に入力したいときは下記のようなコードになります。

Parameters:
  LatestAmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'

※Amazon Linux 2023の場合は下記URLに詳細情報が記載されています

docs.aws.amazon.com

※Ubuntuの場合は下記URLに詳細情報が記載されています canonical-aws.readthedocs-hosted.com

それ以外のイメージについては、基本的に上記CloudFormationのコードの中でDefaultの値を変更する前提で、AWS Systems Manager Parameter Storeに記載の値を参考に設定することができます。

※赤枠部分の値を使用する

最終的に完成したコード

ステップバイステップでそれぞれの項目を見た後で完成形のコードを見ると、 どこの部分に注意しながらどう作っていけばよいか理解が深まりやすいと思います。

AWSTemplateFormatVersion: 2010-09-09
Description: A simple EC2 instance
Parameters:
  InstanceName:
    Description: "Imput instance name"
    Type: "String"
  InstanceType:
    Description: "Select instance type"
    AllowedValues:
      - "t2.micro"
      - "t2.small"
    Type: "String"
  SubnetId:
    Description: "Select subnet"
    Type: "AWS::EC2::Subnet::Id"
  LatestAmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'
Resources:
  MyEC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      Tags:
        - Key: "Name"
          Value: !Ref InstanceName
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeleteOnTermination: true
          DeviceIndex: "0"
          SubnetId: !Ref SubnetId

総括

もともとはAWS CloudFormationでEC2のami idを入力するのが面倒だなという所から始まりまして、検証を進めていく上で公開しているテンプレートが動かんぞ?!というドツボにハマった結果、自分もステップバイステップでコードの切り分けを行いながら普段ほとんど書かないAWS CloudFormationのコードの書き方について理解を深めました。あまり細かくは書かれていないけどハマリやすいポイントがあったり、テンプレートとして使いまわす上でここは知っておいた方がいいという点がいくつかありましたので、そのあたりの情報がどなたかのお役に立てれば幸いです。

◆ 塩野 正人
◆ マネージドサービス部 所属
◆ X(Twitter):@shioccii
◆ 過去記事はこちら

前職ではオンプレミスで仮想化基盤の構築や運用に従事。現在は運用部隊でNew Relicを使ってサービス改善に奮闘中。