AWS

CloudFormationを効果的に使うための6つのルール

あなたはAWSでEC2を作成する時にAWSコンソールから作っていますか?
最初にAWSに慣れるまではそれで良いのですが、何度も似たような環境を作ったり、大量に作ったりする時、非常に手間になります。
そういったときにCloudFormationというAWSのサービスを使うことで、テンプレートを元にリソースを自動で構築することができます。
また、テンプレートをGitで管理することで変更の履歴を保管できるようになることもCloudFormationを使うメリットです。今回は私が使用しているCloudFormationの運用に関するルールについて紹介していきたいと思います。

CloudFormationとは

CloudFormationは、YAML, JSONなどのコード化したテンプレートを使って、リソースの作成や変更ができるAWSのサービスです。

AWS CloudFormation(テンプレートを使ったリソースのモデル化と管理)| AWS

CloudFormationを使うメリットとして、Gitなどのソースコード管理ツールで変更の履歴を管理できるため、レビューによる変更点の事前確認や、変更前の状態に戻すことも簡単にできるようになります。

下記のAWSの公式のドキュメントでCloudFormationのベストプラクティスがまとまっており、大変参考になります。

AWS CloudFormation ベストプラクティス – AWS CloudFormation

私は、5年程前からCloudFormationを使ってほぼ毎日、作業を行っています。 しかし、使い始めた当時は、あまりノウハウが無いせいで、トラブルを起こしてしまったことも多々ありました。 その経験を踏まえて、安全で効率的にCloudFormationを使って運用を行うために、現在使用している6つのルールについてご紹介します。

1. YAMLで書く

CloudFormationはYAMLとJSON、2つの形式で書くことができますが、YAMLの方がおすすめです。YAMLだと短縮記法が使えて、テンプレートを短くできるからです。短い方が見やすいですし、レビューもしやすく、ミスを見逃す可能性も低くなります。

短縮しない場合

- Fn::FindInMap:
    - AWSInstanceType2Arch
    - Ref: InstanceType
    - Arch

短縮記法

!FindInMap [AWSInstanceType2Arch, !Ref InstanceType, Arch]

2. スタックの更新は変更セットを使用する

スタックを更新する場合、変更セットを使用をすることで、変更を反映する前にどのリソースにどのような変更が行われるか知ることができ、安全に作業を行うことができます。

変更セットの作成 – AWS CloudFormation

AWSコンソールの場合は、Updateボタンではなく、下記のcreate changeset for current stackを選ぶことで、変更セットを作成できます。

変更セットを作ると、下記のようなこの変更を反映するとどのようなことが起こるか確認できます。また、変更セットを作成した時点では、システムには変更は反映されていないので安全です。

上の画像の場合だとEC2InstanceのReplacementがTrueとなっており、現在のEC2インスタンスが破棄され、新しいものが作られることがわかります。 もしEC2インスタンスのローカルディスクに重要なデータが置かれている場合には、消えてしまいます。 ですので、Replacementの情報を確認することは非常に重要です。 私は、Gitで管理しているCloudFormationのテンプレートの変更のレビューを依頼するプルリクエストに、本番環境で取得したchangesetの結果を張り付け、レビューする人が作業の安全性をチェックできるようにしています。

3.スタックのネストは極力使わない

ネストされたスタックというのは、CloudFormationのスタックに親子関係があるということです。

ネストされたスタックの操作 – AWS CloudFormation

図にすると下記のようになります。

スタックのネストを使用する場合、スタックの更新は親から全て行うことになります。 その際、子のスタックの中のどのリソースが作り変えられるかが事前に変更セットに表示されず、実行してみないとわからないので大変危険です。

下記はスタックのネストを使用した場合の変更セットの内容です。

子のスタックについては、スタック単位で変更があるといった大まかな情報しか表示されておらず、そのスタック内にあるEC2が作り直されるのかどうかがわかりません。 ですので、予期しないデータの損失を防ぐためにもネストされたスタックは極力しない方が良いです。

私は、当初はネストスタックを多数使用しており、そのため、意図せずEC2インスタンスが作り直されてしまい、そのEC2インスタンスにしか保存されていなかった過去3か月分のデータが消えてしまったことがあります。

その反省から、EC2インスタンスの共通のCloudWatchアラームの設定など万が一、作り直しが発生しても影響がないもののみ、子のスタックに置くようにしています。

4. 命名ルールを最初にちゃんと決めておく

命名ルールをしっかり決めずに適当にスタックを作ってしまうと、後で作り直したくても、既にサービスで使用されていたりして、作り直せずに困ることがあります。ですので、最初に命名ルールを決めておいた方が良いと思います。

私は、CloudFormationのスタック名、テンプレートは、ケバブケースを使用しており、下記のようなルールで命名しています。

