🌤️

【初心者向け】CloudFormationテンプレートの読み方

2023/01/16に公開

こんにちは。深緑です。

最近は周りにCloudFormationを広めようと頑張っています。
今回はCloudFormationの初学者に向けて記事を書いてみます。

はじめに

本記事ではCloudFormationテンプレートの読み方について記載します。

個人的に初めてCloudFormationテンプレートを見た時、とっつきにくさを感じました。
独自の構造とプロビジョニングツール自体への理解不足から来るものと思いますが、
同じにように感じられる方もいる気がするので、
CloudFormationテンプレートはどのように読み進めるのかということを書いてみます。

  • 本記事ではCloudFormationテンプレートをyaml形式で書いています。
  • テンプレートの具体的な書き方はまでは触れません。

サンプルソース

DynamoDBテーブルとそのバックアップ・アラームをセットするCloudFormationです。

https://github.com/satoshi256kbyte/aws-code/blob/master/cloudformation/dynamodb.yaml

セクション

CloudFormationテンプレートにはセクションという区切りがあります。
AWS公式 - テンプレートの分析

取り急ぎ、パラメータ(Parameters)とリソース(Resources)セクションをとてもよく使うので、
これらを抑えてておきます。

パラメータ(Parameters)セクション

Parameters:
  ProjectName:
    Description: Project name
    Type: String
  EnvironmentName:
    Description: Environment name
    Type: String
    Default: STG
    AllowedValues:
      - STG
      - PRD

入力パラメータの定義です。
ここを定義しておくと、CloudFormationのテンプレートを実行する時にパラメータの入力を求めることができます。
パラメータの型・初期値・選択肢などが指定できます。
この例では文字列型しかありませんが、パラメタータとしてEC2のインスタンスIDが欲しい場合は、

Parameters:
  InstanceId:
    Type: AWS::EC2::Instance::Id

のようにして存在するEC2から選ぶ形式にすることもできます。

なお、Descriptionは現状日本語は使えないようです。

リソース(Resources)セクション

Resources:
# ------------------------------------------------------------#
# DynamoDB
# 参考
# https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/gettingstarted.templatebasics.html
# ------------------------------------------------------------#
  DynamoDBTable: 
    Type: AWS::DynamoDB::Table
    Properties: 
      TableName: !Sub ${ProjectName}-${EnvironmentName}-DynamoDB-Table
      AttributeDefinitions: 
        - 
          AttributeName: "Album"
          AttributeType: "S"
        - 
          AttributeName: "Artist"
          AttributeType: "S"
      KeySchema: 
        - 
          AttributeName: "Album"
          KeyType: "HASH"
        - 
          AttributeName: "Artist"
          KeyType: "RANGE"
      ProvisionedThroughput: 
        ReadCapacityUnits: "5"
        WriteCapacityUnits: "5"
      PointInTimeRecoverySpecification:
        PointInTimeRecoveryEnabled: false
      Tags:
        - Key: Project
          Value: !Ref ProjectName          
        - Key: Backup
          Value: !Sub ${ProjectName}-${EnvironmentName}-DynamoDB-Backup

起動するインスタンスやサービスを記述するセクションです。
Propertiesの中でインスタンス・サービスの設定を定義していきますが、
種類ごとに記載方法が異なるので都度AWS公式 - Template referenceを見るしかないでしょう。

出力(Outputs) ※今回は使いません。

本記事では使っていませんが、出力(Outputs)セクションもよく使います。
例えば本記事のテンプレートで作ったDynamoDBテーブルを他のテンプレートで使う場合、
出力セクションで関数の戻り値のようなものを定義します。
割と複雑なので別の機会に書くことにします。

値の参照 Ref関数・Sub関数・GetAtt関数

Ref・Sub関数関数を使うと、パラメータやリソースを変数のように参照できます。
AWS公式 - Ref関数
AWS公式 - Sub関数

