めもめも

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

KVMでHAクラスタの機能検証環境を構築

  • 2011/08/04 17:50 クラスタの基本構成まで書いた。
  • 2011/08/05 18:50 サービスリソースの構成も書いた。

RHCSKVM

PC

High Availability Add-On 

前提ソフトウェア


RHEL6.1High Availability Add-On使Red Hat Cluster Suite(RHCS)

OK
# yum groupinstall "High Availability"

High AvailabilityFedora使
# rpm -q cman ccs omping rgmanager
cman-3.0.12-41.el6_1.1.x86_64
ccs-0.16.2-35.el6.x86_64
omping-0.0.1-4.el6.x86_64
rgmanager-3.0.12-11.el6_1.1.x86_64

VM環境の準備


VM2KVMLinux5





NICIPMI

3
 

node01node02RHEL6.1High Availability

iptablesoff
ntpd
/etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.7.201 node01
192.168.7.202 node02

192.168.8.201 node01m
192.168.8.202 node02m

192.168.9.201 node01h
192.168.9.202 node02h

rootSSHSSH

共有ストレージの準備


LinuxiSCSI使Linux

Linux
# yum install scsi-target-utils
# mkdir -p /var/lib/tgtd/cluster01
# cd /var/lib/tgtd/cluster01
# dd if=/dev/zero of=volume01.img bs=1M count=100
# dd if=/dev/zero of=volume02.img bs=1M count=1000

targetedSELinuxVolume/var/lib/tgtd//etc/tgt/targets.conf
<target iqn.2011-08.com.example.yourhost:tgt01>
    backing-store /var/lib/tgtd/cluster01/volume01.img
    backing-store /var/lib/tgtd/cluster01/volume02.img
</target>

tgtd
# chkconfig tgtd on
# service tgtd start
# tgt-admin -s
Target 1: iqn.2011-08.com.example.yourhost:tgt01
    System information:
        Driver: iscsi
        State: ready
    I_T nexus information:
    LUN information:
        LUN: 0
            Type: controller
            SCSI ID: IET     00010000
            SCSI SN: beaf10
            Size: 0 MB, Block size: 1
            Online: Yes
            Removable media: No
            Readonly: No
            Backing store type: null
            Backing store path: None
            Backing store flags: 
        LUN: 1
            Type: disk
            SCSI ID: IET     00010001
            SCSI SN: beaf11
            Size: 105 MB, Block size: 512
            Online: Yes
            Removable media: No
            Readonly: No
            Backing store type: rdwr
            Backing store path: /var/lib/tgtd/cluster01/volume01.img
            Backing store flags: 
        LUN: 2
            Type: disk
            SCSI ID: IET     00010002
            SCSI SN: beaf12
            Size: 1049 MB, Block size: 512
            Online: Yes
            Removable media: No
            Readonly: No
            Backing store type: rdwr
            Backing store path: /var/lib/tgtd/cluster01/volume02.img
            Backing store flags: 
    Account information:
    ACL information:
        ALL

volume01.imgvolume02.imgLUNOKQuorum Disk使

node01node02iSCSI LUN
# chkconfig iscsi
# service iscsi start
# iscsiadm -m discovery --type sendtargets --portal 192.168.8.1
# service iscsi restart

fdisk100MB/dev/sda1GB/dev/sdbOKvirtio使/dev/vdXXiSCSILinux3

クラスタ構成の準備


node01node02

riccicluster.conf
# chkconfig ricci on
# service ricci start

ricci
# passwd ricci

cmanrgmanager
# chkconfig cman off
# chkconfig rgmanager off

4

/usr/local/bin/clstart 
#!/bin/sh
service cman start
service rgmanager start

/usr/local/bin/clstop
#!/bin/sh
service rgmanager stop
service cman stop

/usr/local/bin/clstart_all 
#!/bin/sh
ssh node01 /usr/local/bin/clstart &
ssh node02 /usr/local/bin/clstart &
wait

/usr/local/bin/clstop_all 
#!/bin/sh
ssh node01 /usr/local/bin/clstop &
ssh node02 /usr/local/bin/clstop &
wait


# chmod u+x /usr/local/bin/clst*

Quorum Disknode01
# mkqdisk -c /dev/sda -l qdisk01
mkqdisk v3.0.12

Writing new quorum disk label 'qdisk01' to /dev/sda.
WARNING: About to destroy all data on /dev/sda; proceed [N/y] ? y
Warning: Initializing previously initialized partition
Initializing status block for node 1...
(中略)
Initializing status block for node 15...
Initializing status block for node 16...
 



Quorum Disk16Quorum Disk使16
 

Quorum Disk
# mkqdisk -L
mkqdisk v3.0.12

/dev/block/8:0:
/dev/disk/by-id/scsi-1IET_00010001:
/dev/disk/by-path/ip-192.168.8.1:3260-iscsi-iqn.2011-08.com.example.yourhost:tgt01-lun-1:
/dev/sda:
 Magic:                eb7a62c2
 Label:                qdisk01
 Created:              Thu Aug  4 16:37:37 2011
 Host:                 node01
 Kernel Sector Size:   512
 Recorded Sector Size: 512

node01
# mkfs.ext4 /dev/sdb

/data01
# mkdir /data01
# mount /dev/sdb /data01
# umount /data01

クラスタ構成ファイルの作成


High Availability Add-On1/etc/cluster/cluster.confXML1


<?xml version="1.0"?>
<cluster config_version="1" name="cluster01">
    <cman expected_votes="3"/>

    <clusternodes>
        <clusternode name="node01h" nodeid="1" votes="1">
            <fence>     
                <method name="virsh_reboot">
                    <device name="kvmhost01" port="RHCSvm01"/>
                </method>       
            </fence>    
        </clusternode>

        <clusternode name="node02h" nodeid="2" votes="1">
            <fence>     
                <method name="virsh_reboot">
                    <device name="kvmhost01" port="RHCSvm02"/>
                </method>       
            </fence>    
        </clusternode>
    </clusternodes>

    <totem token="20000"/>
    <quorumd interval="1" label="qdisk01" master_wins="1" tko="10" votes="1"/>

    <fencedevices>
        <fencedevice name="kvmhost01" agent="fence_virsh" ipaddr="192.168.8.1" login="root" passwd="XXXXX" option="reboot"/>
    </fencedevices>

</cluster>


Quorumの設定

Quorumはハートビートネットワークが分断して、クラスタが複数の島に分かれたときに生き残る島を決定する仕組みです。これには、島が持っている"votes"の値を計算する必要があります。(2ノード構成の場合は、1対1に分かれるしかないのであまり深い意味はありませんが・・・。)

まず、各ノードは1vote持っており、Quorum Diskも1vote持っているので、すべてが正常に稼働している時はクラスタ全体で3votesになります。これをここで指定します。

    <cman expected_votes="3"/>
クラスタに参加するノードの設定

"clusternode"タグに1ノードずつ記載します。

        <clusternode name="node01h" nodeid="1" votes="1">
            <fence>     
                <method name="virsh_reboot">
                    <device name="kvmhost01" port="RHCSvm01"/>
                </method>       
            </fence>    
        </clusternode>

nameオプションは、ハートビートネットワークのアダプタ名を指定します。nodeidは重複しない値を指定すること。

fenceタグは、ハートビートが切断するなどして、クラスタマネージャがこのサーバを強制再起動すると判断した時に用いる再起動方法です。node01が障害と判断すると、node02がここに指定された方法でnode01を再起動します。したがって、この方法はnode02から実行できる必要があります。ここで指定するmethodとdeviceの実体は、この後のfencedeviceで定義されます。

    <fencedevices>
        <fencedevice name="kvmhost01" agent="fence_virsh" ipaddr="192.168.8.1" login="root" passwd="XXXXX" option="reboot"/>
    </fencedevices>

ここでは、KVMのホストLinuxにlibvirtで接続して、VMを強制再起動するという仕組みを用いています。先に説明したように、ハートビート・ネットワークが切れているかもしれない状況で実施するものですので、ハートビートネットワークとは独立した管理ネットワーク経由で接続するようにIPを指定しています。ホストLinuxのrootパスワードが入っているのが気になる人は、SSH公開鍵認証も利用できます。passwdオプションの代わりにidentity_fileオプションで秘密鍵を指定します。先のclusternode側の設定にあるportオプションはlibvirtから見えるVM名を指定します。

Quorum Diskの設定

Quorum Diskに関する設定はここです。

    <totem token="20000"/>
    <quorumd interval="1" label="qdisk01" master_wins="1" tko="10" votes="1"/>

各ノードは、interval(1秒)ごとにQuorum Diskに生存情報を書き込みます。tko(10回)連続して生存情報が確認されないノードは死亡したと判断されて、先のFencedeviceで強制再起動されます。あるいは、Quorum Diskにtko回連続で書き込めないことに自分で気づいた場合は、自発的に再起動します。つまり、Quorum Diskによる障害検知は10秒以内に行われます。Quorum Diskは、ハートビートよりも"確実"な障害検知を提供する仕組みなので、ハートビート切断による障害検知は、これより遅くする必要があります。がハートビートによる障害検知の時間指定です。この例では20000msec(20秒)になります。

Quroum Disk的にはノードは生きているのに、ハートビート切断が起きた場合にどうなるか。。。。ですが、ここでは、master_winsオプションを指定しているので、内部的に決定されるマスターノードが生き残って、相手のノードは強制再起動されます。

ちなみに・・・・

あまり推奨される構成ではありませんが、サービスネットワークとハートビートネットワークを兼用する構成の場合、この方法では困ることがあります。例えば、サービス用のNICの障害でハートビートが切れた場合、どちらになるかよく分からない非マスターノードではなくて、NIC障害がおきたノードの方に死亡してもらう必要があります。このような場合は、master_winsオプションを外して、代わりに、heuristicを指定します。

    <quorumd interval="1" tko="10" votes="1" label="qdisk01">
        <heuristic program="/root/bin/pingcheck.sh" score="1" interval="2" tko="3"/>
    </quorumd>

programで指定されたシェルをinterval(2秒)ごとに実行して、tko(3回)連続して0以外のリターンコードを返すとそのノードは自発的に死亡します。例えば、ゲートウェイにpingが通るか確認するシェルを利用すれば、NIC障害のノードが自爆して、もう一方のノードが生き残ります。

なお、cluster.confに文法的な間違いがないかどうかは、次のコマンドで確認ができます。

# ccs_config_validate 
Configuration validates

クラスタの起動


node01/etc/cluster/cluster.confnode02

node01
# clstart_all 
Starting cluster: 
   Checking if cluster has been disabled at boot... [OK]
   Checking Network Manager... Starting cluster: 
   Checking if cluster has been disabled at boot... [OK]
   Checking Network Manager... [OK]
   Global setup... [OK]
   Loading kernel modules... [OK]
   Global setup... [OK]
   Loading kernel modules... [OK]
   Mounting configfs... [OK]
   Starting cman... [OK]
   Mounting configfs... [OK]
   Starting cman... [OK]
   Starting qdiskd... [OK]
   Starting qdiskd... [OK]
   Waiting for quorum... [OK]
   Starting fenced... [OK]
   Starting dlm_controld... [OK]
   Waiting for quorum... [OK]
   Starting fenced... [OK]
   Starting dlm_controld... [OK]
   Starting gfs_controld... [OK]
   Unfencing self... [OK]
   Joining fence domain... [OK]
   Starting gfs_controld... [OK]
   Unfencing self... [OK]
   Joining fence domain... [OK]
Starting Cluster Service Manager: [OK]
[OK]
Starting Cluster Service Manager: [OK]

/var/log/messages
# clustat 
Cluster Status for cluster01 @ Thu Aug  4 17:40:28 2011
Member Status: Quorate

 Member Name                                   ID   Status
 ------ ----                                   ---- ------
 node01h                                           1 Online, Local
 node02h                                           2 Online
 /dev/block/8:0                                    0 Online, Quorum Disk

# cman_tool status
Version: 6.2.0
Config Version: 1
Cluster Name: cluster01
Cluster Id: 8208
Cluster Member: Yes
Cluster Generation: 12
Membership state: Cluster-Member
Nodes: 2
Expected votes: 3
Quorum device votes: 1
Total votes: 3
Node votes: 1
Quorum: 2  
Active subsystems: 10
Flags: 
Ports Bound: 0 177  
Node name: node01h
Node ID: 1
Multicast addresses: 239.192.32.48 
Node addresses: 192.168.9.121 
 



Multicast address
SSH11
  HAHA
 

ifdownQuorum DiskiptablesiSCSI
# iptables -A INPUT -m tcp -p tcp --sport 3260 -j REJECT


# clstart
Starting cluster: 
   Checking if cluster has been disabled at boot...        [  OK  ]
   Checking Network Manager...                             [  OK  ]
   Global setup...                                         [  OK  ]
   Loading kernel modules...                               [  OK  ]
   Mounting configfs...                                    [  OK  ]
   Starting cman...                                        [  OK  ]
   Starting qdiskd...                                      [  OK  ]
   Waiting for quorum...                                   [  OK  ]
   Starting fenced...                                      [  OK  ]
   Starting dlm_controld...                                [  OK  ]
   Starting gfs_controld...                                [  OK  ]
   Unfencing self...                                       [  OK  ]
   Joining fence domain...                                 [  OK  ]
Starting Cluster Service Manager:                          [  OK  ]

サービスリソースの定義


IP(192.168.7.99)(/dev/sdb/data01)HA/etc/init.d/servicestart/stop/status/etc/init.d/myappl

cluster.confcluster
    <rm>
        <failoverdomains>
            <failoverdomain name="dom01" ordered="1" restricted="1">
                <failoverdomainnode name="node01h" priority="1"/>
                <failoverdomainnode name="node02h" priority="2"/>
            </failoverdomain>
        </failoverdomains>

        <service autostart="0" domain="dom01" name="service01">
            <ipaddress="192.168.7.99" monitor_link="on"/>
            <fsdevice="/dev/sdb" fstype="ext4" mountpoint="/data01" name="data_fs">
                <script file="/etc/init.d/myappl" name="myappl"/>
            </fs>               
        </service>      
    </rm> 


failoverドメイン

failover2node01node02failovername="dom01"132:1node01node03node02node03node01, node02node03



2:12TCPListen
HA2High Availability Add-On1
 

ordered="1"priorityautostart="1" priorityclusvcadm

ordered="0"priority

ordered="1"ordered="0"autostart="0"

restricted="1"failoverrestricted="0"failoverfailover
serviceタグ

serviceipfsscriptfsfsmyappl

IPipIPNICNICIP

設定変更の反映


node01/etc/cluster/cluster.conf

clusterconfig_version
<cluster config_version="2" name="cluster01">

node01
# cman_tool version -r

riccicluster.conf
# ccs_config_dump

cluster.conf

サービスの起動



# clustat 
Cluster Status for cluster01 @ Thu Aug  4 18:34:23 2011
Member Status: Quorate

 Member Name                                   ID   Status
 ------ ----                                   ---- ------
 node01h                                           1 Online, Local, rgmanager
 node02h                                           2 Online, rgmanager
 /dev/block/8:0                                    0 Online, Quorum Disk

 Service Name                         Owner (Last)                         State         
 ------- ----                         ----- ------                         -----         
 service:service01                    (none)                               disabled      

disabledautostart="0"service01(enable)
# clusvcadm -e service01
Local machine trying to enable service:service01...Success
service:service01 is now running on node01h


# clustat 
Cluster Status for cluster01 @ Thu Aug  4 18:34:46 2011
Member Status: Quorate

 Member Name                                   ID   Status
 ------ ----                                   ---- ------
 node01h                                           1 Online, Local, rgmanager
 node02h                                           2 Online, rgmanager
 /dev/block/8:0                                    0 Online, Quorum Disk

 Service Name                         Owner (Last)                         State         
 ------- ----                         ----- ------                         -----         
 service:service01                    node01h                              started   

node01h-m


# clusvcadm -r service01
Trying to relocate service:service01...Success
service:service01 is now running on node02h

# clusvcadm -d service01
Local machine disabling service:service01...Success




# rg_test test /etc/cluster/cluster.conf


# rg_test noop /etc/cluster/cluster.conf start service service01
# rg_test noop /etc/cluster/cluster.conf stop service service01