【CloudFormation入門】CloudFormation Templateの基本構成を詳しく理解する【第三回】

前回は、CloudFormationを実際に動かして、YAMLでAWSリソースを作成してみました。

今回は、もう少しCloudFormation Templateの中身について詳しく見ていきます。

CloudFormation Templateには、いくつかの「セクション」があります。

例えば、以下のようなテンプレートです。

AWSTemplateFormatVersion: '2010-09-09'

Description: Sample CloudFormation Template

Parameters:
  Environment:
    Type: String
    Default: dev

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

Outputs:
  BucketName:
    Value: !Ref SampleBucket

初めて見ると、

AWSTemplateFormatVersionって何?

Parametersには何を書くの?

ResourcesにはAWSのリソースを全部書くの?

Outputsって何のためにあるの?

となると思います。

そこで今回は、CloudFormation Templateの各セクションについて、

  • 何のために存在するのか
  • どのような値を設定できるのか
  • 実際にどう考えて設定するのか

という順番で見ていきます。


CloudFormation Templateの全体像

まずはCloudFormation Templateの全体像を見てみましょう。

CloudFormation Templateには、主に以下のセクションがあります。

AWSTemplateFormatVersion: '2010-09-09'

Description: ...

Metadata:
  ...

Parameters:
  ...

Mappings:
  ...

Conditions:
  ...

Transform:
  ...

Resources:
  ...

Outputs:
  ...

ただし、すべてのセクションを書く必要があるわけではありません。

例えば、最小限のCloudFormation Templateなら、

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

だけでも動作します。

つまり、最初からすべてのセクションを覚える必要はありません。

まずは、

Parameters
    ↓
Resources
    ↓
Outputs

という3つを理解するところから始めると分かりやすいです。


① AWSTemplateFormatVersion

最初に登場するのが、

AWSTemplateFormatVersion: '2010-09-09'

です。

これはCloudFormation Templateの形式を指定するための項目です。

現在利用されている値は、

AWSTemplateFormatVersion: '2010-09-09'

です。

ここで少し不思議なのが、

「2010年って古くない?」

という点です。

この値は「2010年に作成されたTemplate」という意味ではありません。

CloudFormationのテンプレート形式を示すバージョン値です。

また、このセクションは必須ではありません。

そのため、

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

のようにAWSTemplateFormatVersionを省略してもTemplateを作成できます。

どう考える?

基本的には、

CloudFormation Templateを書くなら、とりあえず'2010-09-09'を指定する

くらいで問題ありません。

値を自分で設計するものではないので、ここで悩む必要はありません。


② Description

次に、

Description: Sample CloudFormation Template

です。

これはTemplateの説明を書くためのセクションです。

例えば、

Description: Development environment for sample application

と書けば、

「サンプルアプリケーションの開発環境」

という説明になります。

日本語も記述できますが、チーム開発では英語で統一するケースもあります。


Descriptionには何を書く?

ここは、

「このTemplateは何を作るためのものなのか?」

を考えます。

例えば、

Description: Web application infrastructure

ならWebアプリケーション用のインフラ、

Description: Production environment

なら本番環境用、

Description: S3 bucket for application logs

ならアプリケーションログ保存用のS3バケット、

ということが分かります。

DescriptionはAWSリソースの設定値というより、Templateの目的を人間に伝えるための情報と考えると分かりやすいです。


③ Metadata

Metadataというセクションもあります。

Metadata:
  ...

Metadataは、Templateに関する追加情報を記述するために使用します。

例えば、CloudFormationのパラメータ入力画面をカスタマイズするために利用できます。

代表的な用途として、

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Environment Settings
        Parameters:
          - Environment

のような設定があります。

これによってCloudFormationのパラメータ入力画面を整理できます。

ただし、最初の段階ではMetadataを無理に覚える必要はありません。

どう考える?

Metadataは、

「CloudFormationがAWSリソースを作るための設定」というより、「Templateに付随する補足情報」

と考えるとよいでしょう。


④ Parameters

ここから重要になってきます。

Parameters:
  Environment:
    Type: String
    Default: dev

Parametersは、Stackを作成するときに外部から値を渡すための仕組みです。

例えば、

Parameters:
  Environment:
    Type: String
    Default: dev

とすると、Stack作成時にEnvironmentという値を指定できます。

例えば、

Environment = dev

や、

Environment = prod

