読者です 読者をやめる 読者になる 読者になる

標準出力

新しいもの、変わらないこと 自分の頭を通して考えてみました (stdout)

Building Bewulf type PC cluster

Bewulf型PCクラスタを構築してみる。
目標は、
 「MPIライブラリを使ったサンプルプログラムを複数ノードで実行する」

今回構築するクラスタの概要は、
*ヘッドノード、スレーブノード2ノードの計3ノード
*すべてのノードは、CentOS release 6.4 minimal
*ヘッドノードは、/home のみをNFSにて共有する(ディスクレスに挑戦したかったけどまた今度

ネットワークは、下図の様になる。

192.168.200.0/24がクラスタ専用のネットワークです。

各ノードのスペックは、

node name      CPU                       RAM         HDD
bwhead       amd64 (1 core)*1     2 Gbyte       50Gbyte x 2*2
bwslv01      amd64  (1 core)     1 Gbyte       50 GByte
bqslv02      amd64  (1 core)     1Gbyte        50 GByte

*1 型名になっていないのは、今回構築したノードすべてが仮想マシンだからです。
*2 /home 用に1台、/用に1台



-目次-

[0] HeadノードへのOSのインストール
一番上の項目を選択
イメージをマウントしてますが、メディアテスト

Testを選択

OK



Continueを選択

OK

Next

Engilish

キーボードレイアウトの選択英字配列キーボードを使ってます。

Basic strage device


Yesを選択

ホスト名 ここでは、間違っていたので後でbwheadに修正しました。



root のパスワード

パーティション構成を決めます

今回は、このように切ることにしました

Formatを押下

Write changes to diskを押下

Nextを押下


インストール中です

インストール完了 再起動します

再起動後 ログイン状況


[1] Head ノードの設定

A) ネットワークインターフェースの設定
前述のネットワーク構成図に沿って設定します。
/etc/sysconfig/network-scripts/ifcfg-eth0
ONBOOT=yes
BOOTPROTO=dhcp

/etc/sysconfig/network-scripts/ifcfg-eth1
ONBOOT=yes
BOOTPROTO=static
IPPADDR=192.168.200.1
NETMASK=255.255.255.0


B) /etc/hosts の編集
以下を追加
192.168.200.1 bwhead
192.168.200.2 bwslv01
192.168.200.3 beslv02
上記の編集を反映させるためにネットワークサービスを再始動
/etc/init.d/networking restart

C) DHCPサーバーのインストール
slaveノードへのOSのインストールは、物理マシンでの構築の演習としてPXEによるネットワークブートとします。ネットワークブートでは、ブートローダーの場所等の情報を配布するのにDHCPを用います。そこでDHCPサーバーを構築します。

yum list dhcp
でパッケージを検索

yum install dhcp
そして、設定ファイルを作成
---- /etc/dhcp/dhcpd.conf ------

#
# DHCP Server Configuration file.
#   see /usr/share/doc/dhcp*/dhcpd.conf.sample
#   see 'man 5 dhcpd.conf'
#

DHCPDARGS=eth1;

# network boot setttings
allow booting;
allow bootp;
option option-128 code 128 = string;
option option-129 code 129 = text;
next-server 192.168.200.1;
filename "pxelinux.0";


subnet 192.168.200.0 netmask 255.255.255.0{

  # default gateway
  option routers                192.168.200.1;
  option subnet-mask            255.255.255.0;

  option domain-name-servers    192.168.100.1;

  range 192.168.200.100 192.168.200.254;
  default-lease-time 21600;
  max-lease-time 43200;

  host bwslv01{
    hardware ethernet 08:00:27:9C:25:55;
    option host-name "bwslv01";
    fixed-address 192.168.200.2;
  }
 
  host bwslv02{
    hardware ethernet 08:00:27:29:4E:37;
    option host-name "bwslv02";
    fixed-address 192.168.200.3;
  }

   
}

------------------------------------



設定ファイルの構文チェック
service dhcpd configtest
service dhcpd start
chkconfig dhcpd on

dhcpの使うポートを開けておく
iptables  -I INPUT -i eth1 -p udp --dport 67:68 --sport 67:68 -j ACCEPT
再起動時に設定が無効にならないように
/etc/init.d/iptables save
ファイヤーウォールの再起動
/etc/init.d/iptables restart


D) tftpサーバーのインストール
ネットワークブートにおいてブートローダ等を配布するのに必要

yum install tftp tftp-server
/etc/xinetd.d/tfptd
chkconfig xinetd on
service xnetd start

chkconfig tftp on

E) slave ネットワークブートのための準備
syslinuxをインストールします。
yum install syslinux

PXEブートにブートローダ関係の必要なファイルをtftpの公開ディレクトリにコピーします。
cp /usr/lib/syslinux/pxelinux.0 /var/lib/tftpboot
cp /usr/lib/syslinux/menu.c32 /var/lib/tftpboot
cp /usr/lib/syslinux/memdisk /var/lib/tftpboot
cp /usr/lib/syslinux/mboot.c32 /var/lib/tftpboot
cp /usr/lib/syslinux/chain.c32 /var/lib/tftpboot

OS関係の必要なファイルをtftpサーバーの公開ディレクトリに取ってきます。
yum install wget
mkdir -p /tftpboot/images/centos/x86_64/6.4
cd /var/lib/tftpboot/images/centos/
wget http://linux.mirrors.es.net/centos/6.4/os/x86_64/images/pxeboot/initrd.img
wget http://linux.mirrors.es.net/centos/6.4/os/x86_64/images/pxeboot/vmlinuz

ブートローダメニューの設定ファイルを作成
---/var/lib/tftpboot/pxelinux.cfg/default---

default menu.c32
prompt 0
timeout 300
INTIMEOUT local

MENU TITLE PXE Menu

LABEL local
MENU LABEL Boot from local hard disk drive
LOCALBOOT 0

LABEL CentOS 6.4 x86_64
MENU LABEL CentOS 6.4 x86_64
KERNEL images/centos/6.4/x86_64/vmlinuz
APPEND load initrd=images/centos/6.4/x86_64/initrd.img devfs=nomount


--------------------------------------



tftp(udp 69番ポート)を開ける
iptables -A INPUT -m state --state NEW -i eth0 -p udp --dport 69 -j ACCEPT
再起動時に設定が無効にならないように
/etc/init.d/iptables save
ファイヤーウォールの再起動
/etc/init.d/iptables restart

フォワーディングを有効にする
-- /etc/sysctl.conf--
# Controls IP packet forwarding
net.ipv4.ip_forward = 1   # 0 から 1に変更
----------------------


[2] slavve ノードのOSインストール
仮想マシンを起動したら即座にF12キーを押下する

PXEブートするために「l」キーを押下する

予め行った設定が適切に行われていれば
tftpサーバーからブートロードがDLされてメニューが表示される
CentOSを選択して、Enterを押下
インストール中に用いる言語の選択

キーボードレイアウトの選択

OSインストーラーのメディア種別を選択。セキュリティ的には、
あまり宜しくないけどHTTPで取ってきます。

ネットワーク設定
IPv4は、DHCPにします。

NIC設定中

インストーラーイメージ取得中

これ以降は、Headノードと同じGUIインストーラーが起動しての同じインストールとなる。



[3] ssh でのhead から slave へのパスワード無しログイン
MPIライブラリのデータの移動、設定ファイルの配布のための仕組みを構築します。
よくr系コマンドが用いられますが、自分の環境では、rootでのパスワード無しログインが
できるようにすることを断念したため、sshを用います。

A) slave ノードへssh-server のインストール
yum install openssh-server
scpを使うため
yum install openssh-client


/etc/ssh/sshd_configの以下のコメントをはずす
#PermitRootLogin yes -> PermitRootLogin yes

chkconfig ssh on
service sshd start

試しにrootで全てのslaveノードにログインしてみる

ssh root@192.168.200.n # n は、整数
ログインしたまま後の作業の準備
cd $HOME
mkdir .ssh


B) head ノードでの作業

公開鍵生成

ssh-keygen -b 1024 -t rsa
鍵のパスフレーズは空にしておく

公開鍵を全てのslaveノードに配布しておく。
scp ~/.ssh/id_rsa.pub root@192.168.200.n:.ssh/authorized_keys

クラスタは、外からの開始される接続を許可しないネットワーク内で運用するのでとりあえずSElinuxは無効化しておく。
setenforce 0
そして、起動後も無効になるように/etc/selinux/configのSELINUXTYPEを下記のようにdisabledに変更しておく。
SELINUXTYPE=diabled


C)シェルスクリプトの作成

各ノードに同様の実行するためのシェルスクリプトを用意( rshでも実現可能だが自分の環境では、rootでの実行がPermission Denied ど言われで実現できなかった


----${HOME}/utils/rssh.sh-----

#!/bin/bash
BEGIN_ADDR=2
END_ADDR=3
ADDR_PREFIX="192.168.200."

for i in `seq $BEGIN_ADDR $END_ADDR`
do
  DST_ADDR="$ADDR_PREFIX$i"
  echo "Processing for $DST_ADDR"

ssh $DST_ADDR<
$*
EOF

done

---------------------------
chmod 744 ${HOME}/utils/rssh.sh

各ノードにファイルコピーするためのコマンド
---${HOME}/utils/rsscp.sh---

#!/bin/bash
SRC_FILE=$1
DST_PATH=$2

BEGIN_ADDR=2
END_ADDR=3

ADDR_PREFIX="192.168.200."

for i in `seq $BEGIN_ADDR $END_ADDR`
do
  DST_ADDR="$ADDR_PREFIX$i"
  echo "Copying $SRC_FILE -> $DST_ADDR:$DST_PATH"

scp $SRC_FILE $DST_ADDR:$DST_PATH

done

--------------------------

D) /etc/hosts の配布

/etc/hosts を作成して
 ${HOME}/utils/rsscp.sh /etc/hosts /etc/hosts


[4] NIS を用いたアカウント一元管理

A) サーバーの構築

アカウントを一括管理するためにNISサーバーを構築する

まずは、サーバーのインストール
yum install ypserv

ドメインの設定 このドメインは、DNSとは関係がない
ypdomainname clnet

/etc/sysconfig/network に 先ほど設定したNISドメインを追加
NISDOMAIN = clnet

/var/yp/Makefile の編集(下記がオリジナルのファイルとの差分)
-----差分-----------------------

*** Makefile.org 2013-04-27 17:41:09.642037547 +0900
--- Makefile 2013-04-27 17:42:41.594036564 +0900
***************
*** 39,49 ****
 
  # Should we merge the passwd file with the shadow file ?
  # MERGE_PASSWD=true|false
! MERGE_PASSWD=true
 
  # Should we merge the group file with the gshadow file ?
  # MERGE_GROUP=true|false
! MERGE_GROUP=true
 
  # These are commands which this Makefile needs to properly rebuild the
  # NIS databases. Don't change these unless you have a good reason.
--- 39,49 ----
 
  # Should we merge the passwd file with the shadow file ?
  # MERGE_PASSWD=true|false
! MERGE_PASSWD=false
 
  # Should we merge the group file with the gshadow file ?
  # MERGE_GROUP=true|false
! MERGE_GROUP=false
 
  # These are commands which this Makefile needs to properly rebuild the
  # NIS databases. Don't change these unless you have a good reason.
***************
*** 114,120 ****
  # If you don't want some of these maps built, feel free to comment
  # them out from this list.
 
! all:  passwd group hosts rpc services netid protocols mail \
  # netgrp shadow publickey networks ethers bootparams printcap \
  # amd.home auto.master auto.home auto.local passwd.adjunct \
  # timezone locale netmasks
--- 114,120 ----
  # If you don't want some of these maps built, feel free to comment
  # them out from this list.
 
! all:  passwd shadow group hosts rpc services netid protocols mail \
  # netgrp shadow publickey networks ethers bootparams printcap \
  # amd.home auto.master auto.home auto.local passwd.adjunct \
  # timezone locale netmasks

--------------------------------


このままだとすべてのホストからNIS情報を引き出すことができるようになっているので
NIS情報を引き出せるホストを限定するために /var/yp/securenets を作成して
以下を書き込みます。
255.255.255.0 192.168.200.0


これで指定したネットワークに属するホストだけがNIS情報を引き出せるようになりました。
ここでサーバーデーモンの起動
/etc/rc.d/init.d/ypserv start
/etc/rc.d/init.d/yppasswdd start

そして、起動時に自動でデーモンが走るように以下を実行
chkconfig ypserv on
chkconfig yppasswdd on

/usr/lib64/yp/ypinit -m を実行
NISサーバーの情報を確認される。今回は、サーバーは1台体制(冗長化無し)なのでNISDOMAINで設定した内容が表示されていればおk

B) ファイヤーウォールの設定
portmapper が使う tcpudp 111番ポートへの通信を受け入れるようにしておく。


C ) クライアントの準備 (サーバーマシンでも実行する)
./rssh.sh  ' echo "NISDOMAIN = clnet" >> /etc/sysconfig/network '
./rssh.sh "sed -ei 's/\(USENIS=\)no/\1yes/' /etc/sysconfig/authconfig "
./rssh.sh 'echo "domain clnet server bwhead" > /etc/yp.conf'

slaveノード用のNS設定ファイルを作成して配布する。
mkdir tmp
cd tmp
cp /etc/nsswitch.conf tmp.conf
スレーブ用設定ファルの変更。以下がオリジナルのファイルとの差分
------差分----------

*** /etc/nsswitch.conf 2013-04-29 15:43:35.280253996 +0900
--- tmp.conf 2013-05-06 22:59:03.979813909 +0900
***************
*** 30,38 ****
  #shadow:    db files nisplus nis
  #group:     db files nisplus nis
 
! passwd:     files nis
! shadow:     files nis
! group:      files nis
 
  #hosts:     db files nisplus nis dns
  hosts:      files dns nis
--- 30,38 ----
  #shadow:    db files nisplus nis
  #group:     db files nisplus nis
 
! passwd:     nis files
! shadow:     nis files
! group:      nis files
 
  #hosts:     db files nisplus nis dns
  hosts:      files dns nis

--------------------
cd
./rscp.sh ./tmp/tmp.conf /etc/nsswitch.conf

ypbind をインストールする
./rssh.sh 'yum -y install rpcbind'
./rssh.sh '/etc/rc.d/init.d/rpcbind start'
./rssh.sh 'chkconfig rpcbind on'

./rssh.sh 'yum -y install ypbind'
./rssh.sh '/etc/rc.d/init.d/ypbind start'
./rssh.sh 'chkconfig ypbind on'


D) ユーザーの追加 (適宜)
NISサーバーにて
useradd newuser_name
passwd newuser_name

以上で通常通りユーザーを追加した後

cd /var/yp
make

NIS DBに追加したユーザーの情報を追加する。
これでもログイン出来ない場合は、まずクライアントマシンで
ypcat passwd して追加したユーザーの情報が反映されれているかチェック。

追加されているにもかかわらずログイン出来ない場合は、
/etc/ypserv.conf中の
files: 30

files: 0
に変更してキャッシュを無効にする。


[5] NFS の構築

すべてのノードでホームディレクトリを共有できるようにする。

A) サーバーの構築

yum -y install nfs-utils

共有するディレクトリに関する設定を行う /etc/exports に以下を追加

/home 192.168.200.0/24(rw,sync,no_root_squash,no_all_squash)

/home … 共有するディレクトリの指定
192.168.200.00/24 … 共有を許すネットワーク
sync … 遅延書き込みをしない
no_root_squash … root の特権を行こうにする
no_all_squash … そのままの権限でアクセスさせる

/etc/idampd.conf にドメインの設定をする。デフォルトでは、「Domain = 」を含む行がコメントアウトされているので有効にしてドメインを記述する。

Domain = clnet


起動していないデーモンを起動しておく
/etc/rc.d/init.d/rpcbind start
/etc/rc.d/init.d/nfslock start
/etc/rc.d/init.d/nfs start

起動時にデーモンが自動で起動するようにしておく

chkconfig rpcbind on
chkconfig nfslock on
chkconfig nfs on


B) クライアントの準備

サーバーマシンからシェルスクリプトを用いて実行する

./rssh.sh 'yum -y install nfs-utils'

先ほど編集したNFSサーバーの /etc/idamp


./rssh.sh '/etc/rc.d/init.d/rpcbind start'
./rssh.sh '/etc/rc,d/init.d/nfslock start'
./rssh.sh '/etc/rc.d/init.d/netfs start'

./rssh..sh 'chkconfig rpcbind on'
./rssh.sh 'chkconfig nfslock on'
../rssh.sh 'chkconfig netfs on'


ここからは、各ノードに直接ログインして操作する
まずは、サーバーのパーティションをマウントできるかをテスト


mount -t nfs bwhead:/home /home

df -h

でマウントされたかどうかを確認する。

次に起動時に自動でマウントされるように/etc/fstab を変更
以下の行を追記
bwhead:/home /home nfs bg,intr 0 0

bg… NFSでのマウントが失敗した時にバックグランドで試行を繰り返す。
intr … 停止しているプロセスをkillするために、割り込みを可能にする。
0 … dump頻度
0 … fchkパスのフィールド

さらにインストール時に切った/home のパーティションをマウントしないようにコメントアウトしておく。
これ以上ができたNFSクライアントマシンを再起動して無事にマウントされるかを確認しておく。


[6] OpenMPI のインストール(headノード含めすべてのノードで)
その前にgcc とg++ ,makeのインストール

yum -y install gcc
yum -y install gcc-c++
yum -y install make

今回は、OpenMPI Ver.1.6.4 を用いる。
wget http://www.open-mpi.org/software/ompi/v1.6/downloads/openmpi-1.6.4.tar.gz
cd openmpi-1.6.4
./configure --prefix=/usr/local
make all # 複数コアある場合は make -j num_proc all で並列コンパイルできるらしい

[7] サンプルプログラムの実行

実行用専用ユーザーをNISサーバーにて作る
useradd cltest
passwd cltest
NIS DBへの反映
cd /var/yp ; make

ヘッドノードにてログアウトしてcltestでログインする
以下のソースを作成
-----main.c------------

#include
#include

int main(int argc, char **argv){
int rank, size, namelen;
char name[256];

MPI_Init(&argc;, &argv;);
MPI_Comm_rank(MPI_COMM_WORLD, &rank;);
MPI_Comm_size(MPI_COMM_WORLD, &size;);
MPI_Get_processor_name(name, &namelen;);
sleep(5);
printf("This is %d of %d on %s\n", rank, size, name);
MPI_Finalize();
return 0;
}

----------------------

mpicc main.c
コンパイル


実行前にライブラリサーチPATHをbashrcに追加
export LD_LIBRARY_PATH=/usr/local
source .bashrc


そして、root権限を得て/usr/local/etc/openmpi-default-hostfile (headノード)
にどのユーザーのジョブでも常に実行させたシステム共通の計算ノードを追記する。
以下例
bwhead
bwslv01
bwslv02

本来なら、ヘッドノードは、ジョブ実行のみで計算は行わないがホストPCのリソースがそんなに潤沢ではないためヘッドノードも追加した。


mpirun -np 3 a,out

これで下記の様に各ノードでの出力が表示されればクラスタ構築一応完了。
---実行結果-----

This is 0 of 3 on bwhead.clnet
This is 1 of 3 on bwslv01
This is 2 of 3 on bwslv02

----------------



[7]参考
http://kuni255.blogspot.jp/2013/04/iptables.html