前回、次のような流れを自動化するという話をしました。
(1) 上記のカスタマイズスクリプトを渡してDBサーバーを起動する。
(2) DBサーバー内のゲストOSで、DBのセットアップが終わるのを待つ。
(3) DBサーバーに割り当てられたIPを取得する。
(4) Webサーバー構築用のカスタマイズスクリプトに、(3)で取得したIPを埋め込む。
(5) (4)で用意したカスタマイズスクリプトを渡してWebサーバーを起動する。
が、記事の中では、実質的には、(1)〜(2)しかやってませんでした。
あらためて、(1)〜(5)を実現するテンプレートを紹介しておきます。
これです。
{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "A Database instance running a local PostgreSQL server", "Parameters" : { "GitRepo" : { "Description" : "Git Repository URL", "Type" : "String" }, "GitTag" : { "Description" : "Git Tag", "Type" : "String" }, "KeyName" : { "Description" : "KeyPair to enable SSH access", "Type" : "String" }, "InstanceType" : { "Description" : "Instance type", "Type" : "String", "AllowedValues" : [ "m1.tiny", "m1.small", "m1.medium", "m1.large", "m1.xlarge" ], "ConstraintDescription" : "must be a valid instance type.", "Default" : "m1.small" }, "ImageName" : { "Description" : "Image name of instance", "Type" : "String", "Default" : "F17-x86_64-cfntools" } }, "Resources" : { "PgSQLDatabaseServer": { "Type": "AWS::EC2::Instance", "Properties": { "ImageId" : { "Ref" : "ImageName" }, "InstanceType" : { "Ref" : "InstanceType" }, "KeyName" : { "Ref" : "KeyName" }, "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash -x\n", "GitRepository=", { "Ref" : "GitRepo" }, "\n", "ConfigTag=", { "Ref" : "GitTag" }, "\n", "yum -y install puppet git\n", "RepoName=${GitRepository##*/}\n", "RepoName=${RepoName%.git}\n", "mkdir -p /tmp/gittmp\n", "cd /tmp/gittmp\n", "git clone $GitRepository\n", "cd $RepoName\n", "git checkout $ConfigTag\n", "export FACTER_manifest_dir=\"/tmp/gittmp/$RepoName\"\n", "puppet apply main.pp\n", "# All is well so signal success\n", "/opt/aws/bin/cfn-signal -e 0 -r \"PostgreSQL Database setup complete\" '", { "Ref" : "PgSQLWaitHandle" }, "'\n" ]]}} } }, "PgSQLWaitHandle" : { "Type" : "AWS::CloudFormation::WaitConditionHandle" }, "PgSQLWaitCondition" : { "Type" : "AWS::CloudFormation::WaitCondition", "DependsOn" : "PgSQLDatabaseServer", "Properties" : { "Handle" : {"Ref" : "PgSQLWaitHandle"}, "Timeout" : "6000" } }, "WebServer": { "Type": "AWS::EC2::Instance", "DependsOn": "PgSQLWaitCondition", "Properties": { "ImageId" : { "Ref" : "ImageName" }, "InstanceType" : { "Ref" : "InstanceType" }, "KeyName" : { "Ref" : "KeyName" }, "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash -x\n", "export DB_IP=", { "Fn::GetAtt" : [ "PgSQLDatabaseServer", "PublicIp" ] }, "\n", "echo \"PostgreSQL Server IP: $DB_IP\" >>/etc/motd\n" ]]}} } } } }
いろいろ余計な要素をそぎ落として、できるだけシンプルにしました。
"WebServer": { "Type": "AWS::EC2::Instance", "DependsOn": "PgSQLWaitCondition",
という部分で、DBサーバーの起動が完了してから、Webサーバーを起動するように指示しています。正確に言うと、DBサーバーの起動後、まず、"PgSQLWaitCondition"が、ゲストOSからのシグナルを待ち続けます。"WebServer"は、"PgSQLWaitCondition"に依存しているので、シグナルを受けて"PgSQLWaitCondition"が終了した後に、"WebServer"の構築がスタートするという寸法です。
Webサーバーと言いながら、カスタマイズ・スクリプトの中身はこれだけですが。
"#!/bin/bash -x\n", "export DB_IP=", { "Fn::GetAtt" : [ "PgSQLDatabaseServer", "PublicIp" ] }, "\n", "echo \"PostgreSQL Server IP: $DB_IP\" >>/etc/motd\n"
要するに、「{ "Fn::GetAtt" : [ "PgSQLDatabaseServer", "PublicIp" ] }」によって、DBサーバーのIPを取得できる事を示しています。Heat EngineがWebサーバー用の仮想マシンインスタンスを起動する際に、この部分をIPアドレスに置換してから、カスタマイズ・スクリプトとして、ゲストOSに送り込みます。実際にゲストOS内で確認すると、次のようになっています。
# cat /var/lib/heat-cfntools/cfn-userdata #!/bin/bash -x export DB_IP=192.168.101.3 echo "PostgreSQL Server IP: $DB_IP" >>/etc/motd
まさに、(1)〜(5)をPythonスクリプトでごりごり書いたらこういう動きになるだろうなぁ、的な動きがテンプレートによって実現している事が分かります。