めもめも

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

RDO(Havana)でHeatを試す

RDO(Havana)でHeatを試してみる手順です。ネットワーク構成は、下記のオールインワン構成と同じです。

最短手順でRDO(Grizzly)のデモ環境を構築

ただし、今回は、Fedora19を「最小限のインストール」+ 「標準アドオン」でインストールします。インストールしたら次のコマンドで事前準備します。

# setenforce 0
# sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config
# yum -y update
# yum -y install iptables-services
# systemctl stop firewalld.service
# systemctl mask firewalld.service
# systemctl start iptables.service
# systemctl enable iptables.service
# yum -y install mariadb-server
# rm -f /usr/lib/systemd/system/mariadb.service
# cp /usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system/mariadb.service

続いて、PackstackでRDO(Havana)をインストールします。Answer FileでHeatのインストールを指示しています。

# yum -y install http://repos.fedorapeople.org/repos/openstack/openstack-havana/rdo-release-havana-8.noarch.rpm
# yum -y install openstack-packstack
# packstack --gen-answer-file=answers.txt
# sed -i 's/CONFIG_PROVISION_DEMO=.*/CONFIG_PROVISION_DEMO=n/' answers.txt
# sed -i 's/CONFIG_SWIFT_INSTALL=.*/CONFIG_SWIFT_INSTALL=n/' answers.txt
# sed -i 's/CONFIG_NAGIOS_INSTALL=.*/CONFIG_NAGIOS_INSTALL=n/' answers.txt
# sed -i 's/CONFIG_HEAT_INSTALL=.*/CONFIG_HEAT_INSTALL=y/' answers.txt
# sed -i 's/CONFIG_HEAT_CLOUDWATCH_INSTALL=.*/CONFIG_HEAT_CLOUDWATCH_INSTALL=y/' answers.txt
# sed -i 's/CONFIG_HEAT_CFN_INSTALL=.*/CONFIG_HEAT_CFN_INSTALL=y/' answers.txt
# packstack --answer-file=answers.txt
# openstack-config --set --existing /etc/heat/heat.conf ec2authtoken auth_uri http://127.0.0.1:5000/v2.0
# . ~/keystonerc_admin
# heat-manage db_sync

最後のdb_syncは「SADeprecationWarning」が出ても無視してください。インストールが終わったら、「/etc/sysconfig/iptables」のセクション「:nova-filter-top - [0:0]」の頭に下記の項目を追加しておきます。

-A INPUT -p tcp -m tcp --dport 8000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 8003 -j ACCEPT

ここで、一回、サーバを再起動します。サーバが起動したら、テナントを作成するために次のスクリプトを用意します。

config.sh

#!/bin/sh -e

####
public="192.168.199.0/24"
gateway="192.168.199.1"
nameserver="8.8.8.8"
pool=("192.168.199.100" "192.168.199.199")
private=("192.168.101.0/24")
####

export LANG=en_US.utf8

