ちょっと話題の記事

AWS CloudFormationのテンプレートを細かく分けて確認してみた

AWS CloudFormationのテンプレート、長!となったのは私だけでしょうか。同志の皆さん、一緒にテンプレートを少しずつ確認して、テンプレート職人を目指しましょう。こちらを読む際、是非テンプレートも横に開きながら、読んでみてくださいね!
2020.07.02

みなさんどうも、新卒エンジニアのたいがーです。
今年も半年が過ぎましたね。早いものです。

それぞれのリソースの立ち上げはマネジメントコンソールやAWS CLIでやってみたけど、そろそろInfrastructure as Codeを触ってみたい!!Cloud Formationを使ってみよう!!という気持ちになっていらっしゃる方はいませんか?

私です。

しかし、実際のAWS CloudFormatinのテンプレートを見てみるも、長いな…どこから始めたらいいんだ…となってしまった方はいませんか?

そうです、私です

そんな今回は、CloudFormationのテンプレートのへ理解を深めるため、AWS CloudFormation サンプルテンプレートの中にある東京リージョンのサービスサンプルテンプレートの中でも、Amazon VPCにおける単一のAmazon EC2というテンプレートを分解していこうと思います。

こちらの記事を読みながら、みなさんも是非テンプレートを上から見てみてください!

そもそも、AWS CloudFormationとはどういうものなのかを振り返っていきましょう。

AWS CloudFormationとは

AWS CloudFormation では、プログラミング言語またはシンプルなテキストファイルを使用して、あらゆるリージョンとアカウントでアプリケーションに必要とされるすべてのリソースを、自動化された安全な方法でモデル化し、プロビジョニングできます。

AWS CloudFormationはテンプレートを作成することによって、リソースのプロビジョニングや設定をしてくれるサービスです。つまり、ユーザーはAWSリソースを個別で作成、設計する必要がなくなります。複製や制御、変更の追跡等も簡単に行うことができます。

より細かく分けて理解していきたいという方は、こちらのブログを参考にしてみてください!
こちらではYAMLファイルを少しずつ書いていきながら、理解を深めていく内容になっています。

AWS CloudFormationのテンプレートは、JSON、またはYAMLで記載します。今回のテンプレートは、JSONファイルですね。
まずは、テンプレートを大きい範囲から見ていきましょう。

分解していく前に

一度ご自身のマネジメントコンソールにて、テンプレートをこちらから実行してみることをお勧めします。

一応最後の章で、私が実際に実行したものを載せているのですが、是非ご自身でもやってみてくださいね!そうすることによって、特に"Parameters"の意味が理解しやすくなるのでお勧めです!

大枠から理解していく

こちらのCloudFormationのテンプレートは、このような構造で作成します。

{
    "AWSTemplateFormatVersion" : "2010-09-09",
  
    "Description" : "このテンプレートの説明は、ここに書く",
        
    "Parameters":{
        // それぞれのテンプレートをカスタマイズする一連の入力を決定する
    },
    
    "Mappings" : {
        // キーと名前付きの一連の値とを対応させる
    },

    "Resources":{
        // このテンプレートで作成するAWSリソースとそのリソースの関係を書く
    },
    
    "Outputs":{
        // 戻り値 スタックの作成者に表示される、一連の値を示す
    }
}    

AWSTemplateFormatVersion

テンプレートの機能を識別するものです。
任意入力となっています。
最新のテンプレートは2010-09-09であり、現時点で唯一の有効値です。

Description

このテンプレートがどういったものかを説明するところになっています。
より詳しく書くことにより、このテンプレートがどういう動きをするのかを伝わり易くなるでしょう。

"Description"は、"AWSTemplateFormatVersion"のに記述する必要があります。

Parameters

AWS CloudFormationでは、"Parameters"で設定するとスタックを作成、更新するたびにテンプレートにカスタム値を入力できます。
そのため、それぞれのスタック作成時に設定したい、インスタンスタイプや公開鍵などは、パラメータでカスタマイズするのも良いかもしれません。

ここで設定されていない場合は、それぞれデフォルト値が指定されます。

ちなみにテンプレート内のパラメータは最大60個までと決められており、各パラメータはテンプレート内に同一のものが存在しないようにする必要があります。

InstanceTypeParameterは、t2.microがデフォルトとして設定されているので、変更したいという場合はこちらで設定する必要があります。今回は"t2.small"がデフォルトに変更されていますね。

