LoginSignup
6
10

More than 1 year has passed since last update.

AWS CloudFormation再入門

Last updated at Posted at 2021-01-31

概要

CloudFormationよりTerraform派なので、理解しているようできちんと理解していなかったCloudFormationについて、最近ServerlessFrameworkの利用機会が増えてきて(ServerlessFrameworkはCloudFormationがベースとなっているので)、改めて勉強したので、忘れないようにアウトプットしていく。

参考にした資料:

CloudFormationとは

AWS公式の構成管理ツール(AWSサービス)でAWSにおけるIaCの手段の一つ。
クラウドインフラのIaCツールは他にもあるが、CloudFormation利用のメリットとして、以下がある。

  • AWSサービスのため、ポリシーによる細かい制御やOrganizationsによる複数アカウントの一元管理が可能
  • AWSサービスのため、利用している組織が多い(チームや企業が変わっても変わらず利用できる可能性が高い)
  • SAMやServerlessFrameworkのベースになっているため、これらに応用できる。

AWSリソースの定義をJSONやYAML(JSONはYAMLのサブセットなので当たり前だが)で記述しておき、構成の変更や追加、さらに異なるリージョンやアカウントでの再構築を容易にできる。

スクリーンショット 2021-02-01 0.59.44.png

CloudFormation利用の流れ

定義ファイルを記述し、S3に配置。
その定義ファイルを元に実際にリソースの作成や変更を実行という流れ。
もちろんこれらの操作(アップロード以降)はCLIでもマネジメントコンソールでも実施できる。

スクリーンショット 2021-02-01 1.00.57.png

テンプレートとスタック

CloudFormationの理解に欠かせない2つの要素が「テンプレート」と「スタック」
これらについては少し深く書いていく。
スクリーンショット 2021-02-01 1.17.05.png

テンプレート

CloudFormationの管理対象とするAWSリソースの定義。
YAML/JSONで記述したテキストドキュメント。
スクリーンショット 2021-02-01 1.08.31.png

テンプレートに記載する主な要素

  • AWSTemplateFormatVersion
  • Description
  • Parameters
  • Conditions
  • Resources
  • Outputs スクリーンショット 2021-02-01 1.09.50.png

その他にもあるが基本はこのあたり。
その他の要素については下記を参照のこと。
公式リファレンス:https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-reference.html

Resources

管理対象とするAWSリソースの情報を記述する。
リソースタイプごとに必須とオプションのプロパティがあるので、指定可能なリソースタイプやリソースごとのプロパティについては公式リファレンスを見ながら、必要なものを記述していく。
Terraformのresourceと似ているが、こちらはResources属性の中にまとめて記述する。
スクリーンショット 2021-02-01 1.42.34.png

AWSTemplateFormatVersion & Description

AWSTemplateFormatVersion: テンプレートの構文バージョン。IAMポリシーのVersionのようなもの、現状一度もアップデートされていないので2010-09-09しか存在しない。指定無しでもデフォルトで最新バージョンとなるが、今後バージョンが上がって互換性がなくなる可能性も考え、ときのために書いておいたほうがいい。(とBlackBeltセミナーで言っていた)
Description: このテンプレートの対象が何なのか説明を書くことができる。動作に影響はなく、必須ではないが、保守観点で書いておいたほうがいい。
スクリーンショット 2021-02-01 1.44.03.png

Parameters

スタック構築時にユーザに指定させる値を定義。デフォルト値やデータ型(StringListなど)の指定が必須。
正規表現や長さなどを指定し、入力値のチェックをさせることもできる。
Terraformのvariableに似ているが、こちらはParameters属性の中にまとめて記述する。
スクリーンショット 2021-02-01 2.10.05.png

Outputs

スタック構築後に表示させる情報、自動で付与されたインスタンスIDなど表示させて、後で利用したりできる。
Terraformのoutputに似ているが、こちらはOutputs属性の中にまとめて記述する。
スクリーンショット 2021-02-01 2.09.29.png

