Building Mini-Supercomputer with NanoPi-NEO

# Abstract
I describe how to build mini-supercomputer(cluster) with FriendlyElec's NanoPi-NEO linux computers.
I assume that the OS is installed on NanoPi-NEO.

1. Installing openMPI
2. Assigning fixed IP address for nodes
3. Copying public-key for SSH

# はじめに
Linuxが動作する小さなコンピュータ、Raspberry Piでクラスタを組んでスーパーコンピュータ化するのが一部で人気のようで、共立出版から書籍も出ています。
Raspberry Piは少し高価なので、より安価なNanoPi NEOでクラスタを組んでスーパーコンピュータ化してみましたので次のとおり報告します。

# 用意するもの

1. NanoPi NEO(8台用意しました)
2. マイクロSDカード(NanoPi NEOの数だけ必要です)
3. 100Base-TXのスイッチングHUB
4. 短いLANケーブル(自作。NanoPi NEOの数だけ必要です)
5. 5V 20Aの電源(手持ちを利用)

バラックセットでも構いませんが、ショートさせると怖いので筆者は木の箱に組み込みました。

LANケーブルは短いのがノードの数だけ必要になります。市販されているものを使ってもかまいませんが、箱の後ろでケーブルのあまりがとぐろを巻いてあまり美しくないので自作をお勧めします。

電源はもちろんACアダプタをノードの数だけ買ってきてスイッチつきのテーブルタップに突っ込んでもいいのですが、手持ちにジャンクの5V電源の大きいのがありましたのでそれを利用しました。

もちろんNanoPi-NEO2でも同様に作れます。この場合はLANが1000Base-T(NEOは100Base-TX)なので、スイッチングHUBを1000Base-T対応のものにすると幸せになれると思います。

# セットアップ手順
まず親となるノード上で必要なセットアップをします。全ノードが同じ環境で動く必要があるので、親ノードでセットアップを済ませたあとそのOSイメージをコピーして増やすことにします。

## 必要なパッケージのインストール
openMPIやOpenBLASをコンパイルする際必要になるソフトウェアパッケージを次のとおりインストールします。

$ sudo apt-get install build-essentials automake autoconf m4
$ sudo apt-get install gfortran
$ sudo apt-get install nfs-kernel-server nfs-common

FORTRANコンパイラ(gfortran)はあとでOpenBLASをコンパイルする際必要になりますのでこの段階でインストールします。

MPIによる並列実行では計算に関与する全てのノードの同一のパスに実行ファイルが存在している必要がありますので、ディレクトリを共有するためのNFS関連のパッケージも必要になります。

## openMPIのコンパイル
openMPIは下記URLからダウンロードできます。筆者はバージョン4.0.0を使用しました。
https://www.open-mpi.org/software/ompi/v4.0/
ソースのTarballをダウンロードしたら解凍したあと、

$ ./configure
$ make -j4

でコンパイルします。コンパイルには約1時間ほどかかります。
正常にコンパイルができたら

$ sudo make install
$ sudo ldconfig

でインストールします(/usr/local以下にインストールされます)。

## 各ノードのIPアドレスを固定する
後で改めて説明しますが、MPIによる並列実行ではSSHを用いて各ノード上の実行ファイルを起動します。このため、IPアドレスを固定しておく必要があります。

/etc/network/interfacesファイルを編集し、固定のIPアドレスを設定します。今回は「169.254.128.1」から連番でアドレスをふりましたが、お部屋のネットワークの設定に合わせてください。

/etc/hostnameファイルを編集し、ホスト名を決めます。今回は往年の日立のスパコン「HITAC S-810」にちなんで「S810-1」から連番で名前を決めましたが、好きな名前でかまいません。

/etc/hostsファイルを編集し、ホスト名とIPアドレスの対応表を作成します。

169.254.128.1 S810-1
169.254.128.2 S810-2
(以下同様に追加)

## OSイメージを吸い出す
上記手順をノードの数だけ繰り返しても良いのですが、ノードの数が多いので、このへんでOSイメージを吸い出して保存しておくと楽です。(Linuxが動く別のコンピュータで行います)

マイクロSDカードは同じ銘柄、同じ公称容量でもセクタ数が異なるため、rootパーティションを適宜縮めてから吸い出します。方法については適当に調べてください。

## 子機のマイクロSDカードを作成する
上記で吸い出してあるOSイメージをddなどでマイクロSDカードにコピーして子機のマイクロSDカードを作成します。

コピーしたらIPアドレスとホスト名を変更します。

## 共有ディレクトリのセットアップ
MPIで並列実行するには、各ノード内で同じパスに実行ファイルがある必要があります。

各ノードにコンパイル済みバイナリをコピーしてもかまわないのですが、面倒なので親機の特定のディレクトリを共有することとします。

今回は親機の/media/share以下をNFSで共有します。

### 親機の設定
/etc/exportsファイルを編集し、次の行を追加します。(親機の/media/share以下を共有するようにします)

/media/share 169.254.128.0/16(rw)

アドレス部分はご自分のネットワーク環境に合わせてください。

### 子機の設定
/etc/fstabファイルを編集し、次の行を追加します。

S810-1:/media/share /media/share nfs defaults 0 0

上記作業が終わったら正常にマウントできるか試してみましょう。
その前にpingで各ノードに名前でアクセスできるか、sshでログインできるか確かめておいてください。

各子機上で

$ sudo mount -a

を実行して親機のディレクトリをnfsでマウントします。マウントできたかどうかは

$ df

で確認できます。マウントできていれば、共有ディレクトリの読み書きモードを「誰でも読み書き実行可能」にしておきます。

## SSHの公開鍵設定(親機)
MPIはssh経由でリモートマシン上のプログラムを実行させることでプロセス並列実行を行います。

このため、親機から子機にパスワードなしでsshできるようにしておく必要があります。
そうなってないとmpiexecで実行したときに

「これこれのノードに接続できません」

なエラーが発生してプログラムの実行ができません。

$ ssh-keygen

で親機の公開鍵を作成します。途中暗号の種類やパスフレーズの入力を求められますが、全部ENTERキーを押して進めます。

鍵ファイルができたらssh-copy-idで各子機に鍵をコピーします。

$ ssh-copy-id pi@S810-2

鍵をコピーしたら、親機から子機にパスフレーズなしでsshログインできるかテストします。初回のみ「yes/no」で何やら聞いてきますが、yesで応答すれば次回以降は聞かれません。

$ ssh S810-2

で子機のシェルプロンプトが出れば成功です。

# テストしよう
親機上で適当なCプログラムを書きます(ただのHello, Worldで結構です)。

プログラムが書けたら次のコマンドでコンパイルします。

$ mpicc -o hello hello.c

コンパイルできたら次のコマンドで実行します。

$ mpiexec -H S810-1,S810-1,S810-1,S810-1,S810-2,S810-2,S810-2,S810-2 ./hello

-H の後ろにはプログラムを実行させるホスト名を並べます。NanoPi-NEOは4コアのCPUを搭載しているので、上のように同じホスト名が4個ずつ続きます。

うまくいけば子機上でもプログラムが実行され、-Hオプションで指定した並列数だけ「Hello, World」が表示されるはずです。

MPI並列実行の場合、子機の標準出力はmpiexecコマンドを実行した親機に転送されます。

# まとめ
安価なLinuxコンピュータ、NanoPi-NEOを並列化してミニスパコンを構築する方法について書きました。

思ったより手軽に作れますので試してみてはいかがでしょうか。

次回はMPI並列プログラムを実行してその威力を確認しようと思います。