パラメータ値の参照

パラメータをそのまま使う場合は、Ref関数を使います。
文字列結合する場合はSub関数を使います。

      Tags:
        - Key: Project
	 # パラメータをテーブルをそのまま使用
          Value: !Ref ProjectName          
        - Key: Backup
	 # パラメータをテーブル名の一部として使用 
          Value: !Sub ${ProjectName}-${EnvironmentName}-DynamoDB-Backup

リソースの参照

リソースセクションで作ったリソースを他のリソースで使う場合は、大体Ref関数を使います。
テンプレート内でDynamoDBテーブルを作成し、そのテーブルに対してアラームを作る場合、
Ref関数で作ったDynamoDBテーブルを指定します。

  DynamoDBAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub ${ProjectName}-${EnvironmentName}-DynamoDB-Write-Capacity-Alarm
      Namespace: AWS/DynamoDB
      ComparisonOperator: GreaterThanOrEqualToThreshold 
      Dimensions:
	# テンプレート内で作成したテーブルの名前でメトリクスを絞り込む
        - Name: TableName
          Value: !Ref DynamoDBTable
      EvaluationPeriods: 1
      MetricName: ConsumedWriteCapacityUnits
      Period: 300
      Statistic: Average
      Threshold: 1

Ref関数の注意事項

Ref関数は動きが微妙にわかりづらいです。
Ref関数の戻り値は型が固定ではないからです。
!Ref DynamoDBテーブルならテーブル名が返ります。
!Ref EC2インスタンスならインスタンスIDが返ります。

AWS公式 - Ref関数

一部のリソースでは、リソースのコンテキストにおいて別の重要な意味を持つ識別子が返されます。たとえば、AWS::EC2::EIP リソースは IP アドレスを返し、AWS::EC2::Instance はインスタンス ID を返します。

AWS公式 - AWS::DynamoDB::Table

For the resource with the logical ID myDynamoDBTable, Ref will return the DynamoDB table name.

AWS公式 - AWS::EC2::Instance

hen you pass the logical ID of this resource to the intrinsic Ref function, Ref returns the instance ID. For example: i-1234567890abcdef0.

属性値の参照

作ったリソースから、インスタンスIDとかではなく特定の属性値を参照する場合は、GetAtt関数を使います。
AWS公式 - GetAtt関数

  DynamoDBTagBasedBackupSelection:
    Type: AWS::Backup::BackupSelection
    Properties:
      BackupPlanId: !Ref DynamoDBBackupPlan
      BackupSelection:
        SelectionName: !Sub ${ProjectName}-${EnvironmentName}-Backup-Selection
	# リソースのARNを参照
        IamRoleArn: !GetAtt DynamoDBBackupExecutionRole.Arn
        ListOfTags:
         - ConditionType: STRINGEQUALS
           ConditionKey: Backup
           ConditionValue: !Sub Backup-${ProjectName}

GetAtt関数で取れる属性の種類は、リソースの種類によって変わります。
例えば先述のDynamoDBテーブルですが、

!GetAtt DynamoDBTable.TableName

とかできそうですがこれはできません。
テーブル名はRef関数で取るのが正解です。
Ref関数で何が返り、GetAttで何が取れるかは各リソースのタイプの公式ページをみなくてはわかりません。

Ref関数・Sub関数・GetAtt関数の違いを理解する

まず、Ref関数・Sub関数・GetAtt関数の違いを覚えます。
次にRef関数はそのリソースのキーっぽいものを返す故にリソースから他のリソースが読めることと、
Sub関数は文字列結合に使えることを意識すると、
CloudFormationのテンプレートは読めるようになると思います。

まとめ

以上踏まえてテンプレートに繋がりの線を入れるとこのようになります。

CloudFormationテンプレートの読み方 - 要素同士の繋がりを表した図

本記事の内容が何かのきっかけになれば幸いです。

Discussion