それ積んどく?

ひたすら何かを積んでいくブログ

AWS CloudFormation と和解せよ

概要

AWS CloudFormation を使用するときに知りたいことを記載。
基本的なテンプレートの書き方とスタックの作り方まで。

  • スタック名に _ は使えない(記号は - のみ使用可能)。
  • テンプレートとは、CloudFormation サービスで展開するリソースを定義したテキストファイル。
    • YAML または JSON 形式で記載する。
    • 展開したリソースは実行単位でスタックとして管理される。
  • テンプレート中で使用可能な様々な組み込み関数がある。
  • 対応するサービスとしないサービスがあり、内容は随時アップデートされている。
  • スタックを消すとデフォルトでは作成したリソースも削除される。
    • 何らかのデータを保持するリソースは、削除の保護などで誤削除を防止する。
  • 本記事では扱わないが、テンプレートはネストできる。

[公式リファレンス]

CloudFormation とは

AWS リソースをコードで記述し、展開できるサービス。
所定の書式に従いテンプレートを作成すればその内容に基づいたリソース作成が行える。

  • サービス間の依存関係はサービス側で解決してくれる。
    • EC2 作成の前に VPC が必要などの作成順序をユーザが気にする必要がなくなる。
    • 依存関係の明示的な指定も可能。スタックをネストするなど、特定のケースで使う。
  • リソースの展開、削除が簡単になる。
    • スタックという単位でリソースが展開され、この単位で更新や削除が一括で行える。
    • パラメータ」を使用することで、一部環境のみ設定を変えるなど柔軟な展開も出来る。
  • コードで環境を管理できるようになる。
    • 環境変更を行う場合に、テンプレートの修正 -> 展開 の流れで行うことで、環境の一貫性を保てる。
    • ドリフトの検出」の機能で、テンプレートと実環境との差分検出が可能。
    • 更新時は、「変更セット」を活用する。
  • 作成可能なリソースは、CloudFormation 実行ユーザの権限、またはサービスロールで与えた権限に依存する。

see also

ベストプラクティス

利用時に一読すべし。

see also

テンプレート

セクション

テンプレートの大きな構成要素。

[主な要素]

★はよく使うもの(個人的見解)。

  • ★AWSTemplateFormatVersion:
    • テンプレートバージョン。
      • 2010-09-09 で固定。
    • 今は必須ではない?(昔は必須だった気がする)。
  • ★Description:
    • テンプレートの説明。
  • ★Metadata:
    • Parameters の UI を整理するときによく使う。
    • テンプレートに関する追加情報。
  • ★Parameters:
    • スタック構築時にユーザに指定させる値を指定。
  • Mappings:
    • キーと値のマッピング
    • Fn::FindInMap 関数と組み合わせ利用する。
      • リソースのパラメータ設定時に設定したキーに応じた値を取得し設定する。
    • Mappings - AWS CloudFormation
  • Conditions:
  • Transform:
    • サーバーレスアプリケーションや定型コンテンツ挿入などのためのマクロを指定。
  • ★Resources(必須)
    • 起動するリソースのタイプやプロパティを指定。
      • <Logical ID>: 論理 ID(テンプレート中でユニークな名前を指定)
      • Type: <Resource type> => リソースタイプ(リソースごとに規定のタイプを指定)
      • Properties: <properties> => リソースごとのプロパティ(タイプごとに異なる)
  • Outputs
    • スタック構築後に作成したリソース ARN などを出力できる。
      • URL を出力するなど色々使える。
    • Export: を定義することで、外部参照(他のスタックからの参照)も可能。

see also

Metadata によるパラメータの整理

AWS::CloudFormation::Interface を使用。
ユーザがパラメータを入力する際に関連のあるものをまとめたり、
順番を揃えたりすることでパラメータ入力時の可読性が向上する。
(デフォルトは、内容に関係なく論理 ID 順でソートされるため、非常に使いづらい。)

  • ParameterGroups: において Label 単位に Parameters の項目を整理できる。
    • 記述は Parameters: 中の論理リソース名を使用する。
  • default: に設定した文字列が UI 上に名前として表示される。
  • ParameterLabels: で Parameters の各パラメータの別名を表示できる。
    • デフォルトはパラメータリソース名がそのまま表示される。

[例示]

Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups: 
      - Label: 
          default: "Resource Name Prefix"
        Parameters: 
          - CfPrefix
          - EnvType
