NFSで構築するk3s共有ストレージ環境：Raspberry Pi 5クラスタリング活用法

# はじめに
[前回](https://qiita.com/kewton/items/7dd3192eba0660edfdb0)の記事の改良版です。前回の構成では、各ノードが独自に永続ストレージを持つため、ノード間でファイルの共有ができませんでした。今回は、NFSサーバーを使用して、各ノードが共通の永続ストレージを利用できるように設定する方法を紹介します。

## 前提条件
- 2台のRaspberry Pi 5（Rpi1およびRpi2）
- 両方にUbuntu 24.04がインストール済み
- Rpi1をマスターノード、Rpi2をワーカーノードとしてk3sクラスタを構築済み
- Rpi1の `/mnt/my_ssd/` に外付けSSDをマウント済み
- k3sの永続化ストレージ用に `/mnt/my_ssd/k3s_storage` を作成済み
- マスターノードとワーカーノードは192.168.11.0/24ネットワーク内に配置
- マスターノードのIPアドレスは192.168.11.8

## ゴール
### 完成イメージ
この構成により、Raspberry Piクラスタ上で動作するアプリケーションは、単一の永続ストレージ領域を通してデータをやり取りできるようになります。例えば、Node1で生成されたファイルをNode2が直接読み込んだり、編集したりすることが可能です。NFSサーバーをマスターノードに配置し、そのストレージをクライアントノードからもマウントすることで、すべてのノードでデータの共有が可能となります。

### 利用イメージ
このような共有ストレージを利用することで、例えば以下のようなシナリオが実現可能です：

- **ログやデータの共有**：各ノードで動作するアプリケーションのログファイルや生成データをNFSストレージに保存し、全ノードからアクセスすることで、ログ解析やデータ処理を一元化できます。
- **アップロードファイルの保存**：ユーザーがアップロードしたファイルをNFSストレージに保存することで、複数のノードで同じデータにアクセス可能となり、スケーラビリティの高いシステムが構築できます。
- **マルチノード環境でのデータ共有**：データが1つのストレージに集約されるため、ノード間でのデータ同期が不要になり、複数ノード間のファイル共有がシームレスに行えます。

この共有ストレージは、Kubernetesの永続ボリューム（PV）として設定し、Podで使用することで、コンテナ間でのデータ永続化も実現します。NFSを活用した共有ストレージは、軽量かつシンプルな構成でデータ共有の効率を高め、Raspberry Piクラスタをより有効に活用する手助けとなります。

## NFSサーバーについての補足
### NFSサーバーについて
NFS（Network File System）は、LinuxやUNIX環境で標準的に使われるネットワークファイルシステムで、ローカルディレクトリをネットワーク経由で共有し、複数のクライアントから同じファイルシステムにアクセスできます。これにより、異なるサーバー間でデータ共有やリモートファイルへのアクセスが可能になります。

NFSの主な特徴：
- **ファイル共有が簡単**：ネットワーク越しに複数のクライアントが同じファイルにアクセス可能。
- **設定がシンプル**：簡単な設定で共有フォルダやアクセス権の管理ができる。
- **高い互換性**：多くのLinuxディストリビューションで標準対応。

### NFSサーバーを使用する理由
Raspberry Pi 5で構築するk3sクラスタでNFSサーバーを使う理由は以下の通りです：

1. **共通ストレージの提供**：NFSで各ノード間でファイルを共有し、一貫性を保てます。
2. **コスト効率**：シンプルな構成でRaspberry Pi上でも動作し、低コストでファイル共有が可能。
3. **Kubernetesとの相性**：Kubernetesの永続ボリューム（PV）として簡単に利用でき、データを一貫して管理できます。
4. **軽量なアクセス**：ネットワーク帯域やCPUリソースを抑えながら、複数ノードで効率的にファイル共有が可能。

これらの理由から、NFSサーバーは、今回のRaspberry Pi 5とk3sクラスタでの共通ストレージに最適な選択です。

# 1. NFSサーバーとクライアントの設定
## 1-1. マスターノードの設定

### 1-1-1. NFSサーバーのインストール
NFSサーバーをインストールし、共有ディレクトリのアクセス権を設定します。
```bash
sudo apt-get install nfs-kernel-server
sudo chown nobody:nogroup /mnt/my_ssd/k3s_storage
sudo chmod 777 /mnt/my_ssd/k3s_storage
```

### 1-1-2. /etc/exportsファイルの編集
NFSで共有するディレクトリと許可するクライアントを設定します。
```bash
sudo vi /etc/exports
# 以下を追加
/mnt/my_ssd/k3s_storage 192.168.11.0/24(rw,sync,no_subtree_check)
```

### 1-1-3. 設定の再読み込み
NFS設定を有効化します。
```bash
sudo exportfs -v
```

### 1-1-4. NFSサーバーの再起動
設定を反映させるため、NFSサーバーを再起動します。
```bash
sudo exportfs -a
sudo systemctl restart nfs-kernel-server
```

### 1-1-5. ファイアウォールの設定
ファイアウォールでNFSの通信を許可します。
```bash
sudo ufw allow from 192.168.11.0/24 to any port nfs
sudo ufw reload
```

## 1-2. ワーカーノードの設定
### 1-2-1. NFSクライアントのインストール
ワーカーノードにNFSクライアントをインストールします。
```bash
sudo apt-get install nfs-common
```

### 1-2-2. 共有ディレクトリのマウント
NFSサーバーの共有ディレクトリをローカルにマウントします。
```bash
sudo mkdir /mnt/nfs
sudo mount 192.168.11.8:/mnt/my_ssd/k3s_storage /mnt/nfs
```

### 1-2-3. 再起動時に自動マウントを設定
`/etc/fstab`にエントリを追加し、再起動後も自動でマウントされるようにします。
```bash
sudo vi /etc/fstab
# 以下を追加
192.168.11.8:/mnt/my_ssd/k3s_storage  /mnt/nfs  nfs  defaults  0  0
```

### 1-2-4. 設定の確認
自動マウント設定が反映されているか確認します。
```bash
sudo mount -a
df -h
```

# 2. 永続ボリューム（PV）と永続ボリュームクレーム（PVC）の作成
Raspberry Pi 5でk3sクラスターを構築し、共通のファイル永続化領域を作成するには、Kubernetesの永続ボリューム（PV）と永続ボリュームクレーム（PVC）を使用します。

## 2-1. 永続ボリューム（PV）の定義ファイルの作成（例：pv.yaml）
```yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /mnt/my_ssd/k3s_storage
    server: 192.168.11.8  # NFSサーバーのIPアドレス（マスターノード）
  storageClassName: manual
```

## 2-2. 永続ボリュームクレーム（PVC）の定義ファイルの作成（例：pvc.yaml）
```yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
  storageClassName: manual
```

## 2-3. リソースの適用
作成したPVとPVCの定義ファイルを適用します。
```bash
kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml
```

## 2-4. Podでの使用
永続ボリュームクレームを使用するPodの定義ファイルを作成します。以下は、PVCをマウントしてファイルを保存するPodの例です。Podの`/usr/share/uploads`から各ノード共通の永続ストレージにアクセスできます。
```yml
spec:
  containers:
  - name: AAA
    image: BBB
    imagePullPolicy: Always
    ports:
    - containerPort: 8000
    volumeMounts:
    - mountPath: /usr/share/uploads
      name: ZZZ-storage
  volumes:
  - name: ZZZ-storage
    persistentVolumeClaim:
      claimName: my-pvc
```

# おわりに
Raspberry Pi 5とk3sを組み合わせることで、低コストながらも強力なクラウドネイティブ環境を構築できることを実感いただけたと思います。今回の手順を応用すれば、さらに多くのアプリケーションをデプロイしたり、クラスタリングによるスケーラビリティの向上も可能です。