AWS入門ブログリレー2024〜AWS CloudFormation編〜

AWS CloudFormationについて2024年時点の情報をまとめてみました。AWSサービス入門記事として是非ご活用下さい。
2024.04.19

当エントリは弊社 AWS 事業本部による『AWS 入門ブログリレー 2024』の 26 日目のエントリです。

このブログリレーの企画は、普段 AWS サービスについて最新のネタ・深い/細かいテーマを主に書き連ねてきたメンバーの手によって、 今一度初心に返って、基本的な部分を見つめ直してみよう、解説してみようというコンセプトが含まれています。

AWS をこれから学ぼう!という方にとっては文字通りの入門記事として、またすでに AWS を活用されている方にとっても AWS サービスの再発見や 2024 年のサービスアップデートのキャッチアップの場となればと考えておりますので、ぜひ最後までお付合い頂ければ幸いです。

では、さっそくいってみましょう。今回のテーマは『AWS CloudFormation』です。

はじめに

IaC とは

まず IaC という技術を知る必要があります。

IaC(Infrastructure as Code の略)とはインフラ環境の設定やプロビジョニングをコードで管理する技術のことを指します。

簡単に言うと、料理でいうレシピに相当します。

具材は何を使って調味料は何 ml 使うかのレシピとなるものを、IaC ではテンプレートとして用意します。
IaC ツールではそのテンプレートに従ってサービスは何を使ってスペックやリソースの数はいくつかを把握し、インフラ環境を構築します。

コード管理することで、同じ環境の複製が容易になったり手動設定によるミスを減らせるといったメリットがあります。

各 IaC ツールによって構文やデプロイ方法を理解する必要があるため学習コストが発生しますが、使い方さえ理解できれば非常に便利にインフラ環境の構築ができるようになります。

AWS CloudFormation(CloudFormation)の概要

CloudFormation とは、AWS における IaC サービスです。

CloudFormation を使用することで AWS のインフラ環境の構成をコードで管理できます。

AWS CloudFormation のイメージ

もう少し、コード管理するというのを分かりやすく見ていこうと思います。

以下のような一般的な構成を考えます。

上記構成図のシステムを構築する場合、以下のリソースを作成する必要があります。

  • VPC
  • サブネット
    • パブリックサブネット×2
    • プライベートサブネット×2
  • インターネットゲートウェイ
  • NAT ゲートウェイ×2
  • ルートテーブル
    • パブリックサブネット用×1
    • プライベートサブネット用×2
  • ALB
    • ロードバランサー
    • ターゲットグループ
  • EC2 インスタンス×2
  • セキュリティグループ
    • ALB 用×1
    • EC2 インスタンス用×1

これだけのリソースをマネジメントコンソールで作成しようとすると、AWS に慣れているエンジニアでも早くても 10 分くらいはかかるんじゃないでしょうか?

これを最初 1 度だけしか作業を行わず今後一切変更もないのであれば手作業でも問題ないですが、やはり AWS でサービスを運用している以上そうもいきません。

例えば、

  • 複数のアカウントに全く同じ環境を構築したい
  • 災害対策のためにメインで使用するリージョンが被災した場合には、比較的早めに他のリージョンで同じ環境を構築できるようにしたい

といった場合はいかがでしょうか? 複数のアカウントに同じ環境を用意するのもなかなか手間がかかるかと思います。

そこでパッケージ商品のように CloudFormation テンプレートとして定義することで、手作業だと複雑な設定もテンプレートに沿って CloudFormation 上で自動で環境構築を行えます。

AWS CloudFormation テンプレート

では実際にここからは CloudFormation テンプレートについて見ていきます。

AWS CloudFormation で使用できるファイル形式

CloudFormation で使用できるファイル形式は、下記 2 種類をサポートしています。

  • JSON
  • YAML

拡張子自体は、.json、.yaml、.template、.txt などを使用できます。

JSON と YAML の違いは下記サイトが分かりやすいです。

テンプレートの構成要素

CloudFormation テンプレートを作成する際、ファイル全体ではいくつかのセクションに分かれています。

各セクションには役割があるためそれぞれ見ていきます。

セクション名 説明 テンプレートへの記載が必須かどうか
AWSTemplateFormatVersion テンプレート形式のバージョンを指定するセクション
現在時点での最新バージョンは、2010-09-09です
-
Description テンプレートの説明を記載するセクション
スタックの一覧の説明欄に表示されます
-
Metadata テンプレートに対して追加情報を付与できるセクション
後述する Parameters のグループ化や cfn-init ヘルパースクリプトを使用したい際などに活用されます
-
Parameters テンプレート作成、更新時に値を渡すセクション
後述する Resources と Outputs から参照できます
-
Rules Parameters セクションに渡されたパラメータやパラメータの組み合わせが条件を満たしているかの検証を行うセクション
特定の環境のパラメータを指定した場合、特定のパラメータからしか選択できないようにするなどもできます。
-
Mappings キーと関連する値を対応することができるセクション
例えば特定のリージョンから特定の値を参照するなどが可能です。
-
Conditions 特定のリソースを作成または設定される条件を定義するセクション
例えばパラメータ env が prod の値を指定した場合、
-
Transform テンプレートを処理するために使用するマクロを 1 つ以上指定するセクション
例えば CloudFormation から Lambda 関数を呼び出す場合などに使われます。
-
Resources AWS リソースを宣言するセクション
基本的に AWS リソースを作成したい場合はこのセクションを使用します。
Outputs 作成したリソースを値として出力するセクション
他のスタックから値を参照したい場合に使用されます。
-

Resourcesセクションは必ず記載するセクションとなっているため、気を付けてテンプレートを書きましょう。

テンプレートで使用できる組み込み関数

CloudFormation テンプレートでは、関数を使用することで柔軟に値を指定したり参照することができます。

主要な組み込み関数をいくつか紹介します。

Ref

Ref を使用することで、
Parameters セクションで指定したパラメータや、作成したリソースからリソース ID を参照したい時に使用します。

Ref を使用したい場合は、!Refといったふうに!を先頭に付与します。

使用例は以下です。

Parameters:
  InstanceTypeParameter:
    Type: String
    Default: "t2.micro"
    AllowedValues:
      - "t2.micro"
      - "t2.small"
      - "t2.medium"
    Description: Select the instance type for the EC2 instance

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceTypeParameter
      ImageId: ami-0abc1234567890abc
      ~略~

Ref で取得できる値は CloudFormation リファレンスより確認できます。

Fn::Sub

Fn::Sub を使用することで、
Ref と同様に Parameters で指定したパラメータや、作成したリソースからリソース ID や関連するパラメータを参照したい場合に使用します。

Fn::Sub を使用したい場合は、!SubFn::Subと表現できます。

Ref との違いは以下の通りです。

  • Fn::Sub で参照する場合は${}を付ける
  • 文字列の中に変数として組み込むことができる
    • 例) !Sub "${ProjectName}-Instance"
  • 後述する Fn::GettAtt や Fn::Join の代わりとして使用できる

Fn::Sub の使用例は以下です。

Parameters:
  ProjectName:
    Type: String
    Default: "MyProject"
    Description: Enter the name of your project

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0abc1234567890abc
      ~略~
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-Instance"

Fn::GetAtt

Fn:GetAtt を使用することで、
作成したリソースから特定の属性値を取得することができます。

例えば、テンプレートの中で EC2 インスタンスを作成した場合、
Fn::GetAtt を使用するとプライベート IP アドレスを取得できたり、起動している VPC ID を取得可能です。

Fn::GetAtt を使用したい場合は、!GetAttFn::GetAttと表現できます。

Fn::GetAtt の使用例は以下です。

Parameters:
  ProjectName:
    Type: String
    Default: "MyProject"
    Description: Enter the name of your project

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0abc1234567890abc
      ~略~
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-Instance"

Outputs:
  PrivateIPAddress:
    Description: Private IP address of the EC2 instance
    Value: !GetAtt MyInstance.PrivateIp

Fn::Join

Fn::Join を使用することで、
所定の区切り文字(または空白)を使用して文字列を連結ができます。

例えば、ARN を指定したい場合に ARN に含まれるリージョン名やリソース名を別の値から引用もできます。

Fn::Join を使用したい場合は、!JoinFn::Joinと表現できます。

Fn::Join の使用例は以下です。

Parameters:
  ProjectName:
    Type: String
    Default: "MyProject"
    Description: Enter the name of your project

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0abc1234567890abc
      ~略~
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref ProjectName
              - Instance

他にも、

  • Fn::Base64
  • Fn::Cidr
  • Condition functions
  • Fn::FindInMap
  • Fn::ForEach
  • Fn::GetAZs
  • Fn::ImportValue
  • Fn::Length
  • Fn::Select
  • Fn::Split
  • Fn::ToJsonString
  • Fn::Transform

などが使用できます。

詳細は下記 AWS 公式ドキュメントを参照ください。

Intrinsic function reference - AWS CloudFormation

用語説明

続いてナビゲーションペインからどんな項目なのか見ていきます。

スタック

スタックでは、CloudFormation を使用しデプロイしたものの一覧が参照できます。

テンプレートによって作成されたものはスタックという単位で管理されます。

StackSets

StackSets では、StackSets を使用してデプロイしたものの一覧が参照できます。

StackSets とは、1 つアカウントのみにデプロイするのではなく、 複数のアカウント、複数のリージョンまたは Organizatios 配下のアカウントなど、複数の環境に同時にデプロイしたい場合に使用されます。

アカウントのベースラインとなるものを同時にデプロイおよび管理したい場合に有用です。

StackSets についてはこちらも参照ください。

エクスポート

エクスポートでは、Outputs セクションで出力された値の一覧を参照できます。

Outputs で出力された値は、Fn:ImportValue で参照可能なため、クロススタックに共通の値を参照したい場合はエクスポートの項目を参照してください、

Application Composer

CloudFormation のコンソール画面における Application Composer は、CloudFormation コンソールモードで Application Composer を利用できるものです。

まず Application Composer とは、簡単に言うと GUI ベースでサーバレス構成のモデリングできるサービスです。

こちらでは、Application Composer を CloudFormation コンソールモードで利用できるものとなっています。

詳細は以下ブログをご参照ください。

IaC ジェネレーター

IaC ジェネレーターでは、既存リソースを読み取り CloudFormation テンプレートを生成してくれる機能です。

JSON または YAML で出力が可能です。

詳細は以下ブログをご参照ください。

パブリック拡張機能

パブリック拡張機能では、全ての CloudFormation ユーザーが使用できる CloudFormation レジストリを参照することができます。

CloudFormation レジストリとは、CloudFormation を拡張し、CloudFormation でサポートされていない AWS サービスやサードパーティのサービスを管理できるようにする機能です。

アクティブ化済みの拡張機能

アクティブ化済みの拡張機能では、先述したパブリック拡張機能の中で有効化したものや、プライベートに公開されたプライベート拡張機能の一覧を参照できます。

パブリッシャー

パブリッシャーでは、拡張機能を公開したい場合の登録を行うことができます。

スポットライト

スポットライトでは、CloudFormation に関するお役立ち情報の一覧が参照できます。

ドキュメントやブログだけでなく YouTube に投稿されたポッドキャストなど様々なコンテンツを参照できるためキャッチアップに役立ちます。

CloudFormation の料金

下記名前空間となるリソースプロバイダーを使用する場合は、基本的に無料で使用できます。

  • AWS::*
  • Alexa::*
  • Custom::*

そのため上記以外の名前空間を持つリソースプロバイダーの場合は、ハンドラーオペレーション(リソースの作成・更新・削除・読込・参照などのアクション)が下記の場合に料金が発生します。

項目 料金体系
無料利用枠 1,000 件のハンドラーオペレーション/月/アカウント
ハンドラーオペレーション ハンドラーオペレーションごとに 0.0009 USD
ハンドラーオペレーションの呼び出し時間 1 秒あたり 0.00008 USD

また、CloudFormation フックも同様にコストが発生し、呼び出しの数と時間によって料金が発生します。(料金は上記と同じです。)

詳細は下記ページをご参照ください。

料金 - AWS CloudFormation | AWS