#~
      - Label: 
          default: "User Configuration"
        Parameters: 
          - OnpreCIDR
          - TagRelease
  ParameterLabels: 
      CfPrefix: 
        default: "Resource name Prefix"
#...

see also

サンプルテンプレート

VPC を作るケースを元によく使う内容を記載。

  • 実行するとサブネットを 2 つ持つ VPC が出来る。
  • EnvType が transit の場合のみ、VGW が作成されるよう判定を組み込んでいる。

      Conditions: 
        CreateVGW: !Equals [ !Ref EnvType, transit ]
      ...
        CfVGW:
          Type: AWS::EC2::VPNGateway
          Condition: CreateVGW
    

[CLI]

aws cloudformation create-stack \
  --stack-name SampleCFCreateVPC \
  --template-body file://sample-cf_create-vpc.yml \
  --parameters ParameterKey=EnvType,ParameterValue=guest

[sample-cf_create-vpc.yml]

AWSTemplateFormatVersion: 2010-09-09
Description: Create VPC(only transit-VPC creates VGW)

Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups: 
      - Label: 
          default: "Resource Name Prefix"
        Parameters: 
          - CfPrefix
          - EnvType
      - Label: 
          default: "Network Configuration"
        Parameters: 
          - VPCCIDR
          - PrivateSubnetACIDR
          - PrivateSubnetAName
          - PrivateSubnetAZone
          - PrivateSubnetBCIDR
          - PrivateSubnetBName
          - PrivateSubnetBZone
      - Label: 
          default: "Custom Configuration"
        Parameters: 
          - OnpreCidr
          - TagRelease

Parameters: 
  CfPrefix:
    Type: String
    Description: resource name prefix
    Default: SampleCF

  EnvType:
    Type: String
    Description: vgw create-flag
    Default: guest
    AllowedValues:
      - transit
      - guest

#-----------------------
# Network Configuration
#-----------------------
  VPCCIDR:
    Type: String
    Default: 172.16.0.0/26

# SubnetA
  PrivateSubnetACIDR:
    Type: String
    Default: 172.16.0.0/27

  PrivateSubnetAName:
    Type: String
    Default: SubnetA

  PrivateSubnetAZone:
    Default: apne1-az1
    Description: Expand resource to selected AZ
    Type: String
    AllowedValues:
      - apne1-az1
      - apne1-az2

# SubnetB
  PrivateSubnetBCIDR:
    Type: String
    Default: 172.16.0.32/27

  PrivateSubnetBName:
    Type: String
    Default: SubnetB

  PrivateSubnetBZone:
    Default: apne1-az2
    Description: Expand resource to selected AZ
    Type: String
    AllowedValues:
      - apne1-az1
      - apne1-az2


#-----------------------
# Custom Configuration
#-----------------------
# CustomParameters
  OnpreCidr:
    Type: String
    Description: use Transit VPC Only
    Default: 10.0.0.0/24

# Release-TAG
  TagRelease:
    Type: String
    Description: Rewrite by release months and years("yyyy-mm")
    Default: 2023-01

Conditions: 
  CreateVGW: !Equals [ !Ref EnvType, transit ]

Resources: 
  CfVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub ${CfPrefix}-VPC
        - Key: Release
          Value: !Sub ${TagRelease}

  PrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref PrivateSubnetACIDR
      MapPublicIpOnLaunch: false
      VpcId: !Ref CfVPC
      AvailabilityZoneId: !Ref PrivateSubnetAZone
      Tags:
        - Key: Name
          Value: !Sub ${CfPrefix}-VPC_subnet_${PrivateSubnetAName}
        - Key: Release
          Value: !Sub ${TagRelease}

  PrivateSubnetB:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref PrivateSubnetBCIDR
      MapPublicIpOnLaunch: false
      VpcId: !Ref CfVPC
      AvailabilityZoneId: !Ref PrivateSubnetBZone
      Tags:
        - Key: Name
          Value: !Sub ${CfPrefix}-VPC_subnet_${PrivateSubnetBName}
        - Key: Release
          Value: !Sub ${TagRelease}

# Create Route Table
  CfRouteTableCommon:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CfVPC
      Tags:
        - Key: Name
          Value: !Sub ${CfPrefix}-VPC_rt-tbl_common
        - Key: Release
          Value: !Sub ${TagRelease}

  CfAssocciateRouteTableForPrivateSubnetA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableCommon
      SubnetId: !Ref PrivateSubnetA
  
  CfAssocciateRouteTableForPrivateSubnetB:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableCommon
      SubnetId: !Ref PrivateSubnetB

# Create VGW(TransitVPC Only)
  CfVGW:
    Type: AWS::EC2::VPNGateway
    Condition: CreateVGW
    Properties: 
      Type: ipsec.1
      Tags: 
      - Key: Name
        Value: !Sub ${CfPrefix}-VPC_VGW
      - Key: Release
        Value: !Sub ${TagRelease}

  CfVGWAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Condition: CreateVGW
    Properties: 
      VpcId: !Ref CfVPC
      VpnGatewayId: !Ref CfVGW

  CfRouteToOnpre:
    Type: AWS::EC2::Route
    Condition: CreateVGW
    Properties:
      RouteTableId: !Ref CfRouteTableCommon
      DestinationCidrBlock: !Ref OnpreCidr
      GatewayId: !Ref CfVGW

Outputs:
  CreateVpnID:
    Value: !Ref CfVPC
    Export:
      Name: !Sub ${CfPrefix}VpnID

(CLI)構文チェック

構文チェックが可能。
あくまで構文の検査のみで実行時エラーは検出できない。
(パラメータの型不一致などは実行して初めて分かる)

[CLI]

# url
aws cloudformation validate-template --template-url https:<hoge>
# file
aws cloudformation validate-template --template-body file://<hoge>.yml

・下記のように中身に言及されていないエラーの場合、コマンドの構文を疑ってみる。

An error occurred (ValidationError) when calling the ValidateTemplate operation: Template format error: unsupported structure.

  • --template-bodyfile:// が抜けやすい。

Unable to load paramfile のエラーは、テンプレートの文字コードを疑う(主に Windows 環境)。

see also

YAML の書き方

個人的には YAML のほうが好き(生 JSON 書けない)。

  • 基本はキーと値のマッピング('Key' => value)。
    • key: value:value の間はスペースを入れる。
    • 値はスカラー型(""の利用は任意)。
      • 型付けは自動。タグにより明示も可能(!!<tag>)。
    • 数値のみの場合は数値扱い("" で囲むと文字列)。
    • その他のデータ型
      • true | false は真偽値。
      • null は NULL。
  • データ構造はインデントで表す。
    • インデントは 2 つのスペースで表現する。
  • 要素は入れ子に出来る。
    • インデントでネスト。
  • - はシーケンス(配列)を表す。
  • 記号を使った表現(フロースタイル)も可能。
    • [PHP, Perl, Python] 角カッコ([]) もシーケンス。
    • { PHP: 5.2, MySQL: 5.1, Apache: 2.2.20 } 波カッコ({}) はマッピング
    • 組み合わせも可能。
      • '第1章': [はじめに, イベントの種類]
  • # 以降の行がコメント。

[例示]

docker:
    - image: ubuntu:14.04
    - image: mongo:2.6.8                # 2 つのマッピングを要素に持つ
      command: [mongod, --smallfiles]   # フロースタイル
    - image: postgres:9.4.1

上記の JSON

{
  "docker": [
    {
      "image": "ubuntu:14.04"
    }, 
    {
      "image": "mongo:2.6.8", 
      "command": [
        "mongod", 
        "--smallfiles"
      ]
    }, 
    {
      "image": "postgres:9.4.1"
    }
  ]
}

"mongod" の参照(たぶん)。

$.docker[1].command[0]

リテラルブロック

|> 記号を使った表現。改行を含む複数行に渡る値の記述が可能。
記号との組み合わせで末尾の改行の処理が変わる。

  • | ... 何もなし。以降の改行は文字列上の改行として処理(見た目通り)。
  • |+ ... 文字列中の改行は保持。更に最終行に改行が付与される。
  • |- ... 文字列中の改行は保持。更に最終行の改行が除去される。
  • > ... 途中の改行はスペースとみなされる。最終行のみ改行。
    • >+, >-+- の作用は | の場合と同じ。
  abc: |
    123
    456
    789

see also

YAML オンラインパーサー

YAML を見て ?? となったときに便利(ネストが重なると思考が止まる)。

YAML Tips

よく忘れることを書く。

[マッピングにシーケンスが入れ子している場合の参照]

