背景
私は、研究室にあるベアメタルサーバーを複数台用いてKubernetesクラスタを構築しており、様々な技術検証をしています。
以前は、Longhorn を用いた分散ストレージの構築を行いました。
今回は、よりシンプルなファイル共有方式である NFS (ネットワークファイルシステム)を用いて、複数のVM及びPod間でのストレージ共有の仕組みを検証していきたいと思います。
なお、今回扱った環境のネットワーク構成は以下のようになっているとします。
4台のVMをそれぞれKubernetes Nodeとして割り当てています。VM間はL3でのルーティングを行い、BGPを使用しています。
NFSについて
概要
NFSを用いると、リモートホストがネットワーク経由でファイルシステムをマウントし、そのファイルシステムをローカルにマウントしているファイルシステムと同じように操作できるようになります。
これにより、複数のサーバーやコンテナ間で一貫性を持ったデータを共有・同期し、どのノードからでも同じファイルにアクセスできるようになります。
実現したいこと
「複数のVMおよびPod間で共通のディレクトリを共有し、どの環境からも同じデータを参照・更新できる状態を確認すること」をゴールとしたいと思います。
設定について
VM設定
Kubernetes Nodeのうち1台をNFSサーバーとして割り当てます。( 10.10.10.0/24 側のVM とします)
そして、/srv/nfs/share をNFSサーバーが外部に公開する共有ディレクトリとします。
sudo apt update
sudo apt install -y nfs-kernel-server
sudo mkdir -p /srv/nfs/share
sudo chown nobody:nogroup /srv/nfs/share
sudo chmod 777 /srv/nfs/share
/srv/nfs/share は 自ASであるAS65001 (10.10.10.0/24) 内のVM上で共有されるだけでなく、BGPによる経路交換により AS65002 (10.10.20.0/24) 側のVMからもアクセス可能な共有ディレクトリとしています。
sudo bash -c 'cat <<EOF > /etc/exports
/srv/nfs/share 10.10.10.0/24(rw,sync,no_subtree_check)
/srv/nfs/share 10.10.20.0/24(rw,sync,no_subtree_check)
EOF'
sudo exportfs -ra
sudo systemctl restart nfs-kernel-server
次に、別のVM上で接続設定を行います。
リモートディレクトリである /srv/nfs/share を /mnt/nfs としてローカルに扱えるようにします。
sudo apt install -y nfs-common
sudo mkdir -p /mnt/nfs
sudo mount 10.10.10.101:/srv/nfs/share /mnt/nfs
Kubernetes設定
PVの定義
PV (PersistentVolume) は、Kubernetesクラスタ内で永続的に利用できるストレージ領域を表すオブジェクトです。
今回は、先ほど設定したNFSサーバ( 10.10.10.101 )上の /srv/nfs/share をストレージとして登録しています。
PodはこのPVを通して、NFS上のファイルシステムにアクセスできるようになります。
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
nfs:
path: /srv/nfs/share
server: 10.10.10.101
persistentVolumeReclaimPolicy: Retain
PVCの定義
PVC (PersistentVolumeClaim) は、Podが必要とするストレージ容量やアクセスモードを要求するためのオブジェクトです。PVCがPVとマッチングされることで、Podは実際にNFS上の領域を利用できるようになります。
以下のPVCは、上で定義した nfs-pv を要求しており、storageClassName: "" によって以前設定したLonghornの StorageClass による動的プロビジョニング (自動PV作成) を無効化します。これにより、PVCは明示的に指定した nfs-pv にのみ紐付きます。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: ""
volumeName: nfs-pv
Pod定義
Podでは、先ほど作成したPVCを指定してボリュームをマウントします。
volumes で PVCとして persistentVolumeClaim.claimName: nfs-pvc を指定し、それを volumeMounts でコンテナ内の /data ディレクトリにマウントしています。
この仕組みにより、Pod は PVC を経由して NFS サーバ上の共有ディレクトリにアクセスでき、コンテナ内からローカルディスクのようにファイルの読み書きできます。
apiVersion: v1
kind: Pod
metadata:
name: nfs-test
spec:
containers:
- name: busybox
image: busybox:latest
command: ["/bin/sh", "-c"]
args: ["sleep infinity"]
volumeMounts:
- name: nfs-storage
mountPath: /data
volumes:
- name: nfs-storage
persistentVolumeClaim:
claimName: nfs-pvc
動作確認
VMでのチェック
クライアント側のVMでファイルを作成します。
$ echo "Hello from Client" > /mnt/nfs/test_file.txt
NFSサーバ側のVMでファイルが見れることを確認します。
$ ls -l /srv/nfs/share
total 4
-rw-rw-r-- 1 ryu ryu 20 Nov 10 10:43 test_file.txt
$ cat /srv/nfs/share/test_file.txt
Hello from Client
別のクライアントのVM上でもファイルが見えることを確認します。
$ cat /mnt/nfs/test_file.txt
Hello from Client
この結果から、NFSがネットワークを越えて正常に機能していることが確認できます。
Kubernetesでのチェック
設定したPVCがPVと正しく紐付いていることを確認します。
$ k get pvc nfs-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
nfs-pvc Bound nfs-pv 3Gi RWX <unset> 6s
テスト用のPodの中に入り、PV, PVCによりNFSサーバ上の共有ディレクトリがマウントされている /data に書き込みを行ってみます。
$ k exec -it nfs-test -- /bin/sh
/ # cd data
/data # echo "Hello from Pod" > pod_test.txt
/data # cat pod_test.txt
Hello from Pod
/data # exit
NFSサーバ側のVMで、共有している /srv/nfs/share を確認し、データが書き込まれていることを確認します。
$ ls -l /srv/nfs/share
total 8
-rw-r--r-- 1 nobody nogroup 15 Nov 10 11:09 pod_test.txt
-rw-rw-r-- 1 ryu ryu 20 Nov 10 10:43 test_file.txt
$ cat /srv/nfs/share/pod_test.txt
Hello from Pod
分散ストレージとの比較
分散ストレージとNFSは、複数ノード間でデータを共有できる という点で共通点があります。
また、分散ストレージではデータは各ノードに複製され、ノード障害時に自己復旧する仕組みがあるためデータの 高可用性を維持する 仕組みがあるものの、NFSでは、NFSサーバを冗長化しないと 単一障害点となってしまう リスクがあります。
一方でNFSは、本記事で見たように構成がシンプルで導入が容易というメリットがあります。
まとめ
今回はKubernetes環境でNFSの動作検証をしてみました。データを複数ノード間で共有することを目的とするならば、NFSはシンプルに導入できとても便利だと思いました。