Mappings

キーと名前付きの一連の値が対応づけられます。
今回のテンプレートは、例に挙げている東京リージョン以外のリージョンでも展開されています。そのため、それぞれのリージョンの例がどこに格納されているのか、それぞれのリージョンでのAMI IDはどれなのかをマッピングしています。

Resources

AWSリソースを宣言します。こちらは必須項目です。

今回のテンプレートの場合、上からこのような順番で宣言しています。

  • VPCの作成
  • Subnetの作成
  • インターネットゲートウェイの作成
  • ゲートウェイのアタッチ
  • ルートテーブルの作成
  • ルートの作成
  • サブネットへのルートテーブルの関連付け
  • NACL(ネットワークアクセスコントロールリスト)の作成
  • NACLの設定(インバウンド/アウトバウンド)
  • NACLのサブネットへの関連付け
  • ElasticIPの取得
  • セキュリティグループの作成
  • EC2インスタンスの作成

リソースにも属性が存在し、それぞれを細かく設定できるようになっています。
(詳しくは下記に記載します。)

Outputs

CloudFormationを実行した際に、表示される戻り値を設定することができます。 今回の場合は、作成したEC2インスタンスのパブリックIPが出力される設定になっています。

それぞれの役割がわかったところで、テンプレートの中にあり、より細かく設定されている部分を見ていきましょう。

テンプレートをより詳細に見ていく

ここからはそれぞれの属性の中で設定できる、より細かい部分を確認します。
(AWSTemplateFormatVersion、Description、Mappingsに関しては上記で説明したため、省きます。)

それでは、"Parameters"から見ていきましょう!

Parameters

こちらの属性では、Typeが必須となっています。

Type

パラメータのデータ型を宣言するところです。指定できるものとしては以下の通り。

今回の場合では、String型、AWSの固有のパラメータ型が指定されています。

"InstanceType"ではString型、"KeyName"ではAWSの固有のパラメータ型でKey名が指定されるように設定されています。
実際に実行してみると、現時点で作成されている公開鍵が選択できるようになっていました。

他の型も含め、さらっと説明します。

Number

整数、小数点値が指定可能です。数値として検証しますが、!Ref組み込み関数など、テンプレート内の他の場所で使用した場合は、文字列として扱われます。

List

カンマで区切られた配列を指定できます。こちらも、整数、小数点値が指定可能です。扱いに関しては"Number"と同じく、他の場所で使用すると文字列として扱われます。

CommaDelimitedList

こちらは数字ではなく、文字列の配列です。

AWSの固有のパラメータ型

既存のAWS値を指定する際に使います。アベイラビリティゾーン、EC2インスタンスID等が指定できます。詳しくはこちらからご確認ください!

SSMパラメータタイプ

Systems Managerパラメータ内の既存のパラメータを指定できます。

"Type"属性の次は、Defaultです。

Default

こちらを記載する事によって、そのパラメータで選択されるデフォルト値を設定することが可能です。

今回の場合であれば、InstanceTypeは"t2.small"、SSHのLocationには"0.0.0.0/0"がデフォルト値として表示されているはずです。

Allowed Values

入力を許可される値を入力します。

ここでDefaultで設定した値を記載するのを忘れないようにしましょう。

Min / Max Length

TypeでString型を指定した際、使用できる最小/最大の文字数です。今回の場合であれば。セキュリティグループの設定の際に使うIPアドレスの指定で、最小値が9、最大値が18に設定されています。こちらを設定することで、IPアドレスの間違いを少しでも事前に防ぐことができますよね。

AllowedPattern

String形に使用できるパターンを表す正規表現です。今回の場合であれば。IPアドレスの指定となっているので(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})となっています。

ConstraintDescription

事前に決めていた制約に沿わない場合、表示するメッセージです。パラメータの"Allowed"がついている部分ですね。
今回の例の中で言うと、一番上のインスタンスの場合、"AllowedValues"で指定された以外のインスタンスが選択された場合、"must be a valid EC2 instance type."と表示されます。

Mappingの説明は上で行ったので、"Resources"属性について書いていきたいと思います。

Resources

どういうリソースを構成するかを書いていく、"Resource"属性です。

今回のテンプレートで使われているのは、こちらの属性です。

  • 論理ID
  • ProPerties
  • DependsOn
  • Metadata

順に説明していきます。

論理ID