{
    "detail": {
      "findings": [
        {
#...
          "Severity": {
            "Normalized": 50,
            "Label": "MEDIUM",
          }
        }
      ]
#...
    }
}

上記から "Label" を抜く。
コレクションに含まれる配列の参照は、findings[0] のように書く。

"Serverity": "$.detail.findings[0].Severity.Label",

組み込み関数

[Tips]

  • !Ref 等の参照系の関数で返り値に何が返ってくるかはリソースタイプごとに定義されている。
  • リソースの "Properties" の各パラメータが何の値を求めるかも上記のリファレンスに定義されている。
    • そのため、関数の返り値が要求されているパラメータと一致するか確認が必要。
  • それぞれの関数は 完全名関数 と 短縮形 の 2 つの構文がある。
    • 完全名: Fn::XX
    • 短縮形: !XX
  • 短縮系構文は連続して使用できない(完全名関数の構文を交互に組み合わせる必要がある)。
    • ○: Fn::GetAZs: !Ref 'AWS::Region'
    • X: !GetAZs !Ref 'AWS::Region'
      • ! の連続は見た目も違和感があり、なんとなく使えなそうな雰囲気はある。

[よく出る名前]

  • パラメータの論理名
    • Parameters セクションで指定した名前。
  • リソースの論理名
    • Resources セクションで指定した名前。

see also

Fn::Ref

指定したパラメータまたはリソースの値を返す。

  • パラメータの論理名を指定
    • パラメータの値を返す。
      • Parameters で設定した値が取得される(!Sub ${Variable} と同じ用法}。
  • リソースの論理名を指定
    • リソースを参照するために通常使用できる値を返す(物理 ID)。
      • Resource: で指定した各リソースの名前を指定すると該当リソースの ARN が取得される。
    • Ref でほしい値が取れない場合は、GetAtt の利用を検討。

[構文]

完全名関数の構文:

Ref: <logicalName>

短縮形の構文:

!Ref <logicalName>
  • <logicalName>
    • 引数に関数は使用できない。リソースの論理 ID である文字列を指定する。

see also

Fn::GetAtt

リソースごとに定義された特定の属性を取得する。

[構文]

完全名関数の構文:

Fn::GetAtt: [ logicalNameOfResource, attributeName ]

短縮形の構文:

!GetAtt logicalNameOfResource.attributeName
  • logicalNameOfResource
    • 必要な属性を含むリソースの論理名 (論理 ID)。
  • attributeName
    • リソース固有の属性の名前。

[例示]

ELB の DNS 名を取得。

# 短縮形
!GetAtt myELB.DNSName

# 完全名関数
"Fn::GetAtt": [ "myELB" , "DNSName" ]

see also

Fn::Sub

変数のように使いユーザ入力値などと組み合わせた動的なパラメータ生成ができる。

  • 変数を Parameters で入力された値に置き換える等、実行時に変数展開ができる。
  • Ref との組み合わせや AWS::Region 等の疑似パラメータもよく使う。

[構文]

完全名関数の構文:

Fn::Sub:
  - String
  - Var1Name: Var1Value
    Var2Name: Var2Value

短縮形の構文:

!Sub
  - String
  - Var1Name: Var1Value
    Var2Name: Var2Value
  • <String> に関数の利用は不可(文字列のみ可)。
  • Var1Name: Var1Value は String 中で置き換える(マッピング)パラメータのマッピング
    • 置換が必要な場合のみパラメータを与える。

[例示]

# マッピングあり
  - Name: !Sub
    - www.${Domain}
    - { Domain: !Ref RootDomainName }

# マッピングなし(疑似パラメータのみ)
!Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'

see also

Fn::FindInMap

Mappings セクションで宣言された 2 つのレベルのマッピングのキーに対応する値を返す。

[構文]

完全名関数の構文:

Fn::FindInMap: [ MapName, TopLevelKey, SecondLevelKey ]

短縮形の構文:

!FindInMap [ MapName, TopLevelKey, SecondLevelKey ]

[例示]

Mappings: 
  RegionMap: 
    us-east-1: 
      HVM64: "ami-0ff8a91507f77f867"
      HVMG2: "ami-0a584ac55a7631c0c"
    ap-northeast-1: 
      HVM64: "ami-06cd52961ce9f0d85"
      HVMG2: "ami-053cdd503598e4a9d"