(サービス名)-分類名

例えば、サービス名がtanakaでvpcを作るテンプレートでしたら、tanaka-vpcがスタック名、tanaka-vpc.yamlがテンプレート名といった形です。

5. 複数環境を同じテンプレートで管理する

本番環境、ステージング環境、開発環境と複数の環境を使用している場合に、環境ごとに別のテンプレートにせず、同じものを使うようにした方がよいと思います。

理由は2つあります。

1つは、同じテンプレートを使うことで、本番環境で使うテンプレートが正常に動作するかどうかという確認が開発、ステージング環境ででき、トラブルが発生する確率を減らせるためです。

もう1つは、単純にテンプレートの数を減らすことができ、効率的だからです。 環境ごとに設定を変更しないといけない場合には、下記のようにします。 まず、パラメータで環境名を定義します。

Parameters:
  Environment:
    Description: Environment of the application
    Type: String
    Default: development
    AllowedValues: [ production, staging, development ]
    ConstraintDescription: Must be a valid environment name

そして、Mappingで環境ごとの設定を定義します。

Mappings:
  EC2:
    InstanceType:
      production: m5.large
      staging: m5.large
      development: t3.small

最後に、組み込み関数のSub、FindInMapなどを使用して環境ごとに異なる設定を適用します。

Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !FindInMap [ EC2, InstanceType, !Ref Environment ]
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub rakuten-payment-${Environment}

6. パラメータを使用しすぎない

CloudFormationにはパラメータという機能があり、スタックを作るときに設定のカスタマイズを行うことができます。

パラメータ – AWS CloudFormation

これは便利な機能なのですが、使いすぎると、実際にどのような設定がされているかテンプレートを見てもわからなくなってしまいます。

具体的な判断基準としては、Gitで管理しなくても運用上問題ない値についてのみ、パラメータを使用するのが良いと思います。

例えば、development, staging, productionといった環境名は、その3つのうちから選択するとテンプレートに記載しておけば、実際に各環境ごとのスタックでどれが指定されているかは容易に想像できるのでGitで管理しなくても問題がありません。

OK

Parameters:
  Environment:   # スタックで何が設定されているか推測ができる
    Description: Environment of the application
    Type: String
    Default: development
    AllowedValues: [ production, staging, development ]
    ConstraintDescription: Must be a valid environment name

一方で、EC2のインスタンスタイプやAutoScaling Groupの最小インスタンス数、最大インスタンス数などをパラメータで設定してしまうと、実際にどの値が設定されているかは選択肢が多くなりすぎて、レビューを行う際などにGitを見ただけでは判断することが難しいので、パラメータを使用しないほうが良いです。

NG

Parameters: 
  InstanceType:    # 何がスタックで設定されているかテンプレートを見ただけだと分からない。
    Type: String
    Default: t2.micro
    Description: Must be a valid instance type

まとめ

以上、私がCloudformationを使用するうえで適用しているの6つのルールについて紹介させていただきました。 このような工夫をすることで、安全かつ便利に運用することができています。

参考になりましたら幸いです。

関連記事

  1. AWSでCloudFrontを導入する際に注意する点

    AWS

    AWSでCloudFrontを導入する際に注意する点

    前回の記事でAWSでシステムを構築する際にはCloudFrontを利用…

  2. AWS

    AWSでコンプライアンスのための監査ログを取得する方法

    PCI DSSやIT内部統制などのコンプライアンスの観点でAWS上で監…

  3. AWSで安全なネットワーク設計を行うポイント

    AWS

    AWSで安全なネットワーク設計を行うポイント

    今回は、AWSにおいて安全なネットワーク設計を行いポイントについて…

  4. AWS

    AWSでOSの脆弱性対策をする方法

    今回はAWSで作成したEC2インスタンスのOSの脆弱性対策をする方…

  5. AWSでS3の利用料を節約するためにやって置いた方がよいこと

    AWS

    AWSでS3の利用料を節約するためにやって置いた方がよいこと

    AWSでファイルや画像などを配置する場所として利用する場所はS3ですが…

  6. AWS

    AWSでEC2インスタンスを安全に使うための3つの注意点

    今回はAWSでEC2インスタンスを起動した際に、安全に使うために行った…

最近の記事

  1. AWS

    AWSでLinuxサーバ上のログを自動的にS3に保存する方法
  2. AWS

    CloudFrontでLambda@Edgeを本番運用してわかった注意点
  3. PCI DSSの12要件とAWSにおける対応方法

    AWS

    PCI DSSの12要件とAWSにおける対応方法
  4. AWSで安全なネットワーク設計を行うポイント

    AWS

    AWSで安全なネットワーク設計を行うポイント
  5. PCI DSS

    PCI DSSに準拠するためにまず最初にやるきべこと
PAGE TOP