Loading
BLOG 開発者ブログ

2023年9月20日

「CloudFormationテンプレート見てもちんぷんかんぷんだ…」

前回の記事でCloudFormationに関するキーワードや大まかな利用の流れを説明をしましたが、いざテンプレート作成に取り掛かってみると様々なセクションがあり、どこが設定必要な項目でどんな設定ができるのかよく分からない…


こんにちは。クラウドソリューショングループのshimizuyです。

今回は「テンプレート編」と題して、CloudFormationのサンプルテンプレートを元に各セクションの概要やどんな設定ができるのかを中心に説明していきます。
CloudFormationの概要から確認したい方は前回の記事をご参照ください!

前回の記事:初学者のためのCloudFormation超入門(概要理解編)

目次

1. CloudFormationテンプレートとは?

CloudFormation テンプレートは、AWS上に構築するインフラストラクチャを説明する JSON または YAML 言語でフォーマットされたテキストファイルです。要は設計書ですね。
テンプレートを作成・変更するにはVSCodeなどの任意のエディタツール、または CloudFormation Designer を使用する方法があります。

一応 CloudFormation Designer について簡単に説明すると、CloudFormation テンプレートを作成・表示・変更するためのグラフィックツールで、ドラッグ アンド ドロップ インターフェイスを使用してテンプレート リソースを図示し、統合された JSON および YAML エディターを使用して詳細を編集できます。興味のある方はこちらでテンプレート作成にチャレンジしてみてもいいかもしれません。

参考:AWS CloudFormation デザイナーとは

2. テンプレートの構成要素は?

さて、CloudFormationテンプレートはいくつかのセクションと呼ばれる要素で構成されています。それらのセクションを組み合わせることで、CloudFormationテンプレートはAWSのリソースを定義し、それを元にインフラストラクチャを自動的に作成・更新・削除するための設計図として機能しているわけですね。

/* yaml */
AWSTemplateFormatVersion: "2010-09-09"

Description:
 String

Parameters:
 set of parameters

Metadata:
 template metadata

Rules:
 set of rules

Mappings:
 set of mappings

Conditions:
 set of conditions

Transform:
 set of transforms

Resources:
 set of resources

Outputs:
 set of outputs

CloudFormationテンプレートは上記の10のセクションで構成されています。
実際に必須となるセクションはResourcesのみで、他のセクションは必要に応じて記述していく形になります。
以下でそれぞれのセクションの用途や記述例を確認していきましょう!

2-1. AWSTemplateFormatVersion(任意)

AWSTemplateFormatVersionセクションは、テンプレートのフォーマットバージョンを指定する任意の項目です。
最新のテンプレートの形式バージョンは2010-09-09で、現時点で唯一の有効な値となっています。
また、値を指定しない場合、CloudFormationは最新のテンプレートの形式バージョンを使用します。

/* yaml */
AWSTemplateFormatVersion: 2010-09-09

2-2. Description(任意)

Descriptionセクションには、テンプレートに関する説明文を含めることができます。
注意点として、スタックの更新時にDescriptionセクション単独での更新はできません。Descriptionセクションを更新する際は、リソースの追加、変更、または削除する変更を含める場合にのみ可能となっています。
また、記述する際は必ずAWSTemplateFormatVersionセクションの後に記述する必要があります。

/* yaml */
Description: AWS CloudFormation Sample Template

2-3. Parameters(任意)

Parametersセクションを設定すると、スタック作成時にテンプレートに対してカスタム値を受け渡すことができます。

/* yaml */
Parameters:
 EnvId:
  Description: "Environment ID"
  ConstraintDescription: EnvId is only Strings
  Type: String
  Default: "dev"
 KeyName:
  Description: "EC2 key pair name"
  Default: "ec2-key"
  Type: String
 InstanceType:
  Description: "EC2 instance type"
  Type: String
  Default: "t2.micro"
  AllowedValues:
   - "t2.micro"
   - "m5.large"
   - "c5.xlarge"
  ConstraintDescription: "Please specify a valid instance type."

上記のように記述することで、これらのパラメータはコンソールで以下のように表示されます。

ここで入力されたパラメータの値はResourceのプロパティで使用されます。

2-4. Metadata(任意)

Metadataセクションは、テンプレート自体に関する情報やリソースに関する追加の情報を提供するために使用され、スタックのデプロイや更新時には無視され、テンプレートの実行には影響しないようになってます。

