前提知識
まず、スタックやネストといった言葉の意味がよくわかっていない人は、たぶんCloudFormation
の概要がつかめてないと思いますので、最初はこちらを参照ください。
AWS CloudFormationってなんだ
ネストしたスタックの概要
CloudFormation
で個別に、Aスタック、Bスタック、Cスタックと作成して、これらをまとめて一つのアーキテクチャとして作成する場合は、AスタックからBスタックを参照するためにImport
、Outputs
関数を使うのですが、ある程度の規模のスタックになるのこの参照関係が実に面倒になってきます。
特にスタックが相互に参照している場合です。例えば、AスタックはBスタックの値を参照していてかつBスタックもAスタックの値も参照している。このような場合、wait
などを使って、スタックの作成の順番をこちらで指定する必要があります。
さらに、相互参照のスタックを削除するのも結構面倒です。削除する場合はAスタックの参照を一度、消して、それからBスタックをアップデートして、Aスタックを削除、そして、Bスタックを削除するなんていう面倒なことになります。
ここまでくると流石にまとめてスタックを作りたくなりますよね。そこで使うのがネスト
です。
親スタックの配下に子スタックを作成し、親スタックを作成すればまとめて子スタックが作成され、削除する場合も親スタックを削除すれば子スタックもまとめて削除できるようにします。
ディレクトリ構造
まずは、最初にディレクトリの構造を説明します。正直、ディレクトリの構造は人それぞれなので、あくまでも参考程度にしてください。
1
2
3
4
5
6
7
8
9
10
| .
├── Makefile
└── nested-stack
├── architect-bucket
│ └── s3.yml
├── master.yml
├── package
│ └── packaged.yml
├── s3-1.yml
└── s3-2.yml
|
Makefile
CloudFormationではaws cliのコマンドを何回も実行することが多いです。コマンド実行の度に、このような長ったらしいコマンドを実行するのは実に面倒です。
1
| aws cloudformation create-stack --stack-name myteststack --template-body file://sampletemplate.json --parameters ParameterKey=KeyPairName,ParameterValue=TestKey ParameterKey=SubnetIDs,ParameterValue=SubnetID1\\,SubnetID2
|
なので、予めMakefile
に、これらのコマンドをいい感じにまとめておきます。そうすれば、make create
みたいな感じで実行するだけよくなります。
nested-stack
これはCloudFormationで展開するサービスを入れているフォルダです。このフォルダ内に作りたいスタックを入れてます。
- master.yml (親テンプレート)
- s3-1.yml (子テンプレート)
- s3-2.yml (子テンプレート)
architect-bucket
ネストしたスタックを作る手順はpackage
→deploy
となるのですが、packageコマンドを実行するとローカルにあるテンプレートをS3にアップロードするので、これはそのS3バケット作成用です。
mbコマンド
でS3を作成してもいいですが、まぁ、これは好みですね。
package
packageコマンドのきちんとした説明は、公式を参照してください。ここでは、ざっくり説明します。
律儀にネストしたスタックを作成しようする以下のような過程が必要になります。
- ①子テンプレートをS3にアップロード
- ②アップロードされた子テンプレートのURLを確認
- ③親テンプレートに先ほど確認した子テンプレートのURLを
Properties.TemplateURL
に追加
この面倒な手順を簡単にするためにpackageコマンドのオプション
を使います。
コマンドが長くなるのでMakefile
に書きます。make package
でコマンドを実行すると子テンプレートがs3 bucket
にアップされます。ここでは、architect-bucket
ですね。
1
2
3
4
5
6
7
| # Makefile
# package
.PHONY: package
package:
@aws cloudformation package --template-file ./nested-stack/master.yml \
--s3-bucket architect-bucket \
--output-template-file ./nested-stack/package/packaged.yml
|
そして、親テンプレートであるmaster.yml
のProperties.TemplateURL
が子テンプレートのURLに書き換わったテンプレートpackaged.yml
が作成されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # master.yml
AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-1.yml ← ローカルの相対パスがS3のURLに変換される
Parameters:
Name: !Ref Name
S3Bucket2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-2.yml ← ローカルの相対パスがS3のURLに変換される
Parameters:
S3Name1: !GetAtt S3Bucket1.Outputs.OutputS3Name1
|
実際に試してないので、こんな感じになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # packaged.yml
AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
https://s3.ap-northeast-1.amazonaws.com/nested-stack/なんちゃらなんちゃら.template
Parameters:
Name: !Ref Name
S3Bucket2:
Type: AWS::CloudFormation::Stack
Properties:
https://s3.ap-northeast-1.amazonaws.com/nested-stack/なんちゃらなんちゃら.template
Parameters:
S3Name1: !GetAtt S3Bucket1.Outputs.OutputS3Name1
|
これでデプロイする準備はできました。先ほど作成されたpackaged.yml
を使ってmake deploy
を実行してみます。
deploy
コマンドが親スタック作成とネストした子スタックの作成までまるっとやってくれるので大変便利です。
1
2
3
4
5
6
7
| # Makefile
# deploy
.PHONY: deploy
deploy:
@aws cloudformation deploy \
--template-file nested-stack/package/packaged.yml \
--stack-name nested-stack \
|
親スタックの値をネストした子スタック渡す方法
親スタックの値をネストした子スタック渡す方法ですが、これも好みだとは思うのですが、僕は親スタックに直接、値をセットするのは後々違うプロジェクトでmaster.yml
自体を編集することになるので、なんかイヤなので、Makefile
に値をセットしてdeployコマンドのオプション--parameter-overrides
で値を渡すようにしています。
1
2
3
4
5
6
7
8
9
| # Makefile
Name := bokunonikki
# deploy
.PHONY: deploy
deploy:
@aws cloudformation deploy \
--template-file nested-stack/package/packaged.yml \
--stack-name nested-stack \
--parameter-overrides Name=${Name}
|
Name
の値をまず最初に親スタックに渡します。master.yml
はこのようにします。
このようにすることで、ネストされた子スタックにs3-1.yml
値を渡すことができます。
1
2
3
4
5
6
7
8
9
10
11
12
13
| # master.yml
AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-1.yml
Parameters:
Name: !Ref Name
|
s3-1.yml
は以下のようにすれば親スタックの値を受け取ることができます。この場合は、bokunonikki-1
というS3バケットが作成されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
| AWSTemplateFormatVersion: 2010-09-09
Description: nested-stack-s3-1
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub
- ${ Name }-1
- { Name: !Ref Name }
|
ネストした子スタックどうしで値を渡す
ネストした子スタックどうしで値を渡すにはOutputs関数
を使います。
ここでは、試しにAスタック
の値をBスタック
に渡す場合を考えてみます。
まず、Aスタック
の値をOutputs関数
を使ってBスタック
でも参照できるようにします。この場合は、OutputS3Name1
という名前で参照できるようになってます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| AWSTemplateFormatVersion: 2010-09-09
Description: nested-stack-s3-1
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub
- ${ Name }-1
- { Name: !Ref Name }
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Outputs:
OutputS3Name1:
Value: !Ref S3Bucket1
|
次に受け取る側のBスタック
です。値を受け取る側はまず、親であるテンプレートに!GetAtt
関数を使って参照できるようにします。この場合は、Parameters
のS3Name1
という値に、S3Bucket1のOutputsのOutputS3Name1をセットするという意味です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-1.yml
Parameters:
Name: !Ref Name
S3Bucket2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-2.yml
Parameters:
S3Name1: !GetAtt S3Bucket1.Outputs.OutputS3Name1 ← これ
|
Bスタック
自体は、特別何をする必要もありません。普通にParameters
をセットすればいいです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| AWSTemplateFormatVersion: 2010-09-09
Description: nested-stack-s3-2
Parameters:
S3Name1:
Type: String
Resources:
S3Bucket2:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub
- ${ S3Name1 }-2
- { S3Name1: !Ref S3Name1 }
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
|
以上で終わりです。これらのコマンドは実際に実行したわけではないので、コピペ実行はできないのでお気をつけあれ。
ただ、これらの大まかな知識があればあとは公式サイトを見ればだいだいできるようになるはずです。
参考になった本
Makeの本は、これ一冊あればことたりると思います。何かしたくなったら調べるくらいのレベルでも結構役に立ちます。
この本は実際にawsのサービスを実際に手を動かして作っているので、awsの概要を掴むには最適です。
Amazon Web Servicesインフラサービス活用大全
See Also