めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

OpenStack HeatがCloud-Init / cfntoolsと連携する様子を覗きこむ(その2)

前回、次のような流れを自動化するという話をしました。

(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スクリプトでごりごり書いたらこういう動きになるだろうなぁ、的な動きがテンプレートによって実現している事が分かります。