Resources: 
  myEC2Instance: 
    Type: "AWS::EC2::Instance"
    Properties: 
      ImageId: !FindInMap
        - RegionMap
        - !Ref 'AWS::Region'
        - HVM64
      InstanceType: m1.small

see also

言語拡張の利用(FindInMap)

テンプレート中に言語拡張の記述を加えることで、拡張構文の利用が可能になる。

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
  • 前述の FindInMap のデフォルトの利用に必要。
    • DefaultValue: <デフォルト値>
    • DefaultValue: のキー名は固定。
  • これ以外にも組み合わせが可能な関数の種類が増える。

詳細はドキュメント参照。

[例示]

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
#...
# Mappings では個別の値を定義
Mappings: 
  RegionMap: 
    us-east-1: 
      HVM64: "ami-0ff8a91507f77f867"
      HVMG2: "ami-0a584ac55a7631c0c"
    ap-northeast-1: 
      HVM64: "ami-06cd52961ce9f0d85"
      HVMG2: "ami-053cdd503598e4a9d"
Resources: 
  myEC2Instance: 
    Type: "AWS::EC2::Instance"
    Properties: 
      ImageId: !FindInMap
        - RegionMap
        - !Ref 'AWS::Region'
        - HVM64
        # マッピング中で定義したリージョン以外の場合はこの値を設定。
        - DefaultValue: "ami-XXX"
      InstanceType: m1.small

see also

Fn::Select

インデックスによってオブジェクトのリストから 1 つのオブジェクトを返す。

  • index は 0 始まり。

[構文]

完全名関数の構文:

Fn::Select: [ index, listOfObjects ] 

短縮形の構文:

!Select [ index, listOfObjects ]
  • index
    • 0 - N-1 まで(N は listOfObjects の要素数)。
  • listOfObjects
    • シーケンスを指定([])。
    • null は指定不可。

[例示]

AWS::Region において Fn::GetAZs が返す配列の最初の要素を選択。

Fn::Select: 
  - 0
  - Fn::GetAZs: !Ref AWS::Region

see also

Fn::ImportValue

他のスタックでエクスポートされた値をインポートして利用する。
(これにより別のスタックで作成するリソースの ARN などを連携できる。)

  • Outputs セクションにおいて Export が必要。
    • エクスポートされた値は、リージョン内でのみ有効。
    • かつエクスポート名はリージョン内で一意である必要がある。
  • 他のスタックがエクスポートされた値を利用している状態では、当該スタックは削除できなくなる。
    • つまり依存関係が出来る。
    • 他のスタックから参照されている出力が存在する場合は、スタックを削除することはできません。

[構文]

完全な関数名:

Fn::ImportValue: sharedValueToImport

短縮形:

!ImportValue sharedValueToImport

[制約]

  • ImportValueSub 関数の短縮形と組み合わせはできない。
    • 書き方は例示を参照。
    • !ImportValue が含まれている場合、!Sub の短縮形を使用することはできません。

  • ImportValueRefGetAtt などリソースに依存する関数は組み合わせられない。
    • エクスポート名も同じ制約を持つ。
    • ImportValue 関数に、リソースに依存する Ref または GetAtt 関数を含むことはできません。

[例示]

(エクスポート)

Outputs:
  PublicSubnet:
    Description: The subnet ID to use for public web servers
    Value:
      Ref: PublicSubnet
    Export:
      # エクスポート名を定義してエクスポートする。
      Name:
        'Fn::Sub': '${AWS::StackName}-SubnetID'
  WebServerSecurityGroup:
    Description: The security group ID to use for public web servers
    Value:
      'Fn::GetAtt':
        - WebServerSecurityGroup
        - GroupId
    Export:
      Name:
        'Fn::Sub': '${AWS::StackName}-SecurityGroupID'

(インポート)

Resources:
  WebServerInstance:
    Type: 'AWS::EC2::Instance'
    Properties:
      InstanceType: t2.micro
      ImageId: ami-a1b23456
      NetworkInterfaces:
        - GroupSet:
            # エクスポート名を参照する。
            # Sub 関数は完全名関数を使用する
            - !ImportValue 
              'Fn::Sub': '${NetworkStackNameParameter}-SecurityGroupID'
          AssociatePublicIpAddress: 'true'
          DeviceIndex: '0'
          DeleteOnTermination: 'true'
          SubnetId: !ImportValue 
            'Fn::Sub': '${NetworkStackNameParameter}-SubnetID'