テンプレート内での名前のようなものです。今回のテンプレートでは、各リソースが一つずつしかないために各リソース名がつけられています。

例えばSubnetを二つ作るときに、"PrivateSub""PublicSub"と論理IDをつける事により、どちらがどのサブネットを区別させます。そうする事によって、テンプレート内で論理IDでリソースを指定することができます。

なので、論理IDはテンプレート内で一意である必要があります。

Type

リソースタイプは、どのリソースなのかを宣言しています。
EC2インスタンスであれば、 "AWS::EC2::Instance"のような形です。

全てのリソースタイプの一覧は、こちらからご覧ください。

また、こちらの一覧から下記の"Properties"で設定できる項目に関しても表記されているので、実際にCloudFormationでテンプレートを作成する際には、確認する必要があります。

Properties

リソースに追加できる設定です。作成したリソースをそれぞれ紐づけるとき、設定する値を指定する場合などに使えます。

今回は、リソースを紐づけるパターンをSubnetを例に出して説明しましょう。

そもそもSubnetを作成するとき、どのVPC内にSubnetを作るのか指定する必要があります。つまり、VPC IDに今回作ったVPCのIDを指定する必要があるので{"Ref": "VPC"}と指定しています。

また"Properties"では、各リソースにはタグづけすることができます。今回の場合でいうと、Keyを"Application"、"Value"をスタックIDで指定する事により、どのCloud Formationのスタックで作成したのかということが分かりやすくなっていますよね。

今回のテンプレートで個人的に一番大変だと思ったのは、NACLの設定です。NACLは、デフォルトで全てのインバウンド、アウトバウンドトラフィックが拒否されているので、一つずつ許可するように指定していく必要があります。ルールやプロトコル、CIDRブロックを指定して何番から何番ポートを開けるのか、それぞれ細かく設定できます。

DependsOn

特定のリソースが他のリソースに続けて作成されるように指定できます。今回の場合であれば、ルートの作成、IPアドレスの取得、EC2インスタンスの作成が全てインターネットゲートウェイがアタッチされた後に作成されるように指定されています。

現在、次のリソースは、関連付けられたパブリック IP アドレスを持ち、VPC 内にある場合、VPC ゲートウェイのアタッチメントに依存します。

Auto Scaling グループ

Amazon EC2 インスタンス

Elastic Load Balancing ロードバランサー

Elastic IP アドレス

Amazon RDS データベースインスタンス

インターネットゲートウェイを含む Amazon VPC のルート

(DependsOn 属性が必要なときより)

なので、上記に当てはまるものを作成する場合に関しては、DependsOn属性を設定する必要があります。

ただ、 Refで指定されているようなリソースに関しては、先に指定されているリソースが作成されるという関係性もあります。

MetaData

構造化データを関連付けすることができます。今回の場合は、"AWS::CloudFormation::Init"が使用されています。このメタデータキーは、cfn-init ヘルパースクリプトの設定タスクを定義します。ちなみに、cfn-hup ヘルパーは、リソースメタデータの変更を検出し、変更が検出された場合は、ユーザーが指定した操作を実行するデーモンです。こちらは、EC2インスタンスでアプリケーションの設定とインストールを行う場合に便利です。

さて、今までは設定されていたものを見ていきました。

ここからは、実際に実行してみましょう。

やってみよう

サービスの一覧ページから今回分解してきたテンプレートを選択し、Launch stackします。

テンプレートがS3に格納されているので、そちらを呼び出してきます。

続いて、スタックの名前、パラメータを選択します。

InstanceTypeには、先ほど設定したデフォルト値である"t2.small"が入っています。インスタンスタイプを選択してから公開鍵を選択します。SSH LocationはMY IPに設定しました。

続いて、タグなどを個別に指定したい場合はこちらを設定していきます。

今回は詳細オプションは設定せず、そのままスタックを実行します。

CREATE_COMPLETEと表示されたら、スタックを開き、出力を見てみましょう!

先ほど"Outputs"で設定されていた通りにURLが吐き出されていますね!

続いて、実際にサイトの方を見てみるとこんな感じです。

EC2インスタンスにもログインして、実際に/var/www/html内を覗いてみました。

Metadata属性で設定されていた通りになっていますね!

テンプレート職人になりたい

AWS CloudFormationのテンプレートを書く際、なかなかうまくいかなかったため、公開されているテンプレートを分解してみました。

みなさんも一緒にテンプレート職人になりましょう!

参考資料