function config_tenant {
    . /root/keystonerc_admin

    #
    # Upload glance image
    #
    if ! glance image-show "Fedora19" >/dev/null 2>&1; then
        glance image-create --name "Fedora19" \
            --disk-format qcow2 --container-format bare --is-public true \
            --copy-from http://cloud.fedoraproject.org/fedora-19.x86_64.qcow2
    fi

    if ! glance image-show "F17-x86_64-cfntools" >/dev/null 2>&1; then
        glance image-create --name F17-x86_64-cfntools \
            --disk-format qcow2 --container-format bare --is-public true \
            --copy-from http://fedorapeople.org/groups/heat/prebuilt-jeos-images/F17-x86_64-cfntools.qcow2
    fi
    #
    # create project and users
    #
    keystone user-get demo_admin && keystone user-delete demo_admin
    keystone user-get demo_user && keystone user-delete demo_user
    keystone tenant-get demo && keystone tenant-delete demo

    keystone tenant-create --name demo
    keystone user-create --name demo_admin --pass passw0rd
    keystone user-create --name demo_user --pass passw0rd
    keystone user-role-add --user demo_admin --role admin --tenant demo
    keystone user-role-add --user demo_user --role _member_ --tenant demo

    #
    # initialize neutron db
    #
    neutron_services=$(systemctl list-unit-files --type=service \
        | grep -E 'neutron\S+\s+enabled' | cut -d" " -f1)

    for s in ${neutron_services}; do systemctl stop $s; done
    mysqladmin -f drop ovs_neutron
    mysqladmin create ovs_neutron
    neutron-netns-cleanup
    for s in $neutron_services; do systemctl start $s; done
    sleep 5

    #
    # create external network
    #
    tenant=$(keystone tenant-list | awk '/ services / {print $2}')
    neutron net-create \
        --tenant-id $tenant ext-network --shared \
        --provider:network_type local --router:external=True
    neutron subnet-create \
        --tenant-id $tenant --gateway ${gateway} --disable-dhcp \
        --allocation-pool start=${pool[0]},end=${pool[1]} \
        ext-network ${public}

    #
    # create router
    #
    tenant=$(keystone tenant-list|awk '/ demo / {print $2}')
    neutron router-create --tenant-id $tenant demo_router
    neutron router-gateway-set demo_router ext-network

    #
    # create private networks
    #
    for (( i = 0; i < ${#private[@]}; ++i )); do
        name=$(printf "private%02d" $(( i + 1 )))
        subnet=${private[i]}
        neutron net-create \
            --tenant-id $tenant ${name} --provider:network_type local
        neutron subnet-create \
            --tenant-id $tenant --name ${name}-subnet \
            --dns-nameserver ${nameserver} ${name} ${subnet}
        neutron router-interface-add demo_router ${name}-subnet
    done

    #
    # configure security components
    #
    . /root/keystonerc_admin
    export OS_USERNAME=demo_admin
    export OS_PASSWORD=passw0rd
    export OS_TENANT_NAME=demo
    nova secgroup-add-rule default tcp 22 22 0.0.0.0/0
    nova secgroup-add-rule default tcp 80 80 0.0.0.0/0
    nova secgroup-add-rule default icmp 8 0 0.0.0.0/0
    if nova keypair-list | grep -q '^| mykey |'; then
        nova keypair-delete mykey
    fi
    nova keypair-add mykey > ~/mykey.pem
    chmod 600 ~/mykey.pem
    for i in $(seq 1 5); do
        neutron floatingip-create ext-network
    done
}

# main

extnic=""
while [[ -z $extnic ]]; do
    echo -n "VM access NIC: "
    read extnic
done

if ! ovs-vsctl list-ports br-ex | grep -q ${extnic}; then
    ovs-vsctl add-port br-ex ${extnic}
fi

config_tenant 2>/dev/null

echo
echo "Configuration finished."

これを実行すると「VM access NIC:」と表示されるので、VMアクセス用のNIC(この絵で言うところの「em2」)を入力します。

この後は、ユーザ「demo_admin」用のkeystonercファイルを用意して、このユーザからHeatを利用します。

keystonerc_demo_admin

export OS_USERNAME=demo_admin
export OS_TENANT_NAME=demo
export OS_PASSWORD=passw0rd
export OS_AUTH_URL=http://192.168.199.10:35357/v2.0/
export PS1='[\u@\h \W(keystone_demo_admin)]\$ '

デモ用のテンプレートファイルを用意します。PostgreSQLサーバを構築した後、RoRの伝言板アプリのサーバを構築して、DB接続設定するというシナリオです。PostgreSQLサーバの構築は、GitHubからPuppetマニフェストを取得して適用することで行います。RoRの方は、シェルスクリプトで頑張っています。

dengonban.template

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "A Database instance running a local PostgreSQL server",
  "Parameters" : {
    "GitRepo" : {
      "Description" : "Git Repository URL",
      "Type" : "String",
      "Default" : "https://github.com/enakai00/pgsql_puppet"
    },
    "GitTag" : {
      "Description" : "Git Tag",
      "Type" : "String",
      "Default" : "heat-demo1.0"
    },
    "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": {
        "SubnetId"       : "013cd465-7e75-4edc-ae83-6476fcf9178b",
        "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": {
        "SubnetId"       : "013cd465-7e75-4edc-ae83-6476fcf9178b",
        "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",
          "yum install -y rubygem-rails rubygem-pg postgresql\n",
          "echo '*:*:*:postgres:pas4pgsql' > /root/.pgpass && chmod 600 /root/.pgpass\n",
          "psql -h $DB_IP -U postgres -c \"create user rails encrypted password 'pas4rails'\"\n",
          "psql -h $DB_IP -U postgres -c \"create database dengonban_development owner rails\"\n",
          "psql -h $DB_IP -U postgres -c \"create database dengonban_production owner rails\"\n",
          "mkdir /root/rails && cd /root/rails\n",
          "rails new dengonban -d postgresql\n",
          "sed -i \"s/  username:.*/  username: rails/\" /root/rails/dengonban/config/database.yml\n",
          "sed -i \"s/  password:.*/  password: pas4rails\\n  host: $DB_IP/\" /root/rails/dengonban/config/database.yml\n",
          "cd /root/rails/dengonban\n",
          "rails generate scaffold Messages name:string content:text date:datetime\n",
          "rake db:migrate RAILS_ENV=\"development\"\n",
          "rake db:migrate RAILS_ENV=\"production\"\n",
          "sed -i \"s/    # config.time_zone =.*/    config.time_zone = 'Tokyo'/\" /root/rails/dengonban/config/application.rb\n",
          "rails s -e production -p 80 -d\n"
        ]]}}
      }
    },

    "WebServerIPAssoc" : {
      "Type" : "AWS::EC2::EIPAssociation",
      "Properties" : {
        "InstanceId" : { "Ref" : "WebServer" },
        "EIP" : "192.168.199.105"
      }
    }
  }
}