といった値です。


Parametersには何を入れる?

ここが重要です。

Parametersを考えるときは、

「Templateの中で、環境によって変わる値は何か?」

と考えます。

例えば、

開発環境
  ↓
dev

本番環境
  ↓
prod

で値が変わるのであれば、

Parameters:
  Environment:
    Type: String
    Default: dev

のようにできます。


Parametersの代表的なType

Parametersでは、入力値の型を指定できます。

例えば、

Parameters:
  Environment:
    Type: String

なら文字列です。

他にも、

Type: Number

なら数値、

Type: List<AWS::EC2::AvailabilityZone::Name>

ならAvailability Zoneのリスト、

などがあります。

AWSリソースを選択させるためのAWS固有のParameter Typeもあります。

例えば、

Type: AWS::EC2::KeyPair::KeyName

とすれば、EC2のKey Pairを選択するParameterにできます。


Parametersを考えるときのポイント

Parametersを設計するときは、

Templateを書く
      ↓
環境によって値が変わる?
      ↓
YES
      ↓
Parameterにする

と考えると分かりやすいです。

例えば、EC2のインスタンスタイプが環境によって、

dev  → t3.micro
prod → t3.large

と変わるなら、Parameterにする方法があります。

Parameters:
  InstanceType:
    Type: String
    Default: t3.micro

そしてResource側で、

Resources:
  SampleInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType

とします。

こうすると、

Templateそのものを変更せず、Stack作成時の値だけ変更する

という使い方ができます。


⑤ Mappings

Mappingsは、固定的な対応表をTemplate内に定義するためのセクションです。

例えば、

Mappings:
  EnvironmentMap:
    dev:
      InstanceType: t3.micro
    prod:
      InstanceType: t3.large

とすると、

dev
 └─ t3.micro

prod
 └─ t3.large

という対応関係を作れます。


Parametersとの違い

ここは初心者が混乱しやすいポイントです。

ざっくり分けると、

Parameters

Stack作成時にユーザーから値を受け取る

Mappings

Templateの中にあらかじめ対応表を持っておく

という違いです。

例えば、

Parameters:
  Environment:
    Type: String

で、

dev
prod

をユーザーから受け取ります。

そして、

Mappings:
  EnvironmentMap:
    dev:
      InstanceType: t3.micro
    prod:
      InstanceType: t3.large

で、

dev → t3.micro
prod → t3.large

という対応関係を定義できます。


⑥ Conditions

Conditionsは、条件によってResourceや設定を切り替えるためのセクションです。

例えば、

本番環境の場合だけCloudWatch Alarmを作成したい

というケースがあります。

その場合、

Conditions:
  IsProduction: !Equals
    - !Ref Environment
    - prod

のような条件を作れます。

そしてResource側で、

Resources:
  ProductionAlarm:
    Type: AWS::CloudWatch::Alarm
    Condition: IsProduction

と指定します。

これによって、

Environment = dev
        ↓
Alarmを作らない

Environment = prod
        ↓
Alarmを作る

という制御ができます。


Conditionsを考えるときのポイント

Conditionsは、

「環境や設定によって、Resourceを作る・作らないを切り替えたいか?」

と考えると分かりやすいです。

例えば、

開発環境
 → 監視不要

本番環境
 → 監視が必要

ならConditionsを使う候補になります。


⑦ Transform

Transformは、Templateを処理するための仕組みです。

例えば、AWS SAMを利用する場合、

Transform: AWS::Serverless-2016-10-31

のように指定します。

Transformを利用すると、CloudFormation Templateを拡張したり、特定の構文を変換したりできます。

ただし、通常のCloudFormationを学ぶ段階では、まず後回しにして問題ありません。

どう考える?

Transformは、

「CloudFormation Templateをそのまま使うのではなく、追加の変換処理を入れたい」

ときに登場するもの、と考えておけば十分です。


⑧ Resources

そして、CloudFormationで最も重要なのがResourcesです。

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

ここに、実際にAWS上へ作成するリソースを定義します。

例えばS3なら、

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

EC2なら、

Resources:
  SampleInstance:
    Type: AWS::EC2::Instance

Lambdaなら、

Resources:
  SampleFunction:
    Type: AWS::Lambda::Function

という形になります。


Resourcesを考えるときのポイント

ここでは、

「このシステムを動かすために、AWS上に何が必要なのか?」