Conditions

環境ごとなどで異なる定義でリソースを構築したい時に利用する。
下記例の場合、パラメータの値により構築するインスタンスタイプを切り替えている。
Envパラメータにprodが指定された場合c1.xlargedevの場合m1.large、その他の場合m1.smallとなる。
↓の記述例では組み込み関数も出てくるので、後述の組み込み関数と合わせて読むといい。

記述例
Parameters:
  EnvType:
    Description: Environment type.
    Default: test
    Type: String
    AllowedValues: [prod, dev, test]

Conditions:
  CreateProdResources: !Equals [!Ref EnvType, "prod"]
  CreateDevResources: !Equals [!Ref EnvType, "dev"]

Resources:
  EC2Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      ImageId: "ami-06cd52961ce9f0d85"
      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

組み込み関数

テンプレート内では事前定義されたいくつかの組み込み関数を利用することができる。
詳細は下記公式リファレンスを参照のこと。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html

Fn

Fn::~の利用例
組み込み関数を利用することで、リソースの名前やOutputsで出力させる文字列を動的に生成できる。
基本は属性名関数名として引数を指定する。引数が複数の場合配列で指定する。
短縮形の書き方もあり、Fn::の代わりに!を書き、関数名のあとにスペースを挟んで引数を指定する。
短縮形の場合も引数が複数の場合、配列で指定する。
基本は短縮形だけ覚えておけば困らなそう。

例えばFn::Subは単純に文字列の中に変数を展開する関数。
下記の例ではParametersで受け取ったEnv文字列とCloudFormationを実行するリージョンに応じたバケット名をつけている。

記述例(Sub)
Parameters:
  Env:
    Type: String

Resources:
  DataBucket:
    DeletionPolicy: Retain
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        Fn::Sub:
          src-${AWS::Region}-${Env}

↑のProperties以下を短縮形にすると↓になる。

記述例(Sub短縮形)
    Properties:
      BucketName: !Sub src-${AWS::Region}-${Env}

もう一つの例としてGetAttResourcesで定義したAWSリソースから様々な属性値を取得できる。
下記例の場合、myELBのソースセキュリティグループ名を取得しています。

記述例(GetAtt)
Resources:
  myELB:
    Type: AWS::ElasticLoadBalancing::LoadBalancer
    Properties:
      AvailabilityZones:
        - eu-west-1a
      Listeners:
        - LoadBalancerPort: '80'
          InstancePort: '80'
          Protocol: HTTP
  myELBIngressGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ELB ingress group
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupName:
            GetAtt: 
              - myELB
              - SourceSecurityGroup.GroupName

↑のSourceSecurityGroupName以下を短縮すると↓になる。

記述例(GetAtt短縮形)
          SourceSecurityGroupName: !GetAtt myELB.SourceSecurityGroup.GroupName

その他にも配列から添え字で値を取り出したり、文字列を結合したりできる。(配列から値を取り出すぐらい関数とか使わずかけるようにしてほしいが、しょうがない。)
Fn::SubなんかもTerraformなら関数無しで変数展開してくれるのに、と思ってしまった。

Ref

パラメータまたはリソースの論理名(Resource定義の初めに書く名前)からID(インスタンスIDなど)を取得できる

記述例
MyEIP:
  Type: "AWS::EC2::EIP"
  Properties:
    InstanceId:
      Ref:
        MyEC2Instance

↓こちらも短縮できる

記述例(短縮形)
MyEIP:
  Type: "AWS::EC2::EIP"
  Properties:
    InstanceId: !Ref MyEC2Instance

RefFnを組み合わせる事もできる
↓アカウントIDを取得してIAMロールのARNの文字列を作る例

記述例(YAML)
Fn::Join:
- :
-
 - arn:aws:iam:
 - !Ref AWS::AccountId
 - role/xxxRole

↓短縮

記述例(YAML短縮形)
!Join
- :
-
 - arn:aws:iam:
 - !Ref AWS::AccountId
 - role/xxxRole

