🧾

CloudFormationのベストプラクティスを整理する

2022/07/11に公開

はじめに

本記事ではAWSドキュメントのAWS CloudFormation ベストプラクティスを精読して要点を整理するものです。
ベストプラクティスの方針についての記載はありましたが、実際のサンプルコードはなさそうだったので、今回整理したうえでCloudformationのコードも作成するつもりです。(分量的に別記事にする予定)

概要

ドキュメント上では「計画と編成」「テンプレートの作成」「スタックの管理」の3カテゴリに分かれて説明がされています。
本記事では推奨項目をCloudFormationを作成する過程で気を付けるタイミング単位でカテゴリ分けして、それぞれのフェーズで気を付けるべきポイントを読み取っていこうと思います。
具体的には以下の2つに整理していきます。

  • CloudFormationのコードに関するベストプラクティス
  • 作成したコードの運用方法に関する項目

CloudFormationのコードに関するベストプラクティス

01.スタックを分割して管理する

ライフサイクルと所有権によるスタックの整理
規模が小さい構成であれば1ファイルにリソースを記載してもさほど問題はありませんが、
大規模になってくると管理が煩雑になるため、スタックを分割することが推奨されます。

元にスタックの分割基準として「ライフサイクル」と「所有権」の2つを勧めています。
「所有権は」対象リソースの管理者を指し、例えばDBをDBAチーム、その他インフラ全般をインフラチームで管理するような体制であれば、DBリソースを1つのスタック、それ以外のインフラリソースを1つのスタックとして管理することになります。

「ライフサイクル」はシステムのライフサイクルでスタックを管理する方法です。
ドキュメントでは具体的な分割例として「多層アーキテクチャ」と「サービス志向アーキテクチャ」を挙げています。

  • 多層アーキテクチャによるスタック分割
    多層アーキテクチャとは、アプリケーションを機能単位で層に分けて開発/保守する方法で、WEB3階層システムなどが有名な構成例になります。WEB、API、DBを別のライフサイクルと定義して、各々を別スタックとして管理する方法です。

  • サービス志向アーキテクチャによるスタック分割
    サービス志向アーキテクチャとは、業務上の処理単位でスタックを整理する方法になります。自分はちょっと馴染みがないですが、マイクロサービスアーキテクチャと考え方が似てるが定義が違う構成になるようです。

02.クロススタック参照を使用して共有リソースを参照する

クロススタック参照とは、あるスタックで作成したリソース情報を別のスタックから参照することです。スタック間でリソースのARNなどを参照させたい場合は、ARN名のハードコーティングはしない代わりにクロススタック参照を利用するのが推奨事項になります。

以下方法で参照させることが可能です。

  • 参照する対象のリソースをOutputsでエクスポートします。
  TESTSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub ${Project}-${Environment}-sg
      GroupName: !Sub ${Project}-${Environment}-sg
      VpcId: !Sub ${VPCid}
      Tags: 
        - Key: Name
          Value: !Sub ${Project}-${Environment}-sg

Outputs:
  TESTSecurityGroup:
    Value: !Ref TESTSecurityGroup
  • 参照する側のスタックでImportValueを使って参照します。
  SecurityGroup: !ImportValue TESTSecurityGroup

03. テンプレートを再利用して複数の環境にスタックを複製する

本番・検証・開発など複数の環境を用意する場合は、単一のスタックを利用して複数環境を用意することができます。インスタンスタイプなどの環境毎に変わる値は、パラメータとしてスタック実行時に指定できるようにしておきます。

スタック実行時のパラメータ指定はParameters,Mappings,Conditionsセクションで実装できます。

04. モジュールを使用してリソース構成を再利用する

同じ設定のリソースを複数作成する場合は、繰り返し部分をモジュール化してテンプレートとして呼び出して作成します。モジュールはCloudFormationレジストリに登録することができ、パブリックとプライベートのどちらかを選ぶことができます。

05. 組み込み関数でAWS固有のパラメータを指定する

スタック内でAWS固有のパラメータを指定する必要がある場合は、組み込み関数を利用して定義します。サポートされているAWS固有パラメータの一覧はこちらに記載されています。

例えばキーペアの指定は以下のように記載します。

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

06. 入力可能なパラメータにバリデーションを設定する

スタック実行時に指定するパラメータに対してバリデーションを定義できます。
制限は最小文字数、最長文字数、許可パターンなどが可能です。

制約は以下のように記載します。
ConstraintDescriptionでエラー時のメッセージをカスタマイズすることも可能です。

  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.

07. ヘルパースクリプトを使用してEC2をデプロイする

CloudFormationのヘルパースクリプトを利用して、EC2のデプロイを効率化させることができます。
定義したヘルパースクリプトはユーザーデータ内で呼び出して実行します。
ヘルパースクリプトの種類はこちらで解説されています。

08. 最新のヘルパースクリプトを使用する

ヘルパースクリプトは定期的に更新が入るため、常に最新化することが推奨されています。
ユーザーデータで以下コマンドを実行することで最新化が可能です。

yum install -y aws-CloudFormation-bootstrap

作成したコードの運用方法に関する項目

01. 全リソースのクォータを確認する

作成予定のリソースがAWSアカウントの制限値に達している場合、スタックを実行してもリソースが作成できません。スタックの実行前に制限値を確認し、必要であればリソースの削除やクォータを増やす申請を行うのがベストプラクティスとのことです。

02. テンプレートを使用する前に検証する

リソースを作成or更新する前に、CloudFormationを利用して検証を行うことができます。
terraform planのようなイメージで、以下コマンドで実行できます。

aws cloudformation validate-template --template-body file://sample.yml

03. 組織のポリシーに準拠するためにテンプレートを検証する

AWS CloudFormation Guardを利用して組織のポリシーガイドラインに準拠しているかどうかを、CloudFormation実行前に検証することができます。AWS CloudFormation Guardはオープンソースのcliツールで、CICDのフローに含めることも可能です。
ツールの利用方法等の掘り下げは別記事にしたいと思います。

04. CloudFormationですべてのスタックリソースを管理する

スタックで作成したリソースを変更する場合は必ずCloudFormationを通して変更します。
テンプレートと実際のリソース間で不整合が起こるとリソースの削除や更新時に失敗する可能性があるためです。

05. スタックを更新する前に変更セットを作成する

CloudFormationで作成したリソースを更新する際、変更セットを作成してリソースを更新します。
変更セットを作成することでリソースにどのような影響がでるかを実行前に確認することが出来ます。

06. スタックポリシーを使用する

スタックポリシーを設定すると更新中に想定外の変更がかかってしまうのを防ぐことができます。重要なリソースはポリシーで保護するのがベストプラクティスとなります。

スタックポリシーは以下のように指定します。

aws cloudformation set-stack-policy --stack-name YourStackName --stack-policy-url https://s3-ap-northeast-1.amazonaws.com/YourBucketName/DenyUpdateSt
ackPolicy.json

jsonは以下のように記載します。

{
  "Statement" : [
    {
      "Effect" : "Allow",
      "Action" : "Update:*",
      "Principal": "*",
      "Resource" : "*"
    },
    {
      "Effect" : "Deny",
      "Action" : "Update:*",
      "Principal": "*",
      "Resource" : "LogicalResourceId/ProductionDatabase"
    }
  ]
}

07. コードの確認とリビジョン管理を使用してテンプレートを管理する

CloudFormationのコードをリポジトリ等で管理する、かつバージョンも管理するのがベストプラクティスとなります。スタックの変更履歴を追いやすくなるため、運用性が向上します。
また、コードの内容をリバートすることでスタックの状態を特定バージョンに戻すことができるのもメリットです。

08. Amazon EC2 Linux インスタンスを定期的に更新する

作成したEC2インスタンスは定期的なアップデートを行うのがベストプラクティスです。

おわりに

以上がCloudFormationのコードを作成、運用する際のベストプラクティスになります。
運用項目はお作法観点が多いですが、コード部分は順守すると可読性にだいぶ違いがでるような印象でした。
文頭でも記載しましたが、次回はこれらを意識してサンプルコードを書き上げてみたいと思います。

Discussion