と考えます。

例えばWebアプリケーションなら、

Webアプリケーション
       ↓
必要なAWSリソースを考える

VPC
 ├─ Subnet
 ├─ Route Table
 └─ Internet Gateway

ALB

EC2

RDS

というように、必要なAWSリソースを洗い出します。

その後、

Resources:
  VPC:
    Type: AWS::EC2::VPC

  WebServer:
    Type: AWS::EC2::Instance

  Database:
    Type: AWS::RDS::DBInstance

のようにTemplateへ落とし込んでいきます。

つまり、Resourcesを書く前に、

「AWS上にどんな構成を作りたいのか」

を考えることが重要です。


ResourceのProperties

ResourceにはPropertiesという設定があります。

例えばS3バケットなら、

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: sample-example-bucket

とできます。

ここで、

Type: AWS::S3::Bucket

が、

何を作るのか

を表しています。

一方、

Properties:
  BucketName: sample-example-bucket

は、

そのリソースをどのような設定で作るのか

を表します。


Propertiesには何を入れる?

ここで重要なのは、

ResourceによってPropertiesに指定できる値が違う

ということです。

例えばS3バケットとEC2インスタンスでは、必要な設定が当然異なります。

S3なら、

Properties:
  BucketName: ...

EC2なら、

Properties:
  ImageId: ...
  InstanceType: ...
  SubnetId: ...

というように、それぞれ設定項目が異なります。

そのため、

「Propertiesには何を書けばいいの?」

となった場合は、CloudFormationの各Resource Typeのドキュメントを確認します。


⑨ Outputs

最後にOutputsです。

Outputs:
  BucketName:
    Value: !Ref SampleBucket

Outputsは、Stack作成後に外部へ出したい情報を定義する場所です。

例えば、

作成したS3バケットの名前を確認したい

という場合、

Outputs:
  BucketName:
    Value: !Ref SampleBucket

とできます。

Stackを作成すると、Outputsから、

BucketName
    ↓
作成されたS3バケット名

を確認できます。


Outputsを考えるときのポイント

Outputsでは、

「このStackを作ったあと、外部から知りたい情報は何か?」

と考えます。

例えば、

作成したVPCのID
作成したSubnetのID
作成したALBのDNS名
作成したS3バケット名
作成したLambdaのARN

などです。

特に、別のStackや外部システムから利用する値を出したい場合に便利です。


実際にはどういう順番でTemplateを考える?

ここまで各セクションを説明しました。

では、実際にCloudFormation Templateを書くとき、どのような順番で考えればよいのでしょうか。

個人的には、以下の順番で考えると分かりやすいです。

① 何を作りたい?
        ↓
② 必要なAWSリソースは?
        ↓
③ Resourceを定義
        ↓
④ 環境によって変わる値は?
        ↓
⑤ Parametersを定義
        ↓
⑥ 条件によって変える必要は?
        ↓
⑦ Conditions / Mappingsを検討
        ↓
⑧ 作成後に必要な情報は?
        ↓
⑨ Outputsを定義

最初から、

「Parametersには何を書こう?」

と考える必要はありません。


まず「何を作りたいか」を考える

例えば、

EC2を1台作りたい

とします。

まずは必要なものを考えます。

EC2を作りたい
   ↓
AMIが必要
   ↓
Instance Typeが必要
   ↓
Subnetが必要
   ↓
Security Groupが必要

すると、必要なResourceが見えてきます。

EC2
 ├─ Security Group
 └─ Subnet

既存のVPCやSubnetを使うのであれば、それらをCloudFormationで作る必要はありません。

逆に、新しくネットワーク環境も作るのであれば、

VPC
 ├─ Subnet
 ├─ Route Table
 └─ Internet Gateway
       ↓
     EC2

のようにResourceが増えます。


次に「何が変わるか」を考える

Resourceが決まったら、

「この値は環境によって変わる?」

と考えます。

例えば、

dev
InstanceType = t3.micro

prod
InstanceType = t3.large

なら、InstanceTypeをParameterにする候補になります。

Parameters:
  InstanceType:
    Type: String
    Default: t3.micro

一方、

どの環境でも必ず同じ値

なのであれば、必ずしもParameterにする必要はありません。

この考え方が重要です。

何でもParameterにすればいいわけではありません。


最後に「何を知りたいか」を考える

