CloudFormationでForEachを利用し、パラメータに記載した複数ホストゾーンを一括作成する
初技術ブログです。拙いかもしれません。
本題だけ読みたい方はこちらからどうぞ。
CloudFormationのForEach機能
ForEach関数の概要については以下の記事が参考になるかと思います。
ForEachの具体例として、以下のymlファイルを実行すると「pesi-test-bucket」という名前のS3バケットが一つ作成されます。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: pesi-test-bucket
上記テンプレートを以下のように修正することで、「pesi-test-bucket-first」「pesi-test-bucket-second」「pesi-test-bucket-third」の三つのS3バケットが作成されます。
AWSTemplateFormatVersion: "2010-09-09"
Transform: 'AWS::LanguageExtensions'
Resources:
'Fn::ForEach::S3Loop':
- S3Names
- - first
- second
- third
- 'S3Bucket${S3Names}':
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub "pesi-test-bucket-${S3Names}"
Transform: 'AWS::LanguageExtensions'
という拡張機能の宣言をし、ForEach関数を使用しています。
実際に処理されたテンプレートは以下の通りです。
S3Names
の要素(first/second/third)の数だけループするイメージです。
リソースの論理ID(上記ではS3Bucket${S3Names}
)にそれぞれの要素名をくっつけることで複数リソースの作成を実現しています。
パラメータを使用して、入力した値によってリソースを一括作成するためには、テンプレートを以下のように修正します。
AWSTemplateFormatVersion: "2010-09-09"
Transform: 'AWS::LanguageExtensions'
Parameters:
S3NameList:
Type: CommaDelimitedList
Default: first,second,third,fourth
Description: "Enter S3 Names Separated by Commas"
Resources:
'Fn::ForEach::S3Loop':
- S3Names
- !Ref S3NameList
- 'S3Bucket${S3Names}':
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub "pesi-test-bucket-${S3Names}"
パラメータS3NameList
をDefaultに設定した内容(first/second/third/fourth)で実行すると、入力した要素の数だけリソースが作成されます。
今回は4つのS3バケットが作成されました。
ForEachでは論理IDに半角英数しか使用できない
それでは、上記を元にホストゾーンを複数作成するコードを準備します。
AWSTemplateFormatVersion: "2010-09-09"
Transform: 'AWS::LanguageExtensions'
Parameters:
DomainNameList:
Type: CommaDelimitedList
Default: pesitest.com,pesitest.net
Description: "Enter Domain Names Separated by Commas"
Resources:
'Fn::ForEach::HostzoneLoop':
- Domains
- !Ref DomainNameList
- HostedZone${Domains}:
Type: "AWS::Route53::HostedZone"
Properties:
Name: DomainNameList
パラメータDomainNameList
をDefaultに設定した内容(pesitest.com/pesitest.net)で実行すると、以下のエラーが出力されて作成に失敗します。
Transform AWS::LanguageExtensions failed with: OutputKey 'HostedZonepesitest.com' should be alphanumeric. Rollback requested by user.
これは論理ID(上記ではHostedZone${Domains}
)の値がalphanumeric、つまり英数字以外許可されていないために、ドメイン名の「.」が引っかかってエラーとなっています。
以下リンクでも同様のエラーが紹介されています。
また、以下リンクでは自分とは少し別のやり方でエラー回避する方法を紹介しています。パラメータに記載した複数ホストゾーンを一括作成
上記リンクの方法でもエラー回避はできますが、以下の方法であればもっと単純にエラー回避が可能かと思います。
以下のようにテンプレートを修正することで、ホストゾーンをForEachで複数作成することが可能です。
AWSTemplateFormatVersion: "2010-09-09"
Transform: 'AWS::LanguageExtensions'
Parameters:
DomainNameList:
Type: String
Default: pesitest.com,pesitest.net
Description: "Enter Domain Names Separated by Commas"
Resources:
'Fn::ForEach::HostzoneLoop':
- Domains
- !Split [",", !Join ["tMpDoT", !Split [".", !Ref DomainNameList]]]
- HostedZone${Domains}:
Type: "AWS::Route53::HostedZone"
Properties:
Name: !Join [".", !Split ["tMpDoT", !Ref Domains]]
主な修正点は以下の通りです。
- パラメータのタイプを
CommaDelimitedList
からString
に変更 - Join関数とSplit関数を使用し、「.」を一時的に「tMpDoT」という文字列に置き換える処理を追加
実際に処理されるテンプレートは以下の通りです。
「.」を一時的に「tMpDoT」という文字列に置き換えているため論理IDが非常に不格好ですが、テンプレートファイルの内容やパラメータの入力値はスッキリしているのではないかと思います。
また、「.」以外の文字(ハイフンやアットマーク等)の場合でも上記を参考に置き換えが可能なはずです。
一応注意点としては、入力値内に「tMpDoT」という文字列が含まれている場合、処理がうまくいかないのではないかと思われます(ドメイン名は大文字小文字を区別しないはずなので基本的にないとは思いますが)。
終わりに
業務で複数ホストゾーンをまとめて作成する必要があったため、勉強もかねてForEachを利用しました。
ForEach関数は思ったより自由度が低い気もしますが、セキュリティグループの設定でポートだけ or IPアドレスだけ変えたものを複数作成したい場合などには重宝するのかなとか考えたりしました。
また、本記事内で紹介させていただいた各先行記事には大変お世話になりました。
この記事がどなたかの参考になれば幸いです。
Discussion