see also

文字列操作関数(Join,Split)

結合と分割、対になる文字列操作関数。

  • Fn::Join
    • 配列の要素を指定したデリミタで結合する。
      • デリミタは省略可能。その場合は配列中の要素がそのまま結合される。
      • 返り値は、結合された文字列。
    • 構文
      • 完全名関数の構文: Fn::Join: [ delimiter, [ comma-delimited list of values ] ]
      • 短縮形の構文: !Join [ delimiter, [ comma-delimited list of values ] ]
    • 文字列結合自体は Sub 関数でも出来る。
      • ex) : でのパラメータの結合
        • !Sub ${Param1}:${Param2}:${Param3}
  • Fn::Split
    • 文字列を指定のデリミタで分割する。
      • 返り値は、分割した要素を含む配列。
    • 構文
      • 完全名関数の構文: Fn::Split: [ delimiter, source string ]
      • 短縮形の構文: !Split [ delimiter, source string ]
    • 主に Select 関数と組み合わせて使う。
      • ex) 3番目の要素を取得。
        • !Select [2, !Split [",", !ImportValue AccountSubnetIDs]]

see also

文字列操作の応用例

Sub、Join 及び Split の組み合わせ。

[例示1]

NamePrefix のデリミタを .- に変換。
(Split で分解して得た配列をソースに、Join で結合する)。

!Sub  
  - ${Prefix}-lambda  
  - Prefix:  
      !Join [ "-", !Split [".", !Ref NamePrefix]]

[例示2]

リソース名の一部を取得し、サービス名に利用する。
(命名規則がわかれば色々応用が効きそう)

      ServiceName: !Sub
        - com.amazonaws.vpce.ap-northeast-1.vpce-svc-${vpceid}
        - vpceid: !Select [ "2", !Split ["-", !Ref TransitVpcEndpointService]]

see

条件関数

簡単な条件分岐が書ける。
テスト環境と本番環境でリソースを分けるなどの用途に使う。

Fn::If 条件を除くすべての条件は、テンプレートの Conditions セクションで定義します。Fn::If 条件は、テンプレートの Resources セクションと Outputs セクションのメタデータ属性、更新ポリシー属性、およびプロパティ値で使用できます。

  • If 以外は、Conditons セクションのみで使う。
    • IfConditions セクションの演算結果を受けた実際の分岐処理を書くのに使う。
  • Conditions セクションでは条件関数のインプットの一部となる 条件 を定義する。
    • !Condition で条件の結果を参照可能。
      • ex) !Condition SomeOtherCondition
    • 条件式を使用した演算も条件となる。
      • ex) !Equals ["sg-mysggroup", !Ref ASecurityGroup]
  • いずれの関数も配列を引数に取るため。[] の記載を忘れないこと。
    • かつ、一部はシーケンスの順番が意味を持つ。
  • 条件式はネストして組み合わせが行える。

[条件関数]

基本的にイメージ通りの挙動をする。

  • Fn::If
    • Conditions セクションの演算結果を受けた実際の分岐処理を書く。
    • 構文: !If [<条件>, 真, 偽]
      • <条件> に真偽値(true |false)を持つパラメータを与え、処理を分岐させる。
      • この <条件> は通常、Conditions セクションで後述の条件式による演算を経て決定する。
  • Fn::And
    • 構文: !And [<条件>,...]
      • 条件を含む配列を与える。すべて true の場合に true を返す。
      • Equals など他の条件式と組み合わせて使う。
      • <条件> の最低数は 2 。最大数は 10 。
  • Fn::Or
    • 構文: !Or [<条件>,...]
      • 条件を含む配列を与える。いずれかが true の場合に true を返す。
  • Fn::Equals
    • 構文: !Equals [値1, 値2]
      • 比較を行う値を与える。文字列比較が可能。
        • ex) !Equals ["sg-mysggroup", !Ref ASecurityGroup]
  • Fn::Not
    • 構文: !Not [<条件>]
      • <条件> を反転した結果を返す。
        • ex) 本番関係以外なら true
          • !Not [!Equals [!Ref EnvironmentType, prod]]

[例示]

If の条件である CreateProdResources は本番環境でのみ true になる。