2箇所の"SubnetId"は、下記のコマンドで表示されるIDに書き換えておいてください。

# neutron subnet-list | grep private01 | cut -d"|" -f2
 013cd465-7e75-4edc-ae83-6476fcf9178b 

そして、おもむろにテンプレートからスタックを構築します。

# . keystonerc_demo_admin 
# heat stack-create -f dengonban.template -P "KeyName=mykey" dengonban
+--------------------------------------+------------+--------------------+----------------------+
| id                                   | stack_name | stack_status       | creation_time        |
+--------------------------------------+------------+--------------------+----------------------+
| 642c1678-8966-461c-bbfe-c75c17b75e95 | dengonban  | CREATE_IN_PROGRESS | 2014-02-06T07:01:16Z |
+--------------------------------------+------------+--------------------+----------------------+

この後は、/var/log/heat/engine.logを眺めながら構築が終わるのを待ちます。構築が終わるとこんな感じになります。

# heat stack-list
+--------------------------------------+------------+-----------------+----------------------+
| id                                   | stack_name | stack_status    | creation_time        |
+--------------------------------------+------------+-----------------+----------------------+
| 642c1678-8966-461c-bbfe-c75c17b75e95 | dengonban  | CREATE_COMPLETE | 2014-02-06T07:01:16Z |
+--------------------------------------+------------+-----------------+----------------------+

# nova list
+--------------------------------------+--------------------------------------------+--------+------------+-------------+------------------------------------------+
| ID                                   | Name                                       | Status | Task State | Power State | Networks                                 |
+--------------------------------------+--------------------------------------------+--------+------------+-------------+------------------------------------------+
| c7b48220-ea3c-4053-b699-d3bed8cde657 | dengonban-PgSQLDatabaseServer-wptgqlxdmbt6 | ACTIVE | None       | Running     | private01=192.168.101.3                  |
| 5896b645-a398-4827-9d76-306f7ec9c418 | dengonban-WebServer-s3n5y4wshlq2           | ACTIVE | None       | Running     | private01=192.168.101.4, 192.168.199.105 |
+--------------------------------------+--------------------------------------------+--------+------------+-------------+------------------------------------------+

RoRのサンプルによくある伝言板アプリが動いていることが分かります。

実用性はよく分かりませんが、Havanaでは、Horizonダッシュボードからもスタックの状態が確認できて、こんなポンチ絵も表示できます。