CloudFormationとは
CloudFormation(略称: CFn)はAWSから提供されているIaCツールの一つで、これを使用することでインフラストラクチャーをコードとして管理できるようになります。
YAMLまたはJSON形式のファイルでインフラの定義を行い、これをアップロードすることでファイルの状態になるようにインフラの作成・変更が可能です。
CLIでの操作
CloudFormationはマネージメントコンソールでのデプロイの他、AWS CLIからでもデプロイ可能です。 今回はAWS CLIを用いたCloudFormationのデプロイのオプションをいくつかのユースケースに分けて説明していきます。
オプションの一覧
aws cloudformation deploy
コマンドには以下のオプションがあります。(他のコマンドと共通のオプションを除く)
オプション | 説明 | 必須 |
---|---|---|
--template-file |
スタックで使用するテンプレートファイルを指定します。 | o |
--stack-name (value) |
スタックの名前を指定します。 | o |
--s3-bucket (value) |
テンプレートファイルをアップロードするS3バケットを指定します。 | x |
--force-upload |
S3上のテンプレートファイルを強制的に更新します | x |
--s3-prefix (value) |
テンプレートファイルをアップロードするS3バケットのプレフィックス(フォルダ)を指定します。 | x |
--kms-key-id (value) |
テンプレートファイルを暗号化するために使用するKMSキーのIDを指定します。 | x |
--parameter-overrides (value) [(value)...] |
スタックのパラメータを上書きします。 | x |
--capabilities (value) [(value)...] |
スタックに必要なIAM権限を指定します。 | x |
--no-execute-changeset |
変更セットを自動で実行しないようにします。 | x |
--disable-rollback or --no-disable-rollback |
スタックのロールバックを無効にします。(デフォルト: --no-disable-rollback ) |
x |
--role-arn (value) |
スタックのデプロイに使用するIAMロールを指定します。 | x |
--notification-arns (value) [(value)...] |
スタックのデプロイ状況を通知するSNSトピックのARNを指します。 | x |
--fail-on-empty-changeset or --no-fail-on-empty-changeset |
変更がない場合に、スタックの更新に失敗するかどうかを指定します。(デフォルト--no-fail-on-empty-changeset ) |
x |
--tags [(value)...] |
スタック内のリソースにタグを追加します。 | x |
シンプルなデプロイ
必須のオプション2つのみでの実行です。 今回使用しているテンプレートファイルは付録に書いておきます。
シンプルな例
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack
S3バケットの指定
以下ではアップロードするテンプレートのS3バケットを指定しています。
デフォルトではcf-templates
から始まるバケットが作成され、そこにテンプレートファイルが配置されます。
テンプレートをアップロードするS3バケットの指定
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack \
--s3-bucket sample-bucket \
--s3-prefix cfn
これを実行するとテンプレートファイルはS3のsample-bucket
の中のcfn/{ファイルMD5ハッシュ}.template
に配置されます。
強制的に上書きしたい場合は--force-upload
で上書きできます。
SAMを使ってるとこのオプションを使うこともあるようです、
--kms-key-id
を使用するとS3上で暗号化されて保存されます。引数はKMSのIDです。(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
のような形式)
これを指定することで、KMSへのアクセス権限を持たないユーザー・ロールからはS3バケットからはテンプレートがダウンロードできなくなります。万が一S3の設定を誤ってテンプレートがパブリックに公開されていてもひとまずは安心です。
ただ、KSMの権限を持たなくてもマネージメントコンソールのCloudFomationのページからは普通に生のテンプレートが見えます。
テンプレート中のパラメータの上書き
今回使用しているテンプレートファイルではVPCのIDをパラメータとしています。 デフォルト値が設定されているので今までは指定せずにデプロイできていました。 ここでは別のVPCを指定してみます。
テンプレート中のパラメータを上書き
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack \
--parameter-overrides VPCId=vpc-yyyyy
複数パラメータがある場合はスペースで区切って指定可能です。
テンプレート中のパラメータを上書き(複数)
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack \
--parameter-overrides VPCId=vpc-yyyyy AppPort=3000
複数個パラメータがある場合は以下のようなファイルを作ってパラメータを渡して上げると便利です。
sample.txt
VPCId=vpc-yyyyy
AppPort=3000
ファイルからパラメータを読み込み
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack \
--parameter-overrides $(cat sample.props)
IAMリソースが含まれるスタック
IAMリソースが含まれるスタックを作成する場合は--capabilities
の指定が必要になります。
これを指定しないとInsufficientCapabilities
というエラーが発生します。
指定できる値は以下の2つです。
値 | 説明 | ユースケース |
---|---|---|
CAPABILITY_IAM | IAMリソースの名前はCFnが自動で作成する | IAMリソース名にCFnが生成するプレフィクスが含まれても良い場合 |
CAPABILITY_NAMED_IAM | IAMリソース名を自分で指定する | IAMリソース名をテンプレート中の値で指定したい場合 |
AWS CLIのドキュメントには書かれていませんが、実はもう2つあります。CAPABILITY_RESOURCE_POLICY
とCAPABILITY_AUTO_EXPAND
の2つです。
ただ、ここで説明するとやや長くなるので、また別の記事で書こうかと思います。
IAMリソースを含むようなスタック
aws cloudformation deploy \
--template-file sample-role.yaml \
--stack-name sample-role-stack \
--capabilities CAPABILITY_NAMED_IAM
CFnテンプレートにおいてRoleName等のリソース名は実は必須ではなく、指定しない場合は以下の命名規則の名前のリソースが作成されます
{スタック名}-{リソース名}-{ランダムな値}
例で使っているテンプレートのRoleNameを指定しないと以下のようなRoleが作成されます。
sample-role-stack-SampleRole-{ランダムな値}
スタックの更新
一度作成したスタックを再度更新したいケースがあると思います。 更新に際して、変更セットと呼ばれるものが作成されるのですが、この実行を制御することも可能です。
--no-execute-changeset
を指定した場合は、自動的に変更セットが実行されません。
デフォルトでは変更が自動で実行されます。
後で変更セットを確認し実行したい場合などに有益なオプションです。
変更セットを自動的に実行しない
aws cloudformation deploy \
--template-file sample-update.yaml \
--stack-name sample-stack \
--no-execute-changeset
作成された変更セットはマネージメントコンソールまたはCLIから実行可能です。
--fail-on-empty-changeset
は変更セットがない場合にコマンド自体エラーコードで終わらせるオプションです。デフォルトでは失敗しません。
ロールバックの制御
CloudFormationではスタックの作成・変更に失敗した際に直前の正常な状態に戻すようにロールバックを行うことができます。
[アップデート]CloudFormationにロールバック前にプロビジョニングエラーをトラブルシューティングするオプションが導入されました | DevelopersIO
--disable-rollback
オプションを使用することで、作成に成功したリソースを保持できるようになります。
デフォルトでは自動でロールバックが行われます。
ロールバックを無効化
aws cloudformation deploy \
--template-file sample-invalid.yaml \
--stack-name sample-stack \
--disable-rollback
サービスロールを指定
CloudFormationではスタック作成に際して使用するIAMロールを指定することができます。 サービスロールを指定することでCloudFormationにデプロイする人の権限を分離し、さらにスタックの作成に際して必要な権限を管理しやすくなります。 デフォルトではAWS CLIを実行するのに使用しているロールが使用されます。
スタックの作成・変更を行うIAMロールを指定
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack \
--role-arn arn:aws:iam::{アカウントID}:role/sample-cfn-service-role
リソースにタグを一括して付与する
CloudFormationでは作成するリソースに対して一括でタグを付与できるので便利です。 これもパラメータの上書きと同様スペースで区切って複数指定可能です。
タグの一括付与
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack \
--tag Env=stg Project=sample-prj
SNS経由での通知
CloudFormationではデプロイの結果をSNSで通知することが可能です。 SNSを使えばメールやSlack(別途Lambdaなどで連携が必要)などで通知を受け取ることが可能なので便利かと思います。 こちらもパラメータやタグと同様にスペースで区切って複数設定する事が可能です。
SNSによる通知
aws cloudformation deploy \
--template-file sample.yaml \
--stack-name sample-stack \
--notification-arns arn:aws:sns:ap-northeast-1:{アカウントID}:sample-sns
終わりに
AWS CLIのCloudFormationのオプションを確認することができました。 マネージメントコンソールとの違いは変更セットあたりでしょうか?(マネージメントコンソールでは変更セットの作成の操作が必要) 同一のコマンドでスタックの更新ができるのは便利だと思いました。
付録
シンプルなテンプレート
sample.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: SecurityGroup Template Fix
Parameters:
VPCId:
Type: String
Default: vpc-xxxxx
AppPort:
Type: Number
Default: 80
Resources:
SecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "Sample Security Group"
GroupName: sample-sg
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: sample-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref AppPort
ToPort: !Ref AppPort
CidrIp: 172.16.0.10/32
更新用のテンプレート
sample-update.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: SecurityGroup Template
Parameters:
VPCId:
Type: String
Default: vpc-xxxxx
AppPort:
Type: Number
Default: 80
Resources:
SecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "Sample Security Group"
GroupName: sample-sg
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: sample-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref AppPort
ToPort: !Ref AppPort
CidrIp: 0.0.0.0/32 # ここを更新
デプロイが途中で失敗するテンプレート
sample-invalid.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: SecurityGroup Template
Parameters:
VPCId:
Type: String
Default: vpc-xxxxx
AppPort:
Type: Number
Default: 80
Resources:
SecurityGroup: #こっちは作成に成功して残る
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "Sample Security Group"
GroupName: sample-sg
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: sample-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref AppPort
ToPort: !Ref AppPort
CidrIp: 172.16.0.10/32
InvalidSecurityGroup: # こっちは作成できない
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "Sample Invalid Security Group"
GroupName: sample-invalid-sg
VpcId: vpc-aaaabbbbbcccc # 無意味なVPC ID
Tags:
- Key: Name
Value: sample-invalid-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref AppPort
ToPort: !Ref AppPort
CidrIp: 172.16.0.10/32
IAMリソースを作成するテンプレート
sample-role.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: IAM Role Defenition
Resources:
SampleRole:
Type: 'AWS::IAM::Role'
Properties:
# RoleName: sample-role # これを指定する場合はCAPABILITY_NAMED_IAMが必要
AssumeRolePolicyDocument:
Statement:
- Effect: "Allow"
Principal:
Service: "ec2.amazonaws.com"
Action: "sts:AssumeRole"
Path: "/"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore