ことはじめ

HPCの研究室に所属している割にはHPCっぽいことができていなくて不満なので、自分でHPCぽいことをやることにした。自分のいう「HPCぽさ」ってのは、大規模なデータ分析とか難しい処理を複数ノードを使って効率よくやることとか、まあとりあえずクラスタが好きなんすよ。

ってことでとりあえず手始めにラズパイでHadoopクラスタを構築する。その後kubernetesクラスタや、slurmクラスタも試してみる。 やることは全部で5つある。3つめと4つ目ははHadoopクラスタの構築のためではなく、MPIを使った実行も可能にするためである。勉強にはなる。

1. ラズパイのルータ化
2. クラスタネットワークに属しているノードのIPアドレスを固定
3. ノード間をシームレスで移動できるようにkeychain loginを追加
4. nfsを使ってノード間で共有ディレクトリを作る
5. hadoopの導入

ラズパイのルータ化(やることその1)

大元のLanにはsoftbankのルータを使っているが、このネットワークにラズパイクラスタを置きたくない。なので、ラズパイ一台をルータ兼マスターノードにして新しいネットワーク(172.20.2.0/24)を構築する。

ネットワークの構成

192.168.3.0/24がメインのネットワークで、この中にルータ兼マスターノードをつくる。マスターノードは2つのnicを持つが、 192.168.3.0/24側は、192.168.3.4 新しいネットワーク側(172.20.2.0/24)は172.20.2.1。 そして172.20.2.0/24の中にラズパイクラスタをいっぱい配置する。

必要な道具

ラズパイはether net ポートが1つしかない。そのためラズパイで外部からアクセス可能なLanを作るためにはもう一つ物理的なLanポートが必要になる。これには usb -> ether net変換アダプタを使う。 ifconfigの結果は次のような感じになる。 eth0がもとからついているポートでeth1が追加されたやつ。

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.3.4  netmask 255.255.255.0  broadcast 192.168.3.255
        inet6 fe80::dea6:32ff:fefa:54df  prefixlen 64  scopeid 0x20<link>
        inet6 2400:2413:121:fd00:dea6:32ff:fefa:54df  prefixlen 64  scopeid 0x0<global>
        ether dc:a6:32:fa:54:df  txqueuelen 1000  (Ethernet)
        RX packets 841  bytes 96345 (96.3 KB)
        RX errors 0  dropped 281  overruns 0  frame 0
        TX packets 472  bytes 90115 (90.1 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 18:c2:bf:e9:3b:8d  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0がメインネットワーク側。eth1がクラスタネットワーク側。以下、新しいネットワークを作るための設定

ipフォワーディングの有効化

/etc/sysctl.conf

#...中略

net.ipv4.ip_forward=1

#...以下略

設定の反映

sudo sysctl -p

eth1(cluster network)を固定する。

/etc/dhcpcd.conf

interface eth1
static ip_address=172.20.2.1/24
static routers=0.0.0.0
static domain_name_servers=0.0.0.0

DHCPサーバの導入

sudo apt install -y isc-dhcp-server

dhcpサーバの設定

/etc/dhcp/dhcpd.confにおいて、

#...中略

#コメントアウト
#option domain-name "example.org";
#コメントアウト
#option domain-name-servers ns1.example.org, ns2.example.org;


#有効化
authoritative;

#追記
subnet 172.20.2.0 netmask 255.255.255.0 {
    range 172.20.2.2 172.20.2.99;
    option routers 172.20.2.1;
    option domain-name-servers 172.20.2.1;
    option broadcast-address 172.20.2.255;
    ignore declines;
}

/etc/default/isc-dhcp-server

#...中略

#ターゲットインターフェイスを指定
INTERFACESv4="eth1"

#...略

dhcp serverのデーモン化

sudo systemctl start isc-dhcp-server
sudo systemctl enable isc-dhcp-server

注意:3回目のクラスタ構築の時に、何回やってもisc-dhcp-serverが起動しなかったんだよね。マジでなんでや?ってずっと思ってたんだけど、どうやらethernetではethernetケーブルが接続されてから初めて、nicがオンになるみたいで。つまり、イーサネットケーブルをlanポートに指したらうまくいきます。 ifconfig でもちゃんとeth0に192.168.3.1が割り当てられました。

iptablesコマンドでeth1とeth0のパケットフォワーディニングを有効化させる。これがいわゆるNATだね。

iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

以上の設定を /etc/rc.local に書き込んでマスターノードが再起動されても設定が反映されるようにする。ちなみにrc.localは

Linuxが起動する過程で実行されるシェルスクリプト

スレーブノード側でnicの情報を/etc/network/interfacesに書き込んでipを固定などする(やることその2)

auto eth0
allow-hotplug eth0
iface eth0 inet static
address 172.20.2.10
netmask 255.255.255.0
gateway 172.20.2.1
dns-nameservers 8.8.8.8

以上でipアドレスも固定される。

新たに得られた知見

dhcpサーバが管理しているネットワーク内でも/etc/network/interfacesにipアドレスを書き込むとstatic ipになる。

参考にしたサイト

これ めちゃめちゃ詳しく書いてある。

まず大事な概念としてnicがあるよね。network interfce card。文字通りネットワークのインターフェース。

ifconfig

でデバイスに存在するnicの一覧が見られる。仮想的なnicも存在する。

マスターノードからスレーブノードへの移動をシームレスにする

ssh-keygen -t rsa

このコマンドで秘密鍵と公開鍵のペアができる。

ssh-copy-id username@ip_address

で作った公開鍵を任意のホストに任意のユーザの ./ssh/authorized_keysに転送できる。 以後、公開鍵を持っているホストにsshするときはパスワードではなく鍵のパスフレーズでログインできるようになる。 (ちなみに、ここでパスフレーズをなしにすると、パスフレーズも打たなくてよくなるので、以下の設定が無駄になる) しかし、パスフレーズを打つのも面倒な人向けに、いいコマンドがある

sudo apt-get install keychain

でインストールし、

.bashrcに次のスクリプトを追記

# Logic for keychain
/usr/bin/keychain $HOME/.ssh/id_rsa
source $HOME/.keychain/$HOSTNAME-sh

これは、内部的には ssh-addで秘密鍵とパスフレーズを登録し、ssh-agentが自動でパスフレーズを入力してくれているだけ。

マスターノードにスレーブノードからマウント可能なディレクトリを作る

これは学ぶことが多いですね。 まあ、かんたんに言うと、nfsがかんたんに作れるんですよって話。はい。なんかわざわざnfsとか買っている人いるけど、実はnfsって 知識さえあれば誰でも作れるんだよね。これは驚きだよね。まあ、先に進みましょう。

  1. 必要なツールのインストール
sudo apt-get install nfs-common nfs-kernel-server
  1. エクスポートディレクトリの作成
sudo mkdir /cluster_common
  1. エクスポートディレクトリをnfs-kernel-serverに知らせるため、/etc/exportsを編集 の前に、sudo systemctl enable rpcbind

をしておくこと!!いや、最近はいらないらしい。というのもrpcは脆弱性が見つかっているらしくてね。 まあ参考文献は

こちら

# 中略
# cluster_common
/cluster_common 172.20.2.0/24(rw,sync)

参考文献

  1. nfs-kernel-serverのデーモン化&リスタート
sudo systemctl enable nfs-kernel-server
sudo systemctl reload nfs-kernel-server
  1. ファイアウォールが有効化されている場合は、nfs用のポート(2049)を開ける
sudo ufw allow nfs
sudo ufw reload 
  1. スレーブノード側でエクスポートされたディレクトリをマウントする(のまえに、スレーブ側でもマウントポイント作ってね)
sudo mount 172.20.2.1:/cluster_common /cluster_common
  1. 自動マウントのため,fstabファイルを編集する必要がある。
172.20.2.1:/cluster_common      /cluster_common nfs     defaults,rw,exec        0       0: