追記 (2018/06/09)
初めて VPC 内に Amazon Elasticsearch Service クラスタを作成する際, AWSServiceRoleForAmazonElasticsearchService
という IAM ロールを作成する必要があります. この IAM ロールを CloudFormation で作成する方法を見つけることが出来ませんでした.
ということで, 一度, 手動で VPC 内に Amazon Elasticsearch Service クラスタを作っておくことを今のところはおすすめ致します... 手動で作っておくことで, AWSServiceRoleForAmazonElasticsearchService
が作成されます.
尚, ポリシーについては, AmazonElasticsearchServiceRolePolicy
というポリシーが付与され, ポリシーのドキュメントは以下のような内容となります.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1480452973134", "Action": [ "ec2:CreateNetworkInterface", "ec2:DeleteNetworkInterface", "ec2:DescribeNetworkInterfaces", "ec2:ModifyNetworkInterfaceAttribute", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeVpcs" ], "Effect": "Allow", "Resource": "*" } ] }
どうも
#ただそれだけ
の CloudFormation 初心者, 川原です.
タイトルの通り, Amazon Elasticsearch Service クラスタを VPC 内にサクっと作成する CloudFormation テンプレートを作成しました. 作成したテンプレートは, 以下のリポジトリにアップしています.
以上
簡単ですが, 共有させて頂きます...で終わるのも寂しいので, CloudFormation 職人の皆さんから見ると, 「なんだ今更」と言われてしまうかもしれませんが, 作成にあたって学んだことなどをメモしていきます.
パラメータのタイプ
CloudFormation テンプレート内にParameters で指定する値のタイプについて.
文字列や数値, 配列等の各種タイプについて, 以下のようなタイプがあります. (上記のドキュメントより引用, 抜粋させていただきました.)
タイプ | 内容 | parameters セクションで指定するサンプル |
---|---|---|
String | リテラル文字列 | "FooBarBaz" |
Number | 整数又は浮動小数点 | "12345678" |
List | カンマで区切られた, 整数又は浮動小数点 | "123, 456" |
CommaDelimitedList | カンマで区切られたリテラル文字列 | "foo, bar, baz" |
AWS 固有のパラメーター型 | EC2 キーペア名, VPC ID 等の AWS の値 | AWS::EC2::Image::Id |
SSM パラメータータイプ | Systems Manager パラメーターストア内の既存のパラメーターに対応するパラメーター | AWS::SSM::Parameter::Name |
これらのパラメータを指定する際に個人的に注意したのが, Number タイプを指定する際に値を指定する場合.
{ "ParameterKey": "EsInstanceCount", "ParameterValue": 1 },
数値なので, 1
と書いてしまうと, 以下のようなエラーとなってしまいます.
$ bundle exec rake es:create:demo ./deploy.sh ${AWS_PROFILE} ${STACK_NAME_PREFIX} demo create Parameter validation failed: Invalid type for parameter Parameters[3].ParameterValue, value: 1, type: <type 'int'>, valid types: <type 'basestring'>
パラメータで指定する場合には数値であっても ""
で括って文字列として指定する必要があります. ドキュメントにも以下のように記述されています.
整数または浮動小数点値。AWS CloudFormation は、この型のパラメーターを数値として検証しますが、テンプレート内の他の場所で使用した場合には (Ref 組み込み関数を使用した場合など) 文字列として扱います。
ということで, 以下のように書く必要があります.
{ "ParameterKey": "EsInstanceCount", "ParameterValue": "1" },
うむ.
「文字列値のリスト」タイプをパラメータとして付与したい場合
テンプレートの VPCOptions.SecurityGroupIds
や VPCOptions.SubnetIds
に指定する値のタイプは, 「文字列値のリスト」で定義する必要があります.
Parameters: ... EsSubnetIds: Type: CommaDelimitedList Resources: ElasticsearchDomain: Type: AWS::Elasticsearch::Domain ... VPCOptions: SubnetIds: !Ref EsSubnetIds ...
「文字列値のリスト」を分かりやすく YAML で書くと以下のような感じになると思います.
foo: - bar - baz
foo
の要素である bar
や baz
をパラメータでどのように渡すかという話になりますが, 結論から言うと, CommaDelimitedList
タイプを利用して書きました. CommaDelimitedList
タイプは先述の通り, パラメータにおいては「カンマで区切られた文字列」を指定します. これを !Ref で展開すると, ["foo", "bar"]
という配列として解釈されます.
これを CloudFormation テンプレートに落とし込むと以下のようになると思います.
Parameters: FooBarBaz: Default: "bar, baz" Type: CommaDelimitedList Resources: foo: !Ref FooBarBaz
また, JSON のテンプレートは以下のようになると思います.
{ "ParameterKey": "FooBarBaz", "ParameterValue": "bar, baz" }
フムフム.
テンプレートのチェックはあくまでもテンプレートのみのチェック
テンプレートを検証する為に, AWS CLI では validate-template
というサブコマンドが用意されています.
aws --region=${_AWS_REGION} cloudformation validate-template --template-body file://template.yml
自分のようなうっかり者には, このサブコマンドは非常にありがたいのですが, 検証の対象はあくまでもテンプレートのみが対象となっています. 例えば, 先述の Number パラメータを数値で定義したようなパラメータに異常な値があったとしても, validate-template コマンドは検証成功を返します.
$ aws cloudformation validate-template --template-body file://template.yml; echo $? { "Parameters": [ { "NoEcho": false, "ParameterKey": "EsZoneAwareness" }, { "NoEcho": false, "ParameterKey": "EsSubnetIds" }, { "NoEcho": false, "ParameterKey": "EsDomainEnvironment" }, { "NoEcho": false, "ParameterKey": "EsSecurityId" }, { "NoEcho": false, "ParameterKey": "EsDomainNamePrefix" }, { "NoEcho": false, "ParameterKey": "EsInstanceType" }, { "NoEcho": false, "ParameterKey": "EsInstanceCount" }, { "NoEcho": false, "ParameterKey": "EsVersion" }, { "NoEcho": false, "ParameterKey": "EsStorageVolumeSize" } ] } 0
パラメータを含めた状態で検証して頂けると嬉しいかぎりですが, とりあえずはこんなものだと思って利用したいと思います.
テンプレートの汎用化
異なる環境に対して, 同じような構成でクラスタを構築するにあたって, テンプレートを環境毎に用意して良いのは小学生までという自負はあるものの, どのようにすれば良いのか試行錯誤しました. AWS CLI を利用する場合, スタックの作成や, スタックの更新の際にパラメータをコマンドラインオプションや JSON ファイルで渡すことができるので, 以下のように, 環境毎のパラメータ情報を持った JSON ファイルを用意することにしました.
[ { "ParameterKey": "EsDomainEnvironment", "ParameterValue": "demo" }, { "ParameterKey": "EsDomainNamePrefix", "ParameterValue": "oreno-elasticsearch" }, { "ParameterKey": "EsInstanceType", "ParameterValue": "t2.small.elasticsearch" }, { "ParameterKey": "EsInstanceCount", "ParameterValue": "1" }, { "ParameterKey": "EsVersion", "ParameterValue": "6.2" }, { "ParameterKey": "EsZoneAwareness", "ParameterValue": "false" }, { "ParameterKey": "EsStorageVolumeSize", "ParameterValue": "10" }, { "ParameterKey": "EsSecurityId", "ParameterValue": "sg-xxxxxxxx" }, { "ParameterKey": "EsSubnetIds", "ParameterValue": "subnet-xxxxxxx1, subnet-xxxxxxx2" } ]
上記のようなパラメータを記載した JSON ファイルを例えば demo.json というファイル名で保存して, create-stack や update-stack の際に, 以下のように --parameters
オプションの引数に渡して利用します.
aws --profile=${_AWS_PROFILE} --region=${_AWS_REGION} \ cloudformation create-stack \ --stack-name ${_ENV}-${_STACK_NAME_PREFIX} \ --parameters file://parameters/demo.json \ --template-body file://template.yml \ --capabilities CAPABILITY_IAM
wait コマンドを利用する
AWS CLI の wait コマンド, とても便利だと思います. 例えば, 以下のように EC2 を起動する run-instances した後に利用すると, EC2 のステータス (instance status) が OK
になるまで待機してくれるので, 正常に起動することを確認する為の処理を自前で実装する必要が無いという利点があります.
# EC2 を起動 (※このコードはサンプルです) aws ec2 run-instances --instance-ids i-xxxxxxxxxxxxx # 起動させた EC2 のインスタンスステータスが OK になるまで待機 (※このコードはサンプルです) aws ec2 wait instance-status-ok --instance-ids i-xxxxxxxxxxxxx
cloudformation でも wait コマンドが用意されていて, 以下のようなコマンドをサポートしています.
- change-set-create-complete
- stack-create-complete
- stack-delete-complete
- stack-exists
- stack-update-complete
例えば, stack-create-complete
コマンドの場合, スタックのステータスが CREATE_COMPLETE
になるまで待機してくれるので, スタックが正常に作成されたかをわざわざチェックするような実装が不要となります. ただし, Amazon Elasticsearch Service クラスタを作成する場合, EC2 等を作成するスタックと比べると待機時間が長く, 一瞬, 通信が切れてしまったのかなと思うほどでした.
終わり
以上, メモでした.
素敵な CloudFormation と Elasticsearch 生活をお送りください.