Parameters:
  EnvType:
    Description: Environment type.
    Default: test
    Type: String
    AllowedValues:
      - prod
      - test
    ConstraintDescription: must specify prod or test.
#...
Conditions:
  CreateProdResources: !Equals #<- 条件判定(条件名: CreateProdResources の定義)
    - !Ref EnvType
    - prod
Resources:
#...
NewVolume:
  Type: "AWS::EC2::Volume"
  Condition: CreateProdResources
  Properties: 
    Size:
      !If [CreateLargeSize, 100, 10] #<- 分岐
    AvailabilityZone: !GetAtt EC2Instance.AvailabilityZone

see also

Fn::Base64

入力文字列から Base 64 を生成する。
マニュアル記載の通り、UserData でよく使う。

組み込み関数 Fn::Base64 は、入力文字列の Base64 表現を返します。この関数は通常、UserData プロパティを介して Amazon EC2 インスタンスエンコードされたデータを渡すために使用されます。

[例示]

  TestSV: 
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: !Ref EC2ImageId
#...
      UserData: !Base64 |
        #!/bin/bash
        sudo yum update -y
        sudo yum install -y net-snmp-utils telnet
#...

see also

Fn::Cidr

指定プレフィックスから任意のホストアドレス長を持つネットワークを指定数作成する。

組み込み関数 Fn::Cidr は CIDR アドレスブロックの配列を返します。返される CIDR ブロックの数は、count パラメータによって異なります。

[例示]

プレフィックス「/24」 の CIDR から、内部にサブネットマスク「/27」 の CIDR を 6 つ 作成

!Cidr [ "192.168.0.0/24", 6, 5 ]
  • /27 は 32 - 5 で、ここにはホストアドレス長を指定する

see also

Fn::GetAZs

指定したリージョンの AZ をアルファベット順で返す。

  • 実行ユーザがアクセス可能な AZ を取得できる。
  • パラメータを与えない場合は、"AWS::Region" を指定したものとなる。
  • 関数の実行に下記の権限が必要。
    • スタック実行ユーザが、指定する IAM ロールに権限を持たせる。
    • ec2:DescribeAvailabilityZones
    • ec2:DescribeAccountAttributes
    • ec2:DescribeSubnets

[例示]

mySubnet: 
  Type: "AWS::EC2::Subnet"
  Properties: 
    VpcId: 
      !Ref VPC
    CidrBlock: 10.0.0.0/24
    AvailabilityZone: 
      Fn::Select: 
        - 0
        - Fn::GetAZs: ""

see also

Fn::Transform

CloudFormation の言語拡張で利用するが、これ自体は活用したことがない。

組み込み関数 Fn::Transform は、スタックテンプレートの一部に対してカスタム処理を実行するためのマクロを指定します。マクロを使用すると、検索して置換操作のような単純なアクションからテンプレート全体の広範な変換まで、テンプレートに対してカスタム処理を実行できるようになります。詳細については、「AWS CloudFormation マクロを使用したテンプレートのカスタム処理の実行」を参照してください。

see also

スタックの操作

  • 作成
    • テンプレートを用いたスタックの新規作成。
    • S3 バケットにテンプレートをアップロードして指定する。
  • 更新
    • 変更セットを使用しない更新。
      • 既存テンプレートを流用した、パラメータ値の更新。
      • 更新したテンプレートを利用したスタックリソースの更新。
  • 変更セットによる更新
    • 変更セットによる差分確認のステップを挟んだ更新。
      • 変更セットは複数作成でき、実行時に一括実行される。
        • 反映しない変更セットは削除しておく。
      • 変更セットごとに差分の記録が残る。
    • 実行後の変更セットは削除できない(試した限りは)
      • 実行後の変更を取り消す場合は、切り戻し用の変更セットを再度作成する。
  • 削除

see also

スタックの作成

[パラメータ例示(GUI)]

  • テンプレートの準備
    • 新規テンプレート or サンプル or テンプレートの作成(デザイナー)
  • スタックの名前: <任意>
    • _ は使えない。- か大文字小文字の使い分けで見た目を工夫する。
  • スタックの詳細を指定
    • パラメータ:
      • Parameters にパラメータを設定した場合に入力。
  • スタックオプションの設定
    • タグ
      • 設定は任意。
    • アクセス許可
      • IAM ロールを指定(リソースの作成権限)。
    • スタックの失敗オプション
    • 詳細オプション
      • ロールバック設定
        • モニタリング時間と、モニタリングする CloudWatch アラーム(ARN) を指定。
        • 指定したアラームしきい値が超過した場合、ロールバックされる。
      • 通知オプション
        • SNS トピックを指定。
      • スタックの作成オプション
  • レビュー
    • [x] AWS CloudFormation によって IAM リソースがカスタム名で作成される場合があることを承認します。

see also

(CLI)スタックの作成

CLI での実施例。

[作成]

aws cloudformation create-stack \
  --stack-name Stack-name \
  --template-body file://hogehoge.yml \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameters ParameterKey=Key,ParameterValue=value1

[確認]

aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE
aws cloudformation describe-stacks --stack-name myteststack

see also

[リソースに IAM を含む場合]

CLI 実行時に引っかかることが多い。
オプションに下記を追加(GUI では意識不要)。

--capabilities CAPABILITY_NAMED_IAM

see also

スタックの更新(変更セット)

スタックを更新する場合は通常の更新ではなく「変更セット」の利用を検討する。
対象のスタックを選択後、「変更セットを作成」から操作する。

[操作の流れ]

実際の変更前に差分確認が行える。

  1. 変更セットの作成
    1. 新規作成時と概ね同じ流れ。
  2. 差分の確認
    1. テンプレートまたはパラメータ変更に伴い発生するリソース差分が表示される。
  3. 変更セットの実行 or 削除
    1. 差分が意図しない内容だった場合、変更セットの削除で対応できる。
      1. 実行するまで変更は反映されない。
    2. 追加の変更が必要な場合は、変更セットを追加で作成する。
    3. 問題なければ実行して差分を反映する。
      1. リソース作成エラーなどの実行結果はこの段階でわかる。

[パラメータ例示(GUI)]

  • テンプレートの準備
    • 現在のテンプレート or 置き換え or テンプレートの編集(デザイナー)
  • スタックの詳細を指定
    • 変更セット名: 自動生成される(変更可能)
    • 変更セットの説明: テンプレートの Description がデフォルトで記載。
    • パラメータ:
      • Parameters にパラメータを設定した場合に入力。
  • スタックオプションの設定
    • タグ
      • 設定は任意。
    • アクセス許可
      • IAM ロールを指定(リソースの作成権限)。
    • 詳細オプション
      • ロールバック設定
        • モニタリング時間と、モニタリングする CloudWatch アラーム(ARN) を指定。
        • 指定したアラームしきい値が超過した場合、ロールバックされる。
      • 通知オプション
        • SNS トピックを指定。
      • 変更セット
        • ネストされたスタックの変更セットの作成有無(デフォルト有効)
  • レビュー
    • [x] AWS CloudFormation によって IAM リソースがカスタム名で作成される場合があることを承認します。

see also

(CLI)変更セット

[変更セット名の作成]

ユニークな変更セット名を自動生成するため、ランダム文字列を取得。

#Windows(PowerShell)
$UNIQUE = -join ((1..10) | %{(65..90) + (97..122) | Get-Random} | % {[char]$_})
Write-Output $UNIQUE

#Linux
UNIQUE=$(tr -dc 0-9A-Za-z < /dev/urandom | fold -w 10 | head -1)
echo $UNIQUE

[作成]

STACK=XXX

aws cloudformation create-change-set \
  --stack-name ${STACK} \
  --change-set-name=${STACK}-${UNIQUE} \
  --template-body file://hogehoge.yml \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
  --parameters ParameterKey=Key,ParameterValue=value

[変更セットの確認]

aws cloudformation list-change-sets --stack-name ${STACK}

[変更セットの操作]

変更セット名をオプションに加える。

aws cloudformation <operation> --stack-name ${STACK} --change-set-name ${STACK}-${UNIQUE}
  • \
    • describe-change-set ... 変更内容の確認。
    • execute-change-set ... 実行。
    • delete-change-set ... 削除。

(コピペ用)

aws cloudformation describe-change-set --stack-name ${STACK} --change-set-name ${STACK}-${UNIQUE}
aws cloudformation execute-change-set --stack-name ${STACK} --change-set-name ${STACK}-${UNIQUE}
aws cloudformation delete-change-set --stack-name ${STACK} --change-set-name ${STACK}-${UNIQUE}

see also

(CLI)スタックの削除

[CLI]

aws cloudformation delete-stack --stack-name my-stack