はじめに
前回から間があきましたが、いよいよ複数インスタンスの起動/連携にチャレンジしてみます。例として、前回の最後にデモを紹介したGlusterFSクラスタを構築します。
具体的な手順としては、1つのアプリケーション・ブループリントに複数インスタンスの構成情報を記述すればOKです。ただし、前回のようにアプリケーションの導入手順をスクリプトでベタ書きするのは、あまりスマートではありません。そこで、今回は、「アプリケーション環境構築の自動化をまじめに考えてみる(3)」で編み出した、Puppetによるアプリケーション導入・設定を併用することにします。
つまり、GlusterFSの導入・初期設定を実施するPuppetマニフェストをGithubに上げておき、アプリケーション・ブループリントには、これをダウンロードして適用するテンプレート処理を記載しておきます。ただし、Puppetでは個々のインスタンスの構成しかできませんので、Puppetにより個々のインスタンスでglusterdの起動が完了した後に、GlusterFSのクラスタを構成して、ボリュームを作成する処理を別途、アプリケーション・ブループリントに仕込みます。
Puppetマニフェストの準備
実際に作成したマニフェストはここにあります。ファイルの構成は下記の通りで、dist以下には、iptablesとI/Oチューニングの設定ファイルが入っています。
$ tree gluster_puppet/ gluster_puppet/ |-- dist | |-- iptables | `-- rc.gluster `-- main.pp
折角なので、マニフェストの中身も晒しておきます。
class glusterfs { exec { 'mkfs_data': path => '/sbin', command => "mkfs.ext4 -I 512 -E lazy_itable_init=1 $data_device", unless => "tune2fs -l $data_device", logoutput => true, before => Mount['data_dir'], } file { '/data': owner => 'root', group => 'root', mode => '0755', ensure => directory, before => Mount['data_dir'], } mount { 'data_dir': name => '/data', options => 'defaults', device => $data_device, fstype => 'ext4', ensure => 'mounted', } file { '/etc/sysconfig/iptables': owner => 'root', group => 'root', mode => '0600', source => "$manifest_dir/dist/iptables", notify => Service['iptables'], } service { 'iptables': name => 'iptables', ensure => 'running', enable => true, hasstatus => true, } yumrepo { 'glusterfs_repo': name => 'glusterfs', descr => 'Repository for GlusterFS 3.3', baseurl => 'http://download.gluster.org/pub/gluster/glusterfs/3.3/LATEST/EPEL.repo/epel-6Server/x86_64/', enabled => '1', gpgcheck => '0', before => Package['glusterfs_server'], } service { 'glusterd': name => 'glusterd', ensure => 'running', enable => true, hasstatus => true, subscribe => Package['glusterfs_server'], } $server_packages = [ 'glusterfs-server', 'glusterfs-geo-replication', 'glusterfs-fuse' ] package { 'glusterfs_server': name => $server_packages, ensure => installed, } file { '/etc/rc.gluster': owner => 'root', group => 'root', mode => '0755', source => "$manifest_dir/dist/rc.gluster", notify => Exec['rc_gluster'], } exec { 'rc_gluster': path => [ '/sbin', '/bin', '/usr/bin' ], command => 'echo "/etc/rc.gluster" >> /etc/rc.local; /etc/rc.local', unless => 'grep "/etc/rc.gluster" /etc/rc.local', logoutput => true, refreshonly => true, } } include 'glusterfs'
$data_deviceで指定されるデバイスをフォーマットして/dataにマウントした後に、GlusterFSのRPMをインストールして、glusterdを起動する処理を行います。$data_deviceは、環境変数$FACTER_data_device経由で与えます。
アプリケーション・ブループリントの中から次のスクリプトを実行すると、Githubからマニフェストをダウンロードして適用することができます。
# Setting up glusterfs using Puppet yum -y install http://mirror.us.leaseweb.net/epel/6/i386/epel-release-6-7.noarch.rpm yum -y install git yum -y install puppet mkdir -p /tmp/gittmp cd /tmp/gittmp git clone https://github.com/enakai00/gluster_puppet.git cd gluster_puppet git checkout $AUDREY_VAR_glusterd_gittag export FACTER_manifest_dir="/tmp/gittmp/gluster_puppet" export FACTER_data_device="/dev/xvdj" puppet main.pp
「$AUDREY_VAR_glusterd_gittag」には、Gitの適用するタグを指定します。これにより、複数バージョンの設定ファイルから、希望のバージョンを適用することが可能になります。
アプリケーション・ブループリントの作成
まずは、前回記事の「自動設定機能のテスト」の冒頭部分の手順に従います。イメージ「RHEL6.3 with audrey-agent」に対して、「イメージから展開可能な新規アプリを作成」を押して、新しいアプリケーション「GlusterFS 2nodes cluster」を「EC2 Test Catalogue」に作成します。その後、「XMLの編集」を押して、XML(アプリケーション・ブループリント)の編集画面に移ります。
そして、おもむろに下記の内容を書き込みます。
<?xml version="1.0"?> <deployable version="1.0" name="GlusterFS 2nodes cluster with Puppet"> <description/> <assemblies> <assembly name="node01" hwp="small-x86_64"> <image id="c0d6f20f-6e7a-4835-b41e-7b16a8cdbe35"/> <services> <service name="glusterd"> <executable> <contents><![CDATA[#!/bin/bash -x { # Setting up glusterfs using Puppet yum -y install http://mirror.us.leaseweb.net/epel/6/i386/epel-release-6-7.noarch.rpm yum -y install git yum -y install puppet mkdir -p /tmp/gittmp cd /tmp/gittmp git clone https://github.com/enakai00/gluster_puppet.git cd gluster_puppet git checkout $AUDREY_VAR_glusterd_gittag export FACTER_manifest_dir="/tmp/gittmp/gluster_puppet" export FACTER_data_device="/dev/xvdj" puppet main.pp # Create volume sleep 1 gluster peer probe $AUDREY_VAR_glusterd_node02_host gluster vol create vol01 \ $HOSTNAME:/data/brick01 \ $AUDREY_VAR_glusterd_node02_host:/data/brick01 gluster vol start vol01 } 2>&1 | logger -t "audrey_volume" ]]> </contents> </executable> <parameters> <parameter name="gittag"> <value>ec2-v1_0</value> </parameter> <parameter name="node02_host"> <reference assembly="node02" parameter="hostname"/> </parameter> <parameter name="node02_up"> <reference assembly="node02" parameter="glusterup"/> </parameter> </parameters> </service> </services> </assembly> <assembly name="node02" hwp="small-x86_64"> <image id="c0d6f20f-6e7a-4835-b41e-7b16a8cdbe35"/> <services> <service name="glusterd"> <executable> <contents><![CDATA[#!/bin/bash -x { # Setting up glusterfs using Puppet yum -y install http://mirror.us.leaseweb.net/epel/6/i386/epel-release-6-7.noarch.rpm yum -y install git yum -y install puppet mkdir -p /tmp/gittmp cd /tmp/gittmp git clone https://github.com/enakai00/gluster_puppet.git cd gluster_puppet git checkout $AUDREY_VAR_glusterd_gittag export FACTER_manifest_dir="/tmp/gittmp/gluster_puppet" export FACTER_data_device="/dev/xvdj" puppet main.pp # Notifying this node is up cat <<EOF >/usr/lib/ruby/site_ruby/1.8/facter/glusterup.rb Facter.add(:glusterup) do setcode do true end end EOF } 2>&1 | logger -t "audrey_glusterd" ]]> </contents> </executable> <parameters> <parameter name="gittag"> <value>ec2-v1_0</value> </parameter> </parameters> </service> </services> <returns> <return name="hostname"/> <return name="glusterup"/> </returns> </assembly> </assemblies> </deployable>
なかなか複雑ですが、ポイントをしぼって解説します。まず、大きくは、次の2つの「assembly」があります。これにより、このアプリケーション・ブループリントからインスタンスが2個起動します。「image id」は環境によって変わるので注意してください。デフォルトで用意されたXMLに記載されていた値を使用します。
<assembly name="node01" hwp="small-x86_64"> <image id="c0d6f20f-6e7a-4835-b41e-7b16a8cdbe35"/> ・・・ <assembly name="node02" hwp="small-x86_64"> <image id="c0d6f20f-6e7a-4835-b41e-7b16a8cdbe35"/> ・・・
次に、node02の「executable」タグに記載されたスクリプトを見てみます。前半は先に示した、PuppetでGlusterFSを構成する部分です。その後に続く下記の処理に注目します。
# Notifying this node is up cat <<EOF >/usr/lib/ruby/site_ruby/1.8/facter/glusterup.rb Facter.add(:glusterup) do setcode do true end end EOF
これは、実は、node02の構成が完了したことをnode01に通知するためのトリックです。各ノードは、Rubyのfacterモジュールで取得可能な情報をConfigServerに通知しますが、これが実行されると、新しく「glusterup」というパラメータが用意されて通知されるようになります。この後で説明するように、node01では、node02のこのパラメータをConfigServerから取得した後に設定を開始するように仕込んであります。したがって、node02の構成が完了したタイミングで、glusterupパラメータが取得できて、ようやくnode01の設定処理が開始します。
具体的には、node01のassemblyタグの下にある下記の部分で、node02のパラメータを取得しています。
<parameter name="node02_host"> <reference assembly="node02" parameter="hostname"/> </parameter> <parameter name="node02_up"> <reference assembly="node02" parameter="glusterup"/> </parameter>
ここでは、node02のhostnameも合わせて取得しています。これは、「$AUDREY_VAR_glusterd_node02_host」という変数で参照できるようになります。
そして、node01の「executable」タグに記載されたスクリプトを見ると、Puppetで構成する処理の後に、glusterコマンドで、クラスタの構成とボリュームの作成処理を行なっていることが分かります。先のトリックがあるので、node01の設定処理が走る時は、node02の構成は完了しているので、クラスタの構成処理に安心して進むことができます。
最後に、それぞれのノードに下記のパラメータ指定があります。
<parameter name="gittag"> <value>ec2-v1_0</value> </parameter>
これは、Aeolusからアプリケーションを展開する際にユーザが指定するパラメータで、使用する設定のGitのタグを指定しています。次の画面で、任意のタグを指定できるようになります。
アプリケーションを展開してみる
以上の設定を元に、実際にアプリケーションを展開します。無事に展開に成功したところで、node01のAudreyのログを見ると次のようになっています。
[root@ip-10-150-125-231 ~]# cat /var/log/audrey.log 2012-10-21 02:57:34,935 - INFO : audrey:1351 Invoked audrey_script_main 2012-10-21 02:57:35,638 - INFO : audrey:1380 <Instance of: CSClient Version: 1 Config Server Endpoint: https://ec2-175-41-218-247.ap-northeast-1.compute.amazonaws.com Config Server oAuth Key: xxxxxxxxxx Config Server oAuth Secret: xxxxxxxxxxx Config Server Params: Config Server Configs: Temporary Directory: Tarball Name: eot> 2012-10-21 02:57:35,641 - INFO : audrey:952 Invoked CSClient.get_cs_tooling() 2012-10-21 02:57:36,070 - INFO : audrey:684 Invoked unpack_tooling() 2012-10-21 02:57:36,077 - INFO : audrey:909 Invoked CSClient.get_cs_configs() 2012-10-21 02:57:36,105 - INFO : audrey:1415 No configuration parameters provided. status: 202 2012-10-21 02:57:36,105 - INFO : audrey:924 Invoked CSClient.get_cs_params() 2012-10-21 02:57:36,132 - INFO : audrey:522 Invoked generate_provides() 2012-10-21 02:57:39,763 - INFO : audrey:939 Invoked CSClient.put_cs_params_values() 2012-10-21 02:57:49,806 - INFO : audrey:909 Invoked CSClient.get_cs_configs() 2012-10-21 02:57:49,836 - INFO : audrey:1415 No configuration parameters provided. status: 202 (中略) 2012-10-21 03:00:00,373 - INFO : audrey:909 Invoked CSClient.get_cs_configs() 2012-10-21 03:00:00,403 - INFO : audrey:1415 No configuration parameters provided. status: 202 2012-10-21 03:00:10,413 - INFO : audrey:909 Invoked CSClient.get_cs_configs() 2012-10-21 03:02:54,544 - INFO : audrey:614 Execute Tooling command: /var/audrey/tooling/user/glusterd/start 2012-10-21 03:02:54,545 - INFO : audrey:614 return code: 0 2012-10-21 03:02:54,545 - INFO : audrey:614 Start Output of: /var/audrey/tooling/user/glusterd/start >>> <<< End Output
「(中略)」の部分は、しばらくConfigServerからの202の応答が続いていますが、これは、node02の「glusterup」パラメータを取得しようとして失敗している部分です。node02の構成が完了して、glusterupパラメータが取得できた段階で、設定スクリプトの実行が始まっています。
念のためGlusterFSのボリュームが構成できていることも確認しておきます。
# gluster peer status Number of Peers: 1 Hostname: ip-10-152-142-94 Uuid: 95dfc36f-fc99-446d-a9b3-c6b68a37db95 State: Peer in Cluster (Connected) # gluster vol info Volume Name: vol01 Type: Distribute Volume ID: dc561ad6-903e-4e3b-b62b-ee022b3823a5 Status: Started Number of Bricks: 2 Transport-type: tcp Bricks: Brick1: ip-10-160-78-73:/data/brick01 Brick2: ip-10-152-142-94:/data/brick01 # mount -t glusterfs localhost:/vol01 /mnt # df -h Filesystem Size Used Avail Use% マウント位置 /dev/xvde1 5.7G 1.8G 3.8G 33% / none 828M 0 828M 0% /dev/shm /dev/xvdj 147G 188M 140G 1% /data localhost:/vol01 294G 376M 279G 1% /mnt
まとめ
今回は、2ノードの構成を行いましたが、原理的には、ノード数が増えても同じです。node01では、その他の各ノードから「glusterup」パラメータを取得するように仕込んでおけば、他のノードの構成がすべて終わってから、node01の構成が始まります。
そして、賢明な読者はお気づきかと思いますが、この手法にはいくつか不便な点があります。
まず、使用するノード数が決め打ちになります。アプリケーション展開時にユーザが使用するノード数を指定することができません。また、ノード間の依存関係を「ワークフロー」的に定義することができません。つまり、「node01でgluterdの起動まで行なって、そこで、node02の構成完了を待って、それからクラスタを定義する」などの複雑な処理はできません。
このあたりは、今後のバージョンアップに期待することにしましょう。。。