使い道としては大きく分けて以下の3つがあげられます。

  • AWS::CloudFormation::Init
  • AWS::CloudFormation::Interface
  • AWS::CloudFormation::Designer

個人的にはその中でもParametersセクションのインプット項目の順序入れ替えたりジャンルごとにまとめる用途でAWS::CloudFormation::Interfaceをよく使用しています。

/* yaml */
Metadata:
 AWS::CloudFormation::Interface:
 ParameterGroups:
  - 
   Label:
    default: "Setting for EC2"
   Parameters:
    - InstanceType
    - KeyName
  - 
   Label:
    default: "Setting for Other"
   Parameters:
    - EnvId

先ほどParametersセクションで例に出したコードに加えて、上記のMetadataを追記すると、以下のようにラベル付きでインプット項目がまとめられ、より見やすい状態になったのではないでしょうか?

上記ではAWS::CloudFormation::Interfaceの使用例をあげましたが、他にも、EC2インスタンス内でのパッケージのインストールやファイルの作成、サービスの開始などのスクリプトを記述するAWS::CloudFormation::InitやAWS CloudFormation デザイナーにおけるリソースのレイアウトに関する情報を記述する AWS::CloudFormation::Designer があります。

2-5. Rules(任意)

Rulesセクションは、スタックの作成または更新時にテンプレートに渡されるパラメータまたはパラメータの組み合わせが特定の条件を満たしているか検証するために使用されます。

たとえば、あるパラメータが数値型である場合、その値が0以上であることを確認するルールを作成できます。また、2つのパラメータが関連している場合(パラメータAがtrueの場合にのみパラメータBが設定可能など)、その組み合わせを検証するルールが作成できます。

/* yaml */
Parameters:
 Number:
  Description: An input parameter of type number.
  Type: Number

Rules:
 NumberRule:
  Assertions:
   - Assert: !And [!Equals [!Ref MyNumber, 0], !Not [!If [!Equals [!Ref MyNumber, 0], true, false]]]
    AssertDescription: Number must be greater than or equal to 0.

上記の例では、ParametersセクションでNumberという名前の数値型パラメータを定義しています。
次に、NumberRuleという名前のルールを作成し、その中でNumberが0以上であることを確認しています。
もしMyNumberが0未満であれば、スタックの作成または更新は中止され、AssertDescriptionで指定したエラーメッセージが表示される仕様になっています!

2-6. Mappings(任意)

Mappingsセクションは、キーと名前付きの値が対応付けられたグループ化機能となります。
たとえば、特定の条件(リージョンや環境など)に基づいて異なる値を用いたい場合に使用されます。

/* yaml */
Mappings:
 EnvMap:
  dev:
   InstanceType: t2.micro
  prd:
   InstanceType: m5.large

上記の例では、この例では、EnvMapというマッピングが作成され、それぞれの環境(ここではdevとprd)に対して、InstanceTypeというキーでインスタンスタイプが対応付けられています。

また、マッピングから値を取得するためには、以下のようにFn::FindInMap関数を使用します。

/* yaml */
Parameters:
 EnvId:
  Type: String
  Default: dev
  AllowedValues:
   - dev
   - prd

Resources:
 myEC2Instance:
  Type: "AWS::EC2::Instance"
  Properties:
   ImageId: ami-0ff8a91507f77f867
   InstanceType: !FindInMap [EnvMap, !Ref EnvId, InstanceType]

Mappingsセクションが上手く活用できれば、環境やリージョンごとにテンプレートを作成する必要がなくなり、テンプレートの再利用性と可読性が向上します!

2-7. Conditions(任意)

Conditionsセクションは、特定の条件下でどのようなアクション(リソースの作成、プロパティの設定など)を行うかを設定し、制御することができます。
たとえば、条件を作成し、リソースや出力に関連付けることで、条件が true の場合にのみ CloudFormation がリソースまたは出力を作成するようにできます。すごくざっくり言えばif文のような機能ですね!
(出力に関しての詳細はOutputsセクションで説明します)

/* yaml */
Parameters:
 EnvId:
  Default: test
  Type: String
  AllowedValues:
   - prd
   - test

Conditions:
 CreatePrdResources: !Equals [ !Ref EnvId, prd ]

Resources:
 EC2Instance:
  Type: "AWS::EC2::Instance"
  Condition: CreatePrdResources
  Properties:
   # ...