Resourceを作ったあと、

「作成されたResourceの何を知りたい?」

を考えます。

例えばALBを作ったのであれば、

ALBのDNS名

を知りたいかもしれません。

S3なら、

バケット名

EC2なら、

Instance ID

などです。

必要であればOutputsに追加します。


実践:S3バケットを作るTemplate

ここまでの考え方を使って、S3バケットを作ってみます。

まず、

S3バケットを作りたい

と考えます。

必要なResourceは、

S3 Bucket

です。

次に、

バケット名を環境によって変更したい

とします。

そこでParameterを定義します。

Parameters:
  Environment:
    Type: String
    Default: dev

そしてResourceを定義します。

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

最後に、

作成されたバケット名を確認したい

のでOutputsを追加します。

Outputs:
  BucketName:
    Value: !Ref SampleBucket

最終的には、

AWSTemplateFormatVersion: '2010-09-09'

Description: Sample S3 Bucket

Parameters:
  Environment:
    Type: String
    Default: dev

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

Outputs:
  BucketName:
    Value: !Ref SampleBucket

となります。

ただし、この例ではEnvironmentをParameterとして定義しているものの、Resource側ではまだ利用していません。

つまり、

Environment
    ↓
Parameterとして受け取る
    ↓
Resourceで利用していない

という状態です。

このようなParameterは意味がないので、実際のTemplateでは、

「本当にParameterとして外から値を受け取る必要があるのか?」

を考える必要があります。


Templateを設計するときの考え方

ここまでを整理すると、CloudFormation Templateは以下のように考えると分かりやすいです。

┌─────────────────────────┐
│ 何を作りたい?            │
└────────────┬────────────┘
             ↓
┌─────────────────────────┐
│ Resources               │
│ AWSリソースを定義する     │
└────────────┬────────────┘
             ↓
┌─────────────────────────┐
│ 環境によって変わる?       │
└────────────┬────────────┘
             ↓
       Yes ───────→ Parameters
             │
             ↓
┌─────────────────────────┐
│ 条件によって変わる?       │
└────────────┬────────────┘
             ↓
       Yes ───────→ Conditions
             │
             ↓
┌─────────────────────────┐
│ 固定の対応表が必要?       │
└────────────┬────────────┘
             ↓
       Yes ───────→ Mappings
             │
             ↓
┌─────────────────────────┐
│ 作成後に知りたい値は?      │
└────────────┬────────────┘
             ↓
          Outputs

このように考えると、CloudFormationの各セクションを暗記する必要がなくなります。


すべてのセクションを使う必要はない

最後に、もう一つ覚えておきたいことがあります。

CloudFormation Templateを作るときに、

AWSTemplateFormatVersion:
Description:
Metadata:
Parameters:
Mappings:
Conditions:
Transform:
Resources:
Outputs:

を全部書く必要はありません。

例えば、

Resources:
  SampleBucket:
    Type: AWS::S3::Bucket

だけでも立派なCloudFormation Templateです。

最初は、

Resources

を理解する。

↓

Templateの中で変更したい値が出てきたら、

Parameters

を使う。

↓

条件分岐が必要になったら、

Conditions

を使う。

↓

固定の対応表が必要なら、

Mappings

を使う。

↓

作成したResourceの情報を外へ渡したければ、

Outputs

を使う。

というように、必要になったタイミングでセクションを追加していくのがおすすめです。


まとめ

CloudFormation Templateは、単なる「AWSリソース一覧」ではありません。

Templateの中には、

Templateの説明
        ↓
入力値
        ↓
条件や対応表
        ↓
作成するAWSリソース
        ↓
作成後に外へ渡す情報

という情報を定義できます。

特に最初は、以下の3つを押さえておけば十分です。

セクション役割考えること
Parameters外部から値を受け取る環境によって変わる値は?
ResourcesAWSリソースを作る何を作りたい?
Outputs作成した値を外へ出す作成後に何を知りたい?

そして、Templateを書くときは、

「どんなAWS環境を作りたいのか?」

から考えることが重要です。

いきなりYAMLを書き始めるのではなく、

作りたいシステム
      ↓
必要なAWSリソース
      ↓
環境によって変わる値
      ↓
条件分岐
      ↓
外部へ渡したい値

という順番で考えていくと、CloudFormation Templateを設計しやすくなります。

コメント

タイトルとURLをコピーしました