↓ワンライン

記述例(ワンライン)
!Join [:, [arn:aws:iam:, !Ref AWS::AccountId, role/xxxRole]]

疑似パラメータ

テンプレート内では事前定義されたいくつかの変数を利用することができる。
リージョンやアカウントIDなどにこの変数を指定することで複数リージョン間や複数アカウント間でのテンプレートの共有、共通環境の構築ができる。
詳細は下記公式リファレンスを参照のこと。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html

記述例
Outputs:
  MyStacksRegion:
    Value: !Ref "AWS::Region"
  MyStackAccount:
    Value: !Ref "AWS::AccountId"

Dynamic References

環境ごとに異なるが複数のサービスから共通で使うような変数や、パスワードなどの定義ファイルに記載したくない値はSSMやシークレットマネージャーに登録しておき、CloudFormationの実行時に取得させることができる。
スクリーンショット 2021-02-01 1.33.27.png

例えば、下記の例ではRDSのユーザ名やユーザパスワードなどのセキュアな情報はテンプレートに直接記載したくないので、シークレットマネージャーに登録しておきDynamic Referencesで動的に設定している。

記述例
  MyRDSInstance:
    Type: 'AWS::RDS::DBInstance'
    Properties:
      DBName: MyRDSInstance
      AllocatedStorage: '20'
      DBInstanceClass: db.t2.micro
      Engine: mysql
      MasterUsername: '{{resolve:secretsmanager:MyRDSSecret:SecretString:username}}'
      MasterUserPassword: '{{resolve:secretsmanager:MyRDSSecret:SecretString:password}}'

スタック

CloudFormationでの管理単位、同一スタック内での構築順序はスタック内のリソース同士の依存関係から自動的に決定される。
Terraformで言うとディレクトリやworkspaceの単位にあたる。
スクリーンショット 2021-02-01 1.15.35.png

リソースのインポート

いままでCloudFormationなど利用せずに手動や他のツールで構築したAWSリソースがあり、これからCloudFormationの管理対象にしたい場合はインポートすることもできる。
スクリーンショット 2021-02-01 1.32.03.png

スタック分割について

AWSリソース管理単位の分割については、はじめにある程度うまく分割しておかないと、後々困る。
スクリーンショット 2021-02-01 1.26.23.png

とはいえ、分割したリソース間でも参照したい場合があるので、これを実現する「クロススタック参照」という機能もある。

スクリーンショット 2021-02-01 1.28.07.png

スタック分割については最初に紹介した資料(【AWS Black Belt Online Seminar】AWS CloudFormation)でさらに詳しく説明されているので是非視聴してもらいたい。

スタックセット

CloudFormationではテンプレートを使用して、複数のリージョンのAWSアカウントにスタックを作成できる。
この機能をスタックセットという。
同一Organizations内のアカウントでない場合、対象の各アカウントからスタック作成を許可するIAMロールを引き受ける必要がある。
同一のOrganizations内で複数アカウントに対してリソースを作成する場合、IAMロールは必要ない。
参考:https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/stacksets-concepts.html

スタックとリソースの保護

作成後のスタックやリソースを変更や削除から保護する方法は複数ある。
スクリーンショット 2021-02-01 1.24.21.png

スタックポリシー

スタック作成時や作成後にスタック単位で変更/削除に対するポリシーを付与できる。
(作成後はCLIでしかポリシーの付与ができない。)
スクリーンショット 2021-02-01 1.24.59.png

文法はIAMポリシーなどのポリシードキュメントと同様
スクリーンショット 2021-02-01 1.25.19.png

DeletionPolicy

スタックの削除時に一部リソースのみ保持させたい場合や、バックアップを取得させたい場合に利用する。
スクリーンショット 2021-02-01 1.25.38.png

StackSets

マルチリージョン・マルチアカウントのデプロイを行える。
スクリーンショット 2021-02-01 1.20.31.png

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10