Raspberry PI シリーズで分散環境構築(その2: PiServer の解析と代替システムの設計まで)

# 序
1. [Raspberry PI シリーズで分散環境構築(その1:モデル別、ディスクレスクライアント化の可否まとめ)](https://qiita.com/p_cub/items/e81dd0f49b3f6fb024a5)
2. [Raspberry PI シリーズで分散環境構築(その2: PiServer の解析と代替システムの設計まで)](https://qiita.com/p_cub/items/69fa32a9a62890ca1d04)
3. [Raspberry PI シリーズで分散環境構築(その3: dnsmasq のインストールと設定)](https://qiita.com/p_cub/items/e7c889b0f92a868a6c20)
4. [Raspberry PI シリーズで分散環境構築(その4: NFSサーバの構築とクライアント用OSのインポート)](https://qiita.com/p_cub/items/dd682de7de28276129e6)
5. [Raspberry PI シリーズで分散環境構築(その5: クラスタノード向け Raspberry PI OS のカスタマイズ(1))](https://qiita.com/p_cub/items/ecf4c48b7ecb08d971b1)
6. [Raspberry PI シリーズで分散環境構築(その6: クラスタノード向け Raspberry PI OS のカスタマイズ(2))](https://qiita.com/p_cub/items/73dc833302c3f064dc39)
7. [Raspberry PI シリーズで分散環境構築(その7: 各ラズパイ向けの tftp ルート設定と起動試験)](https://qiita.com/p_cub/items/ecef742e86ab2991c1b0)
8. [Raspberry PI シリーズで分散環境構築(その8: Webクラスタ構築のケース(前半))](https://qiita.com/p_cub/items/10751e2daa2d3b74c5d5)
9. [Raspberry PI シリーズで分散環境構築(その9: Webクラスタ構築のケース(後半))](https://qiita.com/p_cub/items/c4c837a57e6487a076d4)

本稿は [その1](https://qiita.com/p_cub/items/e81dd0f49b3f6fb024a5)からの続きです。
Raspberry PI 多数持ちの人がディスクレスクライアント化に向けて試行錯誤する中、必ずぶち当たる存在であるソフトウェア、PiServer と代替システム構築に関する内容となります。手持ちのラズパイが PiServer から認識されない、という問題に直面している方は、[その1](https://qiita.com/p_cub/items/e81dd0f49b3f6fb024a5)をご覧ください。

# PiServer の紹介
[公式アナウンスはこちら(英語)](https://www.raspberrypi.org/blog/piserver/)。
[Raspberry PI Desktop](https://www.raspberrypi.org/downloads/raspberry-pi-desktop/)をインストールしたPCを使えば、3B以降のラズパイをディスクレス化できるよ、という謳い文句。

ラズパイはもともと教育用途に作られたものですから、教室で生徒が多数のディスクレスラズパイを使い、
先生は PCで同じ画面を見る、という環境を想定して作られたものっぽいですね。

## というわけで Raspberry PI Desktop を触ってみる
- カーネルは x86_64 の Debian ね。
- glibc が i386 (なぜ???)
- ラズパイと全く同じデスクトップ環境ですな
- 「設定」メニューに "PiServerの設定" なる項目が。これが PiServer ということなんでしょうね。

## PiServer の機能と実現方式を確認
<dl>
<dt>1. ラズパイクライアントの発見</dt>
<dd>ラズパイから発せられる DHCP ブロードキャストを受け取って、MACアドレスを管理対象として登録。 dnsmasq の DHCP 機能が受け取った要求をフックしている。登録した MAC アドレス専用の tftp ルートを準備(管理しているOSの boot ディレクトリへのシンボリックを張っている)</dd>
<dt>2. クライアント用OSイメージのインポート</dt>
<dd>bash スクリプトで実現。イメージファイルの内容をローカルディスクにコピーして、/etc/exports にエントリを追加している。ついでに、ディスクレスクライアントには不要なファイルを削除、ロケール関係をRaspberry PI Desktopを実行しているマシンの値と同じものに書き換えている。また、ローカルディスクをマウントすることになっている /etc/fstab をごっそり書き換えている</dd>
<dt>3. tftp サーバ機能</dt>
<dd>dnsmaq で実現している。GUI から dnsmasq の設定ファイルをいじっている</dd>
<dt>4. DNSキャッシュサーバ/ddns機能</dt>
<dd>dnsmasq で実現している。既に別のDNSサーバがある場合や、/etc/hosts で管理できればいい、といった理由でこの機能が不要な場合は /etc/dnsmasq.conf ファイルでポート番号を0に指定する必要がある</dd>
<dt>5. DHCPサーバ機能</dt>
<dd>dnsmasq で実現。既に別の DHCP サーバが存在する場合は、ブート時に必要となるファイルをダウンロードするための tftp サーバのアドレスのみをクライアントに返す、Proxy DHCPとしても機能</dd>
<dt>6. NFSサーバ機能</dt>
<dd>カーネルに最初から組み込まれているNFSサーバ(ver3)を利用。
クライアント向けにルートファイルシステムを提供。
ディスクレスクライアントと言えども、データを保存したい場合もあるので、ルートファイルシステムのマウントが完了して、ブート処理の最中にマウントするための書き込み可能な共有フォルダも提供している。</dd>
<dt>7. クライアントのOS変更</dt>
<dd>登録済みのラズパイに、どの OS イメージを与えるか管理。 各 MAC アドレス向けの tftp ルートをシンボリックリンクで書き換えているだけ</dd>
<dt>8. ラズパイ上のユーザーアカウント管理</dt>
<dd>利用するメリットがないので詳しく確認していないが、どうやら OpeLDAP で実現している模様</dd>
<dt>9. 管理しているクライアント用OSイメージの変更</dt>
<dd>qemu-arm-static コマンドを利用して、chroot を実行しているだけ。glibc が i386 版であるためか、qemu-aarch64-static コマンドはインストールされていないので、64bit版ディストリビューションの管理はできない。</dd>

## 本当に Raspberry PI Desktop 環境が必要なのか?

[GitHub の piserver リポジトリ](https://github.com/raspberrypi/piserver) に公開されているソースを確認してみると、管理用 GUI の C++ ソースと各種 bash スクリプトがあった。GUI 部分は x86_64 版 ArchLinux でもコンパイル+実行できたので、Raspberry PI Desktop を使う必要はないことが判明。 
しかも、PiServer リポジトリに公開されている bash スクリプトさえ移植してしまえば、残り全ての機能は dnsmasq + OpenLDAP + qemu-user-static だけでも実現できるわけで、結論。

- dnsmasq の設定ファイルを書き換えるだけの GUI なんていらんわ
- PiServer はやっぱりクソ(最終判断)。

# PiServer 代替システムの構築方法
つい先日 Raspberry 公式から [Raspberry PI OS を 64bit 化するよ](https://www.raspberrypi.org/forums/viewtopic.php?f=117&t=275370)というアナウンスが出た中、64bit ディストリビューションを管理できない PiServer は見切りをつける必要があります。ということで代替システムを構築する手法を考えてみます。

## 前提事項: 一般的なディスクレスクライアントの挙動(IPv4 の PXEブート)

### PXE ブートでクライアント+サーバがやっていること(シーケンス)
(参考: https://japan.zdnet.com/article/20089685/ )

1. ディスクもIPを持たないクライアントはブロードキャストを投げて DHCPサーバから IP を取得しようとする
2. DHCP サーバは、クライアントのMAC アドレス等を元に、要求元が登録済みのディスクレスクライアントか否かを判定
4. ディスクレスクライアントではないと判定された場合は、IP等を与えて終了、登録済みのディスクレスクライアントであると判定すると、DHCPサーバは要求元のクライアントにIPを与えた後、次に訪れるべき tftp サーバの IP を教えて DHCP サーバの役目は終了。
1. 自分用の IP を与えられたクライアントは、教えられた tftp サーバにアクセスしてブートに必要なカーネル、関連ファイル群をダウンロードする。起動に必要なファイルを全てダウンロード完了したら、tftp サーバの役目は終了。
2. tftp からダウンロードしたファイルの中には、必ずルートファイルシステムを提供する NFS サーバの場所と共有ディレクトリ名が入っているはずなので、クライアントは指定された共有ディレクトリをルートファイルシステムとして読み取り専用でマウントを試みる。
1. ルートファイルシステムのマウントが完了して、実際の OS 起動がスタートする

### PXEブートを実現するために必要なインフラサーバ群

従って、上記の手順を実現させるためには、最低でも以下の環境を整備する必要があり、これら3つの機能を持つサーバのことを "PXEサーバ" と呼ぶことがあります。

+ DHCP サーバ
+ tftp サーバ
+ NFS等のファイルサーバ

本来、ディスクレスクライアントは、教育現場の生徒用端末や、データ入力業務用端末といった多数のユーザーが同一環境を利用する用途で用いられるので、通常

+ DNS サーバ(クライアントホスト名の自動登録)
+ LDAP/NIS 等組織内認証サーバ
+ ゲートウェイ/ファイアウォール

等を同時に整備する必要があるのですが、本稿は個人用分散処理環境を構築するのが最終目的ですから、下3つのサーバに関する内容は記載しません。
ちなみに、DNS は 100台を超えるようなクライアント数であれば必要でしょうけれども、10に満たないクライアント数では /etc/hosts ファイルによる名前解決で十分で、しかもこのファイルは NFS サーバ上で共有できるので不要ですよね。
ついでに、自分しか使わない分散環境では認証サーバなんかいりませんし、 /etc/passwd ファイルも共通化できるので不要ですよね。

## 実現手段1: PXE サーバ構築に特化したソフト、 dnsmasq で tftp/DHCP/DNS を一括構築
DHCP,tftp,DNSサーバを dhcpd や atftpd, bind といった個別ソフトで構築するのは面倒ですし、時間もかかります。
そこで、PiServer でも利用している dnsmasq というソフトの登場となります。
本来このソフトは DNS キャッシュサーバとして開発がスタートしたソフトなのですが、いつの間にか tftp サーバ,DHCPサーバの機能も取り込んでしまったので、PXEサーバ構築に特化したソフト、と言っても過言ではないでしょう。当然、このソフトを利用することにします。ただし、本来の用途である DNS は使用しない方向で。

以後、dnsmasq が稼動している x86_64 マシンのことを 「PXEサーバ」と呼びます。

## 実現手段2: NFSサーバ機能は PXEサーバから切り離したほうが良い。
PiServer では「PC 1台で完結」を売りにするために、全機能を詰め込んでいましたが、安全性を考えると、NFS サーバ機能は別マシンに切り分けておいたほうがいいです。なぜなら、PXEサーバが NFSサーバも兼ねていると、次のような事態が発生し得るからです。

1. PXEサーバを再起動/シャットダウンすると、稼働中のラズパイのルートファイルシステムがごっそりなくなってしまう。この事態を避けるためには、PXEサーバを再起動する前に全てのラズパイをシャットダウンしておく必要が。
2. PXEサーバにディスク障害が発生したときはもっと悲惨な事態に。

もし既にNFS 対応可能なファイルサーバをお持ちであるならば、 RAID や GlusterFS 等で冗長性が取られているでしょうから、より堅牢なシステムとなります。tftp で配布するブート関連ファイルも PXEサーバから NFS マウントかければ問題ありません。ただ、ディスクアクセスの速いマシンを利用したほうがいいと思います。

以後、NFS機能を持つマシンを 「NFSサーバ」と呼びます。

[^理由]: 既存のファイルサーバをお持ちならば、 RAID や GlusterFS 等で冗長性が取られているでしょうから

## 実現手段3: OS インストール用イメージファイルから NFSサーバへのインポート
これは手動でやっても問題ないでしょう。
ただ、PiServer の GitHub で公開されている OS インポート用 bash スクリプトを改造すれば、自動化が可能かも。

## 実現手段4: クライアント用OSをアップデートするために必要な armhf/aarch64 エミュレータ 
ディスクレスクライアントは、ルートファイルシステムを読み取り専用でマウントしますから、クライアント側から OS のアップデートを行うことができません。PXEまたはNFSサーバ側で OS をアップデートする必要が生じます。
しかしながら、今回構築しようとしている環境はクライアント側がARM,サーバ側は x86_64 マシンとなるはずです。ここで、エミュレータが必要となってくるわけですね。

PiServer でも実装している方法ですが、エミュレータ qemu(ユーザーモードスタティック) と binfmt サポート, chroot を使うと、クライアントに配布する OS を簡単に制御可能となります。[ここ](http://blog.kmckk.com/archives/2342452.html)に詳しく載っています。

Debian 系では qemu-user-static パッケージをインストールするだけ, ArchLinux では AUR で自力でコンパイルする必要があります。

## 実現手段5: クライアントの MAC アドレス管理
ラズパイが10枚以下であれば、[私の以前の記事](https://qiita.com/p_cub/items/b0b4351c52c876aaa095)で記載した方法で個別に確認していっても大したことありません。

## 実現手段6: DNS/ユーザー管理機能
自分しか使わないクライアント群ですから、管理する必要がないので割愛。

- /etc/passwd + /etc/shadow をNFS共有でユーザー管理
- dnqmasq の DHCP 機能で、各ラズパイに固定 IP を割り振る+/etc/hosts をNFS共有で名前解決

することで全て解決します。

# 最終形態
筆者はこのような環境を構築する事にします。なお、PXEサーバ,NFSサーバ,コントローラを1台にまとめても構いませんし、サブネットを分けなくても構いません。
![RaspiCloudSystem.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267238/9d0ab7af-1f13-cf7b-3cc9-9b4e8c6cb4fd.png)


というわけで、今回はここまで。[次回](https://qiita.com/p_cub/items/e7c889b0f92a868a6c20)は、実際に x86_64 Linux マシンに dnsmasq のインストール、設定を行いたいと思います。