この例では、EnvIdという入力パラメーターが存在します。本番環境用のスタックを作成する場合は prd を、テスト環境用のスタックを作成する場合は test をここに指定します。CreatePrdResources 条件は、EnvId パラメーターが prd と等しい場合に true として評価されます。このサンプルテンプレートでは、EC2Instance リソースを CreatePrdResources 条件に関連付けているため、EnvType パラメーターが prd と等しい場合にのみリソースが作成されるというわけです!

2-8. Transform(任意)

Transformセクションでは、CloudFormationがテンプレートを処理するために使用するマクロを1つ以上指定することができます。と言われても少しイメージが付きづらいですよね…。

/* yaml */
Transform: 'AWS::Serverless-2016-10-31'

Resources:
 MyLambdaFunction:
  Type: 'AWS::Serverless::Function'
  Properties:
   Handler: index.handler
   Runtime: nodejs14.x
   CodeUri: s3://my-bucket/my-function-code.zip

こちらの例では、AWS::Serverless-2016-10-31というマクロを使用しており、これはLambda関数やAPI GatewayなどのAWSリソースを簡単に記述するためのものになっています。
勘のいい方はお気づきかもしれませんが、すごーくざっくり言うとライブラリやフレームワークに近い機能ですね。
細かい使用感や効果は使用するマクロによっても変わってきますのでユースケースに合わせて公式を確認するようにしましょう!

参考:変換のリファレンス

2-9. Resources(必須)

Resourcesセクションは、スタックに含めるAWSリソースを宣言するためのCloud Formation唯一の必須セクションです。これまでのセクションはResourcesセクションをベースとして色々機能していきます。
基本的な構文は以下の通りです。

/* yaml */
Resources:
 Logical ID:
  Type: Resource type
  Properties: 
   Set of properties

ここでいくつかポイントがあるのですが、

  • Logical IDはテンプレート内で一意である必要があります。
  • Resource typeは宣言しているリソースのタイプを識別します。例えば、AWS::EC2::InstanceはEC2インスタンスを宣言します。
  • Propertiesはリソースに対して指定できる追加オプションです。例えば、EC2インスタンスごとに、そのインスタンスのAMI IDを指定する必要があります。

小ネタですが、CloudFormationテンプレートでEC2インスタンスのUserDataなんかも設定することができるので、思った以上に色々とカスタマイズできそうでちょっとワクワクしますね!

いよいよ次で最後のセクションです…!

2-10. Outputs(任意)

Outputsセクションは、スタックの作成や更新が完了した後に、そのスタックに関する特定の情報を提供するためのものです。具体的には、以下の3つの主な用途があります:
1. 他のスタックにインポート: Outputsセクションで定義した値は、他のCloudFormationスタックから参照できます。これにより、一つのスタックが別のスタックと情報を共有することが可能になります。例えば、あるスタックで作成したS3バケットの名前を出力として定義し、その名前を別のスタックで参照することができるようになります。
2. スタック呼び出しの応答として値を返す: スタック作成や更新のAPI呼び出しに対する応答として、Outputsセクションで定義した値を返すことができます。これにより、API呼び出しを行ったユーザーやアプリケーションがスタック作成や更新の結果を得ることが可能になります。
3. CloudFormationコンソールで表示: CloudFormationコンソールで、各スタックのOutputsセクションで定義した値を表示することができます。

/* yaml */
Resources:
 MyBucket:
  Type: 'AWS::S3::Bucket'
Outputs:
 BucketName:
  Description: 'The name of the newly created S3 bucket'
  Value: !Ref MyBucket
  Export:
   Name: MyExportedBucketName

上記のテンプレートでは、Resourcesセクションで作成したS3バケット(MyBucket)をOutputsセクションで出力していて、出力値は!Ref MyBucketという組み込み関数を使用してバケット名を取得しています。最後に、この出力値をMyExportedBucketNameという名前でエクスポートしていますね。

これによって、他のスタックはFn::ImportValue MyExportedBucketNameという組み込み関数を使用してこのバケット名(MyBucket)を参照することができるわけですね!

3. おわりに

この記事ではCloudFormationテンプレートの各セクションの概要をサンプルコードを用いて説明をしてきました。
各セクションがどんな時に利用されるのか?どのように記述されるのか?など少しでも分かりやすく説明できていれば幸いです。

今後の記事では、これまでの説明を元に実際のテンプレート作成をしつつ、CloudFormationテンプレートを運用していく上でのコツなどを説明していければと思いますので、ぜひ次回以降もご覧ください!

shimizuyのブログ