AWS CloudFormation の制限事項

CloudFormation ではいくつか制限事項(上限)があります。

例えば、テンプレート本文のサイズの上限で、51,200 バイト で、引き上げできない制限事項となります。
そのため、ここまで大きいファイルとなってしまった場合には、スタックをネスト化させるなどし複数のテンプレートい分離することを検討してください。

ネストについては下記ブログをご参照ください。

他には、各リソースのオペレーションにはタイムアウトが存在しています。
公式ドキュメントによると、タイムアウト値は、リソースと使用する認証情報によって異なり、サービスロールを使用することでタイムアウト値を延長が可能のようです。

CloudFormation のその他の上限および制限事項などについては下記を参照ください。

AWS CloudFormation のクォータ - AWS CloudFormation Troubleshooting CloudFormation - AWS CloudFormation

やってみた

下記にサンプルテンプレートがあるためこちらを使用します。
Sample templates - AWS CloudFormation

コードを展開する
AWSTemplateFormatVersion: "2010-09-09"

Mappings:
  RegionMap:
    us-east-1:
      AMI: "ami-0ff8a91507f77f867"
    us-west-1:
      AMI: "ami-0bdb828fd58c52235"
    us-west-2:
      AMI: "ami-a0cfeed8"
    eu-west-1:
      AMI: "ami-047bb4163c506cd98"
    sa-east-1:
      AMI: "ami-07b14488da8ea02a0"
    ap-southeast-1:
      AMI: "ami-08569b978cc4dfa10"
    ap-southeast-2:
      AMI: "ami-09b42976632b27e9b"
    ap-northeast-1:
      AMI: "ami-06cd52961ce9f0d85"

Parameters:
  EnvType:
    Description: Environment type.
    Default: test
    Type: String
    AllowedValues: [prod, dev, test]
    ConstraintDescription: must specify prod, dev, or test.
  
Conditions:
  CreateProdResources: !Equals [!Ref EnvType, prod]
  CreateDevResources: !Equals [!Ref EnvType, "dev"]

Resources:
  EC2Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI]
      InstanceType: !If [CreateProdResources, c1.xlarge, !If [CreateDevResources, m1.large, m1.small]]    
  MountPoint:
    Type: "AWS::EC2::VolumeAttachment"
    Condition: CreateProdResources
    Properties:
      InstanceId: !Ref EC2Instance
      VolumeId: !Ref NewVolume
      Device: /dev/sdh
  NewVolume:
    Type: "AWS::EC2::Volume"
    Condition: CreateProdResources
    Properties:
      Size: 100
      AvailabilityZone: !GetAtt EC2Instance.AvailabilityZone

上記を任意のテキストファイル sample.template に保存します。

CloudFormation のコンソール画面へ遷移し、「スタックの作成」を押下します。

「テンプレートのアップロード」を選択し、「ファイルの選択」を押下、
先ほどのテンプレートをアップロードし、「次へ」を押下します。

任意のスタック名を入力しenvTypeは今回好きなものを選択し「次へ」を押下します。
興味ある方は、ここで envType を切り替えることでどんな違いがあるかをテンプレートから調べてみてください。

次のページはデフォルトのままで大丈夫なため「次へ」を押下します。

最後のページは確認画面となるため特に指定がなければ「送信」を押下するとスタックの作成が開始されます。

しばらく待つと EC2 インスタンスのコンソールで EC2 インスタンスが 1 台起動しているのが分かります。 envType の選択画面によってインスタンスタイプは以下のようになります。

  • test ・・・ m1.small
  • dev ・・・ m1.large
  • prod ・・・ c1.xlarge

このままだと課金されてしまうため、スタックを削除し、作成したリソースをまとめて削除します。

スクリーンショット上の「削除」を押下します。

削除の確認が出るため「削除」を押下すると削除が開始します。

最後に、スタック名の論理 ID が、DELETE_COMPLETEになっていれば削除完了です。

リファレンス

終わりに

以上、『AWS 入門ブログリレー 2024』の 25 日目のエントリ『AWS CloudFormation』編でした。
次回、4/20 は弊社石川覚による「Amazon Redshift編」の予定です!