2014年8月26日火曜日

SoftLayerに冗長化NFSサーバを(その1)

SoftLayer には Block Storage としての iscsi があります。File Storage としての cifs もあります。残念ながら、File Storage としての NFS がありません。正確には、QuantaStor を導入すればあるともいえるのですが、金額的に敷居が高すぎます。

※2014/09/30 追記
File Storage (Consistent Performance) という NFS ベースのサービスが始まっています。
詳細は 「SoftLayerに冗長化NFSサーバを(その10) (http://dba-ha.blogspot.jp/2014/09/softlayernfs10.html)」を参照してください。

そこで、フリーウェアを利用して、冗長化した NFS サーバを構築することとしました。16TB を超えないのであれば、今回紹介するもので十分だと思われます。16TB を超える場合は、Linbit 社のバイナリで構築する場合に、サポートがどうなるか相談が必要になるものと思われます。今回はフリーのバイナリで構築するので、もう少し大きくてもイケイケのように思われます。

まずは、データセンタ内で冗長化を図ります。共有ディスクとして SoftLayer の Block Storage を利用し冗長化した NAS ヘッドを作る、でもよかったのですが、DRBD を利用することにしました。ネットワーク越しの RAID1 を実現するソフトウェアだと考えればよいです。QuantaStor も DRBD を利用したレプリケーションが可能のようです。DRBD は Linux カーネル本体にマージされていますが、RHEL 等では、コンパイルオプションから削られています。最大4台までの構成を実現できます。DR (Disaster Recovery) サイトにデータをリアルタイムでコピーする用途にも利用できます。

DRBD の検証を仮想マシンで実施していた際に気付いたのですが、NIC の通信速度を 1Gbps で発注していても、特に上限を制限しているわけではなさそうで、2Gbps ほど出ていました。100Mbps で発注した時は、キッチリ 100Mbps に張り付いていたことから、100Mbps で発注した時は仮想スイッチで 100Mbps に制限しているだけなのだと思われます。一方、2Gbps も出ていることからすると、同一筐体で動いている可能性が高いと考えています。せっかく冗長化していても、ハイパーバイザが障害を起こした際にはフェイルオーバさせることができません。冗長化させる2台を確実に別筐体で動かしたい場合は、仮想マシンではなく、物理マシンを利用した方がよいです。

※ 2014/11/8 追記
別筐体で動いている場合でも、2Gbps 出ました。 仮想マシンの場合でも別筐体で動いていることを確認することができます(http://goo.gl/xQRJ9l)。

物理マシンでは、NIC の冗長化がサポートされており、最大 2Gbps の速度が理論的に出ます。Public VLAN と Private VLAN の2つを利用すると、最大 4Gbps の速度が理論的に出ます。また、物理マシンの場合、ジャンボフレームもサポートされているので、ストレージ系のノードを構築する場合は物理マシンの利用が必須と考えておいた方がよいと思います。また、RAID コントローラを利用できる筐体を発注すべきと考えるので、4台以上の物理 HDD を搭載できる物理マシンを発注することになります。残念ながら Bare Metal Instance は HDD が1台しかなく、RAID コントローラもないので、考慮対象から外します。

※ 2014/8/29 追記
 (その2) から Bare Metal Instance 対応に変更しました。
発注時、もしくは OS Reload 時に Partition Template にて、「Linux Extra Partition」を選択しておいてください。

※ 2014/11/8 追記
Bare Metal Instance が廃止され、時間課金の物理サーバが登場しています。詳細は 「SoftLayerに冗長化NFSサーバを(その8) (http://dba-ha.blogspot.jp/2014/09/softlayernfs_14.html)」を参照してください。

データについては DRBD を利用して2台のサーバに保持するわけですが、障害発生時に自動的にフェイルオーバするよう、クラスタ化します。クラスタソフトは実績を考慮して Heartbeat & Pacemaker を利用します。HA 構成をとる場合には VCS (Veritas Cluster Server) を使いたいところですが、DRBD との相性も考え、今回はフリーソフトで固めます。

本稿では、仮想マシンでの操作例を示します。ボンディング設定、ジャンボフレーム設定、HDD のデバイス名を除けば、基本的には同じ操作となります。一応 if 文等を利用して Bare Metal Server でも動く操作例となるように心掛けますが、テストは Bare Metal Instance でしかしていない点、ご了承ください。RAID コントローラの操作例は出てきません。

※ 2014/11/8 追記
月額課金の物理サーバでの操作例も確認するようにしました。
テストは月額課金物理サーバ、仮想サーバの両方で実施しています。

まずはネットワーク図を作成します。NFS サーバ2台、NFS クライアント1台から始めます。作図するほどのことはないのですが、少しずつ育てていきたいと考えています。


GitHub にも上げておきます。

https://raw.githubusercontent.com/pcserver-jp/SoftLayer/master/SoftLayerNetworkNFS.vsd
https://raw.githubusercontent.com/pcserver-jp/SoftLayer/master/SoftLayerNetworkNFS.pdf

SoftLayer の Public VLAN 側に振られているグローバル IP アドレスは無効化して、ルーティングを考慮外とするプライベート IP アドレスに置き換えます。Private VLAN 側に振られているプライベート IP アドレスは Portable IP Address に置き換えます。両 VLAN をハートビートに利用します。DRBD は Public VLAN 側でデータ同期のための通信を行います。Private VLAN 側に VIP を持たせ、NFS クライアントは VIP 向けに通信させます。



ローカルストレージの構成は1台目の HDD (/dev/xvda) を OS 領域とし、追加 HDD をデータ領域として利用します。SoftLayer の仮想マシンでは swap 専用の仮想 HDD (/dev/xvdb) が追加されているので、3台目 (/dev/xvdc) 以降の追加 HDD がデータ領域ということになります。物理マシンでは、RAID コントローラを追加し、1つ目の論理デバイス 25GB (/dev/sda) を OS 領域とし、2つ目の論理デバイス 2GB (/dev/sdb) を swap 領域とし、3つ目の論理デバイス (/dev/sdc) 以降をデータ領域とします。このようにすれば、本番環境は物理マシン、検証、開発環境は仮想マシンで構成する、といったことがやりやすくなります。
最初は3台の論理 HDD (2台の仮想 HDD を発注)からスタートします。

仮想マシンで仮想 HDD を選択するにあたり、SAN にするか Local にするか決める必要があります。管理ポータルのデフォルトでは SAN になっていますが、CLI でのデフォルトは Local になっています。Local の場合、割安なのですが、1台の追加しかできません。最大サイズも 300GB となっています。一方 SAN を選ぶと、4台追加することができます。最大サイズは 2TB となっています。LVM で束ねれば、8TB の領域を扱うことができます。勉強会で IBM の新島先生が言われていましたが、SAN を選んでおくと、ハイパーバイザ障害時に、他のハイパーバイザで起動してもらえるようです。
今回は、SAN を選択し、100GB の HDD を追加することにします。OS 用は 25GB のままで十分です。

以下のコマンドで発注します。コマンド・オプションの説明は何度かしているので割愛させていただきます。backup11、backup12 の Public VLAN が同じになるように、client の発注順序を調整してください。


$ sl sshkey list
:.......:.................:.................................................:.......:
:   id  :      label      :                   fingerprint                   : notes :
:.......:.................:.................................................:.......:
: 00000 : softlayer@hkg02 : 14:c9:59:22:f6:8d:8c:db:62:03:2c:60:78:e2:e8:75 :   -   :
:.......:.................:.................................................:.......:
$ sl vs create --key=00000 --datacenter=hkg02 --hostname=backup11 --domain=example.com --cpu=1 --memory=1024 --network=1000 --disk=25 --disk=100 --san --hourly --os=CENTOS_6_64 --postinstall=https://raw.githubusercontent.com/pcserver-jp/SoftLayer/master/co6.sh -y
:.........:......................................:
:    name : value                                :
:.........:......................................:
:      id : 5932858                              :
: created : 2014-08-24T13:51:19+09:00            :
:    guid : 379b5177-0193-4c4e-9aeb-2a2ebed78013 :
:.........:......................................:
$ sl vs create --key=00000 --datacenter=hkg02 --hostname=backup12 --domain=example.com --cpu=1 --memory=1024 --network=1000 --disk=25 --disk=100 --san --hourly --os=CENTOS_6_64 --postinstall=https://raw.githubusercontent.com/pcserver-jp/SoftLayer/master/co6.sh -y
:.........:......................................:
:    name : value                                :
:.........:......................................:
:      id : 5932862                              :
: created : 2014-08-24T13:52:24+09:00            :
:    guid : 1eeb816a-f6a8-4d1f-9c72-19f844dfc2fd :
:.........:......................................:
$ sl vs create --key=00000 --datacenter=hkg02 --hostname=client --domain=example.com --cpu=1 --memory=1024 --network=1000 --disk=25 --san --hourly --os=CENTOS_6_64 --postinstall=https://raw.githubusercontent.com/pcserver-jp/SoftLayer/master/co6.sh -y
:.........:......................................:
:    name : value                                :
:.........:......................................:
:      id : 5932910                              :
: created : 2014-08-24T14:30:44+09:00            :
:    guid : d4f36aa9-5b8d-4aac-bb56-39f53c1a4c2b :
:.........:......................................:


最初に、sl-admin ユーザでログインしてパスワード変更を行います。このあたりの操作についても説明を割愛させていただきます。
SoftLayer の CentOS 6.5 を CentOS 7 にアップグレードしてみた (http://dba-ha.blogspot.jp/2014/08/softlayer-centos-65-centos-7.html) を参照してください。

Portable Private IP Addresses を発注します。10.110.88.0/64 を取得できた前提で操作例を示します。このあたりの操作についても説明を割愛させていただきます。

backup11、backup12 サーバを構築していきます。
クラスタソフトとして利用する Pacemaker ですが、RHEL のパッケージではなく、LINUX-HA JAPAN (http://linux-ha.sourceforge.jp/) が配布しているパッケージを利用します。安定性が高く、また、独自追加のリソース・エージェントを利用したいと思っています。
RHEL のパッケージが間違ってインストールされないように yum リポジトリ設定を変更します。


cat << 'EOF' | sudo tee /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-6 - Base
baseurl=http://mirrors.service.networklayer.com/centos/6/os/x86_64/
gpgcheck=1
gpgkey=http://mirrors.service.networklayer.com/centos/RPM-GPG-KEY-CentOS-6
exclude=cluster-glue* corosync* heartbeat* ldirectord libesmtp* pacemaker* resource-agents* drbd*

[updates]
name=CentOS-6 - Updates
baseurl=http://mirrors.service.networklayer.com/centos/6/updates/x86_64/
gpgcheck=1
gpgkey=http://mirrors.service.networklayer.com/centos/RPM-GPG-KEY-CentOS-6
exclude=cluster-glue* corosync* heartbeat* ldirectord libesmtp* pacemaker* resource-agents* drbd*

[extras]
name=CentOS-6 - Extras
baseurl=http://mirrors.service.networklayer.com/centos/6/extras/x86_64/
gpgcheck=1
gpgkey=http://mirrors.service.networklayer.com/centos/RPM-GPG-KEY-CentOS-6
exclude=centos-release-*

[centosplus]
name=CentOS-6 - Plus
baseurl=http://mirrors.service.networklayer.com/centos/6/centosplus/x86_64/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.service.networklayer.com/centos/RPM-GPG-KEY-CentOS-6

[contrib]
name=CentOS-6 - Contrib
baseurl=http://mirrors.service.networklayer.com/centos/6/contrib/x86_64/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.service.networklayer.com/centos/RPM-GPG-KEY-CentOS-6
EOF


DRBD のパッケージは ELRepo (http://elrepo.org/) のものを利用します。


cat << 'EOF' | sudo tee /etc/yum.repos.d/elrepo.repo
[elrepo]
name=ELRepo.org Community Enterprise Linux Repository - el6
baseurl=http://elrepo.org/linux/elrepo/el6/$basearch/
        http://mirrors.coreix.net/elrepo/elrepo/el6/$basearch/
        http://jur-linux.org/download/elrepo/elrepo/el6/$basearch/
        http://repos.lax-noc.com/elrepo/elrepo/el6/$basearch/
        http://mirror.ventraip.net.au/elrepo/elrepo/el6/$basearch/
mirrorlist=http://mirrors.elrepo.org/mirrors-elrepo.el6
enabled=0
gpgcheck=1
gpgkey=http://www.elrepo.org/RPM-GPG-KEY-elrepo.org
protect=0
exclude=elrepo-release
EOF


DRBD は 8.4 系をインストールします。設定ファイルは 8.4 系のシンタックスで書くこととします。


sudo yum -y --enablerepo=elrepo install drbd84-utils kmod-drbd84


Pacemaker リポジトリパッケージ (RHEL6用) の最新のものを http://linux-ha.sourceforge.jp/wp/dl/packages で確認し、ダウンロード・インストールします。今回は 1.0.13-2.1 を入れます。


wget http://iij.dl.sourceforge.jp/linux-ha/61791/pacemaker-1.0.13-2.1.el6.x86_64.repo.tar.gz
tar xzvf pacemaker-1.0.13-2.1.el6.x86_64.repo.tar.gz -C /tmp/
sudo yum -y -c /tmp/pacemaker-1.0.13-2.1.el6.x86_64.repo/pacemaker.repo install pacemaker heartbeat pm_extras pm_diskd
rm -rf /tmp/pacemaker-1.0.13-2.1.el6.x86_64.repo pacemaker-1.0.13-2.1.el6.x86_64.repo.tar.gz


クラスタの起動方針として、サービスは OS 起動完了後オペレータが手動で起動することとします。復旧作業を考えた場合に自動起動されては困ること、基本的には24時間365日動き続けることを想定しているクラスタを起動するような状況であれば確実にオペレータがいるはずだと考えてよいこと、を勘案しました。
うっかり自動起動設定に変更しないように (気休めでしかありませんが)、また、ランレベル変更の影響を受けないように、サービスの一覧から削除しておきます。サービス起動はクラスタソフトが行います。初期構築、障害対応を除き、オペレータが起動するのは heartbeat サービスだけという想定です。


sudo chkconfig --del corosync
sudo chkconfig --del drbd
sudo chkconfig --del heartbeat
sudo chkconfig --del logd


NFS 関連パッケージをインストールします。
こちらもサービスの一覧から削除しておきます。


sudo yum -y install nfs-utils
sudo chkconfig --del nfs
sudo chkconfig --del nfslock
sudo chkconfig --del rpcbind
sudo chkconfig --del rpcgssd
sudo chkconfig --del rpcsvcgssd


NFS 設定を変更します。ファイアウォール設定が楽になるように使用するポート番号を固定します。また、IPv6 設定をコメントアウトします。


cat << 'EOF' | sudo tee /etc/sysconfig/nfs
MOUNTD_NFS_V2="no"
RQUOTAD_PORT=875
#RPCRQUOTADOPTS=""
#LOCKDARG=
LOCKD_TCPPORT=32803
LOCKD_UDPPORT=32769
RPCNFSDARGS="-N 2"
RPCNFSDCOUNT=16
#NFSD_MODULE="noload"
#NFSD_V4_GRACE=90
#RPCMOUNTDOPTS=""
MOUNTD_PORT=892
#STATDARG=""
STATD_PORT=662
STATD_OUTGOING_PORT=2020
RPCIDMAPDARGS="-S"
#SECURE_NFS="yes"
#RPCGSSDARGS=""
#RPCSVCGSSDARGS=""
#RDMA_PORT=20049
EOF
sudo sed -i -e 's/^udp6/#udp6/' -e 's/^tcp6/#tcp6/' /etc/netconfig


NFS サーバが他の NFS をマウントしていると、フェイルオーバに支障をきたす可能性があるので、禁止とします。コマンドからは実行権限を奪っておきます。


sudo chmod -x /sbin/mount.nfs
sudo chmod -x /sbin/mount.nfs4


※ 2014/9/6 追記
ここから先は環境依存の部分があるので、その部分パラメータ化し、/etc/ha.d/param_cluster ファイルにまとめました。太字の部分を書き換えておけば、後続の処理は、基本的に、貼り付けていくだけでよくなっています。ポータブル IP アドレスは必ず /26 (64個) で取得しておいてください。


cat << 'EOF' | sudo tee /etc/ha.d/param_cluster
HA1_IP=10.110.88.60
HA2_IP=10.110.88.61
HA_VIP=10.110.88.62
HA_DOMAIN=example.com
HA1_NODE=backup11
HA2_NODE=backup12
HA_NODE=backup1
HA_GATEWAY_NODE=gateway1
SSH_CLIENTS=10.0.0.0/8
DRBD_SIZE=90G
DRBD_PASSWORD=password
VIP_CLIENTS=10.0.0.0/8

HA1_NAME=$HA1_NODE.$HA_DOMAIN
HA2_NAME=$HA2_NODE.$HA_DOMAIN
HA_NAME=$HA_NODE.$HA_DOMAIN
HA_GATEWAY_NAME=$HA_GATEWAY_NODE.$HA_DOMAIN
HA1_HB_NAME=$HA1_NODE-hb.$HA_DOMAIN
HA2_HB_NAME=$HA2_NODE-hb.$HA_DOMAIN
HA1_HB_IP=192.168.0.2
HA2_HB_IP=192.168.0.3

HA_NETWORK_123=$(echo $HA_VIP | awk -F. '{print $1 "." $2 "." $3}')
HA_NETWORK_4=$(($(echo $HA_VIP | awk -F. '{print $4}')&~63))
HA_GATEWAY="$HA_NETWORK_123.$((HA_NETWORK_4+1))"
[ -e /proc/net/bonding ] && NIC0=bond0 || NIC0=eth0
[ -e /proc/net/bonding ] && NIC1=bond1 || NIC1=eth1
[ "$(uname -n)" = "$HA1_NAME" ] && PRIV_IP=$HA1_IP || PRIV_IP=$HA2_IP
[ "$(uname -n)" = "$HA1_NAME" ] && PUB_IP=$HA1_HB_IP || PUB_IP=$HA2_HB_IP
[ "$(uname -n)" = "$HA1_NAME" ] && PEER_PRIV_IP=$HA2_IP || PEER_PRIV_IP=$HA1_IP
[ "$(uname -n)" = "$HA1_NAME" ] && PEER_PUB_IP=$HA2_HB_IP || PEER_PUB_IP=$HA1_HB_IP
HA_DEV1=xvdc
if [ ! -d /proc/xen/ ]; then
  [ -e /dev/sdc ] && HA_DEV1=sdc || HA_DEV1=sda
fi
EOF


IP アドレスを変更します。Private LAN 側は Primary IP Address から Portable IP Address にします。Public LAN 側はグローバル IP アドレスから、ルーティング不要なプライベート IP アドレスにします。
Network サービスを再起動したら接続しなおす必要があります。


. /etc/ha.d/param_cluster

sudo sed -i -e "s/^IPADDR=.*\$/IPADDR=$PRIV_IP/" /etc/sysconfig/network-scripts/ifcfg-$NIC0
sudo sed -i -e "s/^IPADDR=.*\$/IPADDR=$PUB_IP/" /etc/sysconfig/network-scripts/ifcfg-$NIC1
sudo sed -i -e '/^GATEWAY=/d' /etc/sysconfig/network-scripts/ifcfg-$NIC0
sudo sed -i -e '/^GATEWAY=/d' /etc/sysconfig/network-scripts/ifcfg-$NIC1

sudo sed -i -e '/^MTU=/d' /etc/sysconfig/network-scripts/ifcfg-$NIC0
sudo sed -i -e '/^MTU=/d' /etc/sysconfig/network-scripts/ifcfg-$NIC1
if [ ! -e /proc/xen ]; then
  echo "MTU=9000" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-$NIC0
  echo "MTU=9000" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-$NIC1
fi
sudo sed -i -e "s/^GATEWAY=.*\$/GATEWAY=$HA_GATEWAY/" /etc/sysconfig/network
sudo rm -f /etc/sysconfig/network-scripts/route-$NIC0

cat << EOF | sudo tee /etc/hosts
127.0.0.1       localhost.localdomain localhost
$HA_GATEWAY     $HA_GATEWAY_NAME $HA_GATEWAY_NODE
$HA1_IP    $HA1_NAME $HA1_NODE
$HA2_IP    $HA2_NAME $HA2_NODE
$HA_VIP    $HA_NAME $HA_NODE
$HA1_HB_IP     $HA1_HB_NAME $HA1_NODE-hb
$HA2_HB_IP     $HA2_HB_NAME $HA2_NODE-hb
EOF

sudo /etc/init.d/network restart


ファイアウォール設定を変更します。


. /etc/ha.d/param_cluster

cat << EOF | sudo tee /etc/sysconfig/iptables
*filter
:INPUT   ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT  ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
########## Public VLAN (& Private VLAN) ##########
-A INPUT -s $HA1_HB_IP,$HA2_HB_IP -j ACCEPT
-A INPUT -i eth1  -j DROP
-A INPUT -i eth3  -j DROP
-A INPUT -i bond1 -j DROP
########## Private VLAN ##########
-A INPUT -s $HA1_IP,$HA2_IP,$HA_VIP -j ACCEPT
-A INPUT -p tcp --dport 2049  -m tcp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p udp --dport 2049  -m udp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p tcp --dport 111   -m tcp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p udp --dport 111   -m udp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p tcp --dport 662   -m tcp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p udp --dport 662   -m udp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p tcp --dport 875   -m tcp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p udp --dport 875   -m udp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p tcp --dport 892   -m tcp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p udp --dport 892   -m udp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p tcp --dport 32803 -m tcp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p udp --dport 32769 -m udp -m state --state NEW -s $VIP_CLIENTS -d $HA_VIP -j ACCEPT
-A INPUT -p tcp --dport 22    -m tcp -m state --state NEW -s $SSH_CLIENTS -j ACCEPT
-A INPUT -p icmp -s 10.0.0.0/8 -j ACCEPT
#-A INPUT -j LOG --log-prefix "iptables: " --log-level=debug
-A INPUT -j REJECT --reject-with icmp-host-prohibited
########## FORWARD ##########
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
EOF
if ! ifconfig bond0 > /dev/null 2>&1; then
  sudo sed -i -e '/bond0/ s/^/#/' /etc/sysconfig/iptables
  sudo sed -i -e '/bond1/ s/^/#/' /etc/sysconfig/iptables
  sudo sed -i -e '/eth2/  s/^/#/' /etc/sysconfig/iptables
  sudo sed -i -e '/eth3/  s/^/#/' /etc/sysconfig/iptables
fi

sudo /etc/init.d/iptables restart


カーネルパラメータを変更します。


cat << 'EOF' | sudo tee -a /etc/sysctl.conf

net.core.wmem_max = 16777216
net.core.rmem_max = 16777216
net.core.wmem_default = 16777216
net.core.rmem_default = 16777216
net.core.netdev_max_backlog = 250000
net.core.optmem_max = 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_sack = 0
net.ipv4.tcp_no_metrics_save = 1
EOF
sudo sysctl -p


DRBD の設定ファイルを作成します。


cat << EOF | sudo tee /etc/drbd.d/global_common.conf
global {
  usage-count no;
}
common {
  handlers {
    local-io-error "/usr/lib/drbd/notify-io-error.sh; /usr/lib/drbd/notify-emergency-shutdown.sh; echo 1 > /proc/sys/kernel/sysrq; echo o > /proc/sysrq-trigger ; halt -f";
    fence-peer "/usr/lib/drbd/crm-fence-peer.sh";
    after-resync-target /usr/lib/drbd/crm-unfence-peer.sh;
  }
  startup {
#wfc#    wfc-timeout 10;
#wfc#    degr-wfc-timeout 10;
#wfc#    outdated-wfc-timeout 10;
  }
  disk {
    on-io-error detach;
    fencing resource-only;
    al-extents 6433;
    c-plan-ahead 20;
    c-delay-target 100;
    c-fill-target 0;
    c-max-rate 100M;
    c-min-rate 1M;
  }
  net {
    protocol C;
    max-buffers 128k;
    sndbuf-size 0;
    rcvbuf-size 0;
    cram-hmac-alg sha1;
    shared-secret "$DRBD_PASSWORD";
    congestion-fill 100M;
    congestion-extents 2000;
    csums-alg md5;
    verify-alg md5;
    use-rle;
  }
}
EOF
cat << EOF | sudo tee /etc/drbd.d/r0.res
resource r0 {
  volume 0 {
    device /dev/drbd0;
    disk /dev/vg0/drbd0;
    meta-disk internal;
  }
  on $HA1_NAME {
    address $HA1_HB_IP:7788;
  }
  on $HA2_NAME {
    address $HA2_HB_IP:7788;
  }
}
EOF


データ領域を LVM で構成し、DRBD 用に初期化します。Bare Metal Instance の場合は追記2の部分を参照してください。


DEV=sdc
[ -e /proc/xen ] && DEV=xvdc
sudo fdisk -H 64 -S 32 /dev/${DEV} << 'EOF'
o
n
p
1


t
8e
p
w
EOF
sudo pvcreate /dev/${DEV}1
sudo vgcreate vg0 /dev/${DEV}1
sudo lvcreate --name drbd0 --extents 90%FREE vg0
sudo drbdadm create-md r0


※ 2014/8/29 追記
物理マシンの場合、発注したサイズよりも大きい HDD が装填される可能性があります。
上記では、空き容量の90%を指定していますが、固定サイズを指定した方が確実です。1号機と2号機でサイズが異なる可能性があります。また、将来障害のため発注しなおす可能性もあり、その時に同じサイズの HDD が装填されていない可能性があります。発注時に指定したサイズ以上の容量のものが装填されることしか保証されません。
環境に合わせ、「--extents 90%FREE」の部分を「--size 90G」等に変更した方がよいです。

※ 2014/9/6 追記2
(その2)で触れた Bare Metal Instance 対応をここにも反映しておきます。

sudo sed -i -e '/disk/ s/^UUID/#UUID/' /etc/fstab
sudo umount /disk0
sudo umount /disk
sudo rmdir /disk0 /disk
sudo fdisk /dev/sda << 'EOF'
t
5
8e
p
w
EOF
sudo pvcreate /dev/sda5
sudo vgcreate vg0 /dev/sda5
#sudo lvcreate --name drbd0 --extents 90%FREE vg0
sudo lvcreate --name drbd0 --size 400G vg0
sudo dd if=/dev/zero of=/dev/vg0/drbd0 bs=1M
sudo drbdadm create-md r0


ここまでの操作は、backup11、backup12 の両方で実行します。
以降の操作は、両者が連携しながら動くことになるので、どちらのサーバで操作するのかを明示するようにします。

DRBD の初期同期を行います。初期同期は時間がかかります。最初の構築時にはスキップして構いません。全領域がゼロ・クリアされた状態で提供されていたはずだからです。スキップするための操作方法を示します。


[sl-admin@backup11 ~]$ sudo /etc/init.d/drbd start
[sl-admin@backup12 ~]$ sudo /etc/init.d/drbd start
[sl-admin@backup12 ~]$ watch cat /proc/drbd
[sl-admin@backup11 ~]$ sudo drbdadm new-current-uuid --clear-bitmap r0/0
[sl-admin@backup11 ~]$ sudo drbdadm primary all


backup11 サーバ側で共有領域を初期化します。
共有領域を /export にローカル・マウントし、NFS クライアントには、/export/backup を /backup としてエクスポートする想定です。NFSv3、NFSv4 のどちらで利用してもエクスポートポイントを共通化しています。NFSv3 の場合は、/export/backup をマウントし、NFSv4 の場合は /backup をマウントする、というのでは、システム的にいかがなものかと思われます。


sudo mkfs.ext4 /dev/drbd0
sudo tune2fs -c 0 -i 0 /dev/drbd0
sudo mkdir /export
sudo mkdir /backup
sudo mount /dev/drbd0 /export

sudo /etc/init.d/rpcbind start
sudo /etc/init.d/nfslock start
sudo /etc/init.d/nfs start
sudo /etc/init.d/nfs stop
sudo /etc/init.d/nfslock stop
sudo /etc/init.d/rpcbind stop
sudo umount /var/lib/nfs/rpc_pipefs/

sudo mv /var/lib/nfs /export/
sudo ln -s /export/nfs /var/lib/nfs
sudo rmdir /export/nfs/rpc_pipefs/
sudo mkdir /var/lib/rpc_pipefs/
sudo ln -s /var/lib/rpc_pipefs /export/nfs/rpc_pipefs
sudo mkdir -p /export/backup/system
sudo chmod 700 /export/backup/system
sudo chown -R nfsnobody:nfsnobody /export/backup

sudo umount /export/
sudo drbdadm secondary all
sudo /etc/init.d/drbd stop

sudo tar czvf sshd.tgz /etc/ssh
scp sshd.tgz backup12:
The authenticity of host 'ctrl2 (10.110.88.61)' can't be established.
RSA key fingerprint is bd:9e:69:ba:f7:81:14:29:7f:ec:85:65:90:10:02:f9.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ctrl2,10.110.88.61' (RSA) to the list of known hosts.
ssh-keygen -R backup12
rm -f .ssh/known_hosts sshd.tgz


backup12 サーバ側で漏れている設定を施します。
ssh ホスト鍵を1号機と同じものに変更したので、次に2号機に ssh 接続した際は警告が出ます。


sudo mkdir /export
sudo mkdir /backup
sudo mkdir /var/lib/rpc_pipefs/
sudo rm -rf /var/lib/nfs
sudo ln -s /export/nfs /var/lib/nfs
sudo /etc/init.d/drbd stop

cd /
sudo tar xzvf /home/sl-admin/sshd.tgz
sudo /etc/init.d/sshd restart
cd
rm -f sshd.tgz


ログ設定を行います。クラスタのログが /var/log/ha-log に出力されるようにします。
両サーバで実施します。


sudo sed -i -e 's%^.* /var/log/messages$%*.info;mail.none;authpriv.none;cron.none;local1.none    /var/log/messages%' -e '/\/var\/log\/messages$/a local1.info                                             /var/log/ha-log' /etc/rsyslog.conf
sudo /etc/init.d/rsyslog restart

cat << 'EOF' | sudo tee /etc/logrotate.d/heartbeat

EOF
cat << 'EOF' | sudo tee /etc/logrotate.d/syslog
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/ha-log
/var/log/secure
/var/log/spooler
{
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}
EOF


heartbeat の設定を行います。
両サーバで実施します。


cat << 'EOF' | sudo tee /etc/ha.d/authkeys
auth 1
1 crc
EOF
sudo chmod 600 /etc/ha.d/authkeys
cat << EOF | sudo tee /etc/ha.d/ha.cf
crm yes
debug 0
logfacility local1
keepalive 2
warntime 7
deadtime 10
initdead 48
udpport 694
ucast $NIC0 $PEER_PRIV_IP
ucast $NIC1 $PEER_PUB_IP
node $HA1_NAME
node $HA2_NAME
uuidfrom nodename
autojoin none
respawn root /usr/lib64/heartbeat/ifcheckd
EOF


別端末を開き、backup11 サーバに接続し、ログを表示しておきます。


sudo touch /var/log/ha-log
sudo tail -f /var/log/ha-log


両サーバで heartbeat を起動します。


sudo /etc/init.d/heartbeat start
sudo crm_mon -rfA


crm_mon -rfA の実行結果が下記のようになるまで待ち、backup11 側は Ctrl+C で停止させます。


============
Last updated: Sat Aug 23 19:49:29 2014
Stack: Heartbeat
Current DC: backup12.example.com (1cf3e4ed-919b-84d7-9853-0c46f4854365) - partition with quorum
Version: 1.0.13-a83fae5
2 Nodes configured, unknown expected votes
0 Resources configured.
============

Online: [ backup11.example.com backup12.example.com ]

Full list of resources:


Node Attributes:
* Node backup11.example.com:
    + backup12.example.com-eth0         : up
    + backup12.example.com-eth1         : up
* Node backup12.example.com:
    + backup11.example.com-eth0         : up
    + backup11.example.com-eth1         : up

Migration summary:
* Node backup11.example.com:
* Node backup12.example.com:


backup11 サーバにて、pacemaker のリソース設定ファイルを作成し、ロードします。
設定ファイルは backup12 サーバにも作成しておいた方がよいと思いますが、必須ではありません。


VIP_CLIENTS=$(echo $VIP_CLIENTS | tr , " ")
P_VIP=p_vip_$(echo $HA_VIP | tr . _)
cat << EOF | sudo tee /etc/ha.d/crm.txt
primitive p_drbd_r0 ocf:linbit:drbd \\
  params drbd_resource="r0" \\
  op start   interval="0" timeout="240s" \\
  op monitor interval="31s" role="Master" timeout="20s" \\
  op monitor interval="29s" role="Slave"  timeout="20s" \\
  op notify  interval="0" timeout="90s" \\
  op stop    interval="0" timeout="120s" \\
  op promote interval="0" timeout="90s" \\
  op demote  interval="0" timeout="90s"
primitive p_vipcheck ocf:heartbeat:VIPcheck \\
  params target_ip="$HA_VIP" count="1" wait="10" \\
  op start interval="0" timeout="90s" start_delay="4s" \\
  op stop  interval="0" timeout="60s"
primitive $P_VIP ocf:heartbeat:IPaddr2 \\
  params ip=$HA_VIP cidr_netmask=26 \\
  op start   interval="0"   timeout="20" \\
  op monitor interval="30s" timeout="20" \\
  op stop    interval="0"   timeout="20"
primitive p_vip ocf:heartbeat:IPsrcaddr \\
  params ipaddress=$HA_VIP \\
  op monitor interval="50s" timeout="30"
primitive p_fs_export ocf:heartbeat:Filesystem \\
  params device=/dev/drbd0 directory=/export fstype=ext4 run_fsck="no" \\
  op start   interval="0"   timeout="60s" \\
  op monitor interval="10s" timeout="40s" \\
  op stop    interval="0"   timeout="60s"
primitive p_fs_nfs3 ocf:heartbeat:Filesystem \\
  params device=/export/backup directory=/backup fstype=none options="bind" \\
  op start   interval="0"   timeout="60s" \\
  op monitor interval="10s" timeout="40s" \\
  op stop    interval="0"   timeout="60s"
primitive p_ping ocf:pacemaker:ping \\
  params name="p_ping" host_list="$HA_GATEWAY" multiplier="1000" dampen="5s" \\
  op start   interval="0"   timeout="60s" \\
  op monitor interval="30s" timeout="60s" \\
  op stop    interval="0"   timeout="20s"
primitive p_diskd_root ocf:pacemaker:diskd \\
        params name="p_diskd_root" write_dir="/tmp" interval="10" \\
        op start   interval="0"   timeout="60s" \\
        op monitor interval="10s" timeout="60s" \\
        op stop    interval="0"   timeout="60s"
primitive p_diskd_share1 ocf:pacemaker:diskd \\
        params name="p_diskd_share1" device="/dev/$HA_DEV1" interval="10" \\
        op start   interval="0"   timeout="60s" \\
        op monitor interval="10s" timeout="60s" \\
        op stop    interval="0"   timeout="60s"
primitive p_rpcbind lsb:rpcbind \\
  op monitor interval="30s"
primitive p_nfslock lsb:nfslock \\
  op monitor interval="30s"
primitive p_nfsserver lsb:nfs \\
  op monitor interval="30s"
primitive p_exp_root ocf:heartbeat:exportfs \\
  params fsid="0" directory="/export" \\
  options="rw,sync,crossmnt" \\
  clientspec="$VIP_CLIENTS" wait_for_leasetime_on_stop="false" \\
  op start interval="0" timeout="240s" \\
  op stop  interval="0" timeout="100s"
primitive p_exp_backup ocf:heartbeat:exportfs \\
  params fsid="1" directory="/export/backup" \\
  options="rw,sync,mountpoint" \\
  clientspec="$VIP_CLIENTS" wait_for_leasetime_on_stop="false" \\
  op start   interval="0"   timeout="240s" \\
  op monitor interval="30s" \\
  op stop    interval="0"   timeout="100s" \\
  meta is-managed="true"
primitive p_exp_nfs3 ocf:heartbeat:exportfs \\
  params fsid="2" directory="/backup" \\
  options="rw,sync" \\
  clientspec="$VIP_CLIENTS" wait_for_leasetime_on_stop="false" \\
  op start   interval="0"   timeout="240s" \\
  op monitor interval="30s" \\
  op stop    interval="0"   timeout="100s" \\
  meta is-managed="true"
group g_nfs p_vipcheck p_fs_export p_fs_nfs3 p_rpcbind p_nfslock p_nfsserver p_exp_root p_exp_backup p_exp_nfs3 $P_VIP p_vip
ms ms_drbd_r0 p_drbd_r0 \\
  meta master-max="1" master-node-max="1" clone-max="2" \\
  clone-node-max="1" notify="true" target-role="Started" \\
  is-managed="true"
clone cl_ping p_ping
clone cl_diskd_share1 p_diskd_share1
clone cl_diskd_root p_diskd_root
location lc_nfs g_nfs 100: $HA1_NAME
location lc_ping_disk g_nfs \\
  rule \$id="lc_ping_disk-rule" 100: #uname eq $HA1_NAME \\
  rule \$id="lc_ping_disk-rule-1" -inf: defined p_ping and p_ping lt 100 \\
  rule \$id="lc_ping_disk-rule-2" -inf: defined p_diskd_root and p_diskd_root eq ERROR \\
  rule \$id="lc_ping_disk-rule-3" -inf: defined p_diskd_share1 and p_diskd_share1 eq ERROR
colocation cl_nfs inf: g_nfs ms_drbd_r0:Master
order ord_nfs 0: ms_drbd_r0:promote g_nfs:start
property stonith-enabled="false"
property no-quorum-policy="ignore"
property pe-error-series-max="100"
property pe-warn-series-max="100"
property pe-input-series-max="100"
rsc_defaults migration-threshold="2"
rsc_defaults resource-stickiness="200"
EOF

sudo crm configure load update /etc/ha.d/crm.txt

sudo crm configure show | cat


crm_mon -rfA の実行結果が下記のようになればうまく設定できています。


============
Last updated: Sun Aug 24 16:03:08 2014
Stack: Heartbeat
Current DC: backup12.example.com (1cf3e4ed-919b-84d7-9853-0c46f4854365) - partition with quorum
Version: 1.0.13-a83fae5
2 Nodes configured, unknown expected votes
5 Resources configured.
============

Online: [ backup11.example.com backup12.example.com ]

Full list of resources:

 Resource Group: g_nfs
     p_vipcheck (ocf::heartbeat:VIPcheck):      Started backup11.example.com
     p_fs_export        (ocf::heartbeat:Filesystem):    Started backup11.example.com
     p_rpcbind  (lsb:rpcbind):  Started backup11.example.com
     p_nfslock  (lsb:nfslock):  Started backup11.example.com
     p_nfsserver        (lsb:nfs):      Started backup11.example.com
     p_exp_root (ocf::heartbeat:exportfs):      Started backup11.example.com
     p_exp_backup       (ocf::heartbeat:exportfs):      Started backup11.example.com
     p_fs_nfs3  (ocf::heartbeat:Filesystem):    Started backup11.example.com
     p_exp_nfs3 (ocf::heartbeat:exportfs):      Started backup11.example.com
     p_vip_10_110_88_62 (ocf::heartbeat:IPaddr2):       Started backup11.example.com
     p_vip      (ocf::heartbeat:IPsrcaddr):     Started backup11.example.com
 Master/Slave Set: ms_drbd_r0
     Masters: [ backup11.example.com ]
     Slaves: [ backup12.example.com ]
 Clone Set: cl_diskd_root
     Started: [ backup11.example.com backup12.example.com ]
 Clone Set: cl_diskd_share1
     Started: [ backup11.example.com backup12.example.com ]
 Clone Set: cl_ping
     Started: [ backup11.example.com backup12.example.com ]

Node Attributes:
* Node backup11.example.com:
    + backup12.example.com-eth0         : up
    + backup12.example.com-eth1         : up
    + master-p_drbd_r0:1                : 10000
    + p_diskd_root                      : normal
    + p_diskd_share1                    : normal
    + p_ping                            : 1000
* Node backup12.example.com:
    + backup11.example.com-eth0         : up
    + backup11.example.com-eth1         : up
    + master-p_drbd_r0:0                : 10000
    + p_diskd_root                      : normal
    + p_diskd_share1                    : normal
    + p_ping                            : 1000

Migration summary:
* Node backup11.example.com:
* Node backup12.example.com:

pacemaker の設定をやり直したい場合は、以下のコマンドを両サーバで実行します。heartbeat を停止後初期化しています。


sudo /etc/init.d/heartbeat stop
sudo rm -f $(sudo find /var/lib/pengine/) $(sudo find /var/lib/heartbeat/crm/) /var/lib/heartbeat/hb_generation
cat /dev/null | sudo tee /var/log/ha-log


NFS client を設定します。恒久的な設定ではなく、暫定的な操作です。

NFS 関連パッケージをインストールし、起動します。


sudo yum -y install nfs-utils
sudo sed -i -e 's/^udp6/#udp6/' -e 's/^tcp6/#tcp6/' /etc/netconfig
sudo /etc/init.d/rpcbind start
sudo /etc/init.d/nfslock start


Private IP Address を 10.110.88.59 に変更します。
IP アドレスは適宜置き換えてください。
変更後は、ssh 接続しなおす必要があります。


sudo mkdir /rescue
cat << 'EOF' | sudo tee /rescue/mk_portable_ip
#!/bin/bash
if [ ! "$1" ]; then
  echo Usage: $0  new_portable_private_ip_address  [norestart]
  exit 1
fi
[ -e /proc/net/bonding ] && NIC0=bond0 || NIC0=eth0
NETWORK_123=$(echo $1 | awk -F. '{print $1 "." $2 "." $3}')
NETWORK_4=$(($(echo $1 | awk -F. '{print $4}')&~63))
GATEWAY="$NETWORK_123.$((NETWORK_4+1))"
sed -i -e "s/^IPADDR=.*\$/IPADDR=$1/" /etc/sysconfig/network-scripts/ifcfg-$NIC0
sed -i -e '/^GATEWAY=/d' /etc/sysconfig/network-scripts/ifcfg-$NIC0
sed -i -e "s%^10\\.0\\.0\\.0/8 via.*\$%10.0.0.0/8 via $GATEWAY%" /etc/sysconfig/network-scripts/route-$NIC0
[ "$2" = "norestart" ] || /etc/init.d/network restart
EOF
sudo chmod 755 /rescue/mk_portable_ip

sudo /rescue/mk_portable_ip 10.110.88.59


NFS サーバがエクスポートしているディレクトリをマウントし、ひたすら書き込みを実行します。


sudo mount -t nfs 10.110.88.62:/backup /mnt
for i in $(seq 1 1000000)
do
  echo "[$i] $(date)"
  sudo dd if=/dev/zero of=/mnt/test4.dd bs=1M count=1024
  date
  ls -l /mnt/test4.dd
done


もう一つ端末を開き、NFSv3 でマウントし、ひたすら書き込みを実行します。


sudo mkdir /mnt3
sudo mount -t nfs -o vers=3 10.110.88.62:/backup /mnt3
for i in $(seq 1 1000000)
do
  echo "[$i] $(date)"
  sudo dd if=/dev/zero of=/mnt/test3.dd bs=1M count=1024
  date
  ls -l /mnt/test3.dd
done


backup11 サーバにて、スイッチオーバ(手動フェイルオーバ)を実行します。


sudo crm resource move p_vip 2> /dev/null;sleep 60;sudo crm resource unmove p_vip


client の書き込みが中断しますが、何事もなかったかのように処理が継続されます。
タイミングによりエラーが発生することもあるかもしれません。

0 件のコメント:

コメントを投稿