【番外編】ゼロからはじめるOpenShift Virtualization(3)共有ストレージの作成(NFSプロビジョナーの構築)

Red Hatでソリューションアーキテクトをしている田中司恩(@tnk4on)です。 この連載はvSphere環境上にOpenShift Container Platform(以下、OpenShift)およびOpenShift Virtualizationの環境を構築する方法を解説するシリーズです。

本記事は元々、連載「ゼロからはじめるOpenShift Virtualization」の第3回として投稿した内容のNFSプロビジョナーの構築部分のみをピックアップした内容です。 このNFSプロビジョナーはボリュームのスナップショットに対応しておらず、OpenShift Virtuzalizationとして利用するには機能不足な点がありました。 そのため、本連載第3回の内容はNFS CSI driver for Kubernetes(以下、NFS CSIドライバー)を使った内容に変更しております。 本記事はあくまで参考情報として残しておくことを目的とします。

本連載の一覧は下記の通りです。

-目次-


前提条件

  • 連載第1回、第2回および、第3回の「2. 踏み台サーバー上のNFSサーバー設定」作業が完了していることとします
  • NFSプロビジョナー構築後の「イメージレジストリの設定」は第3回を参照ください
  • 全体の構成や各パラメーターなどは連載第1回を参照してください
  • 作業用端末のプロンプトは%とします
  • 踏み台サーバーのプロンプトは$とします
  • 踏み台サーバーの作業は明示的に記載がある場合を除いて、作業ディレクトリ${HOME}/workで作業することとします

踏み台サーバー上のNFSサーバー設定後の構成
踏み台サーバー上のNFSサーバー設定後の構成

1. NFSプロビジョナーの設定

踏み台サーバー上に構築したNFSサーバーを利用してPVの動的プロビジョニングを行うため、OpenShiftにNFSプロビジョナーをインストールします。

NFSプロビジョナー導入後の構成
NFSプロビジョナー導入後の構成

1-1 NFSプロビジョナーについて

OpenShiftでPVの動的プロビジョニングを行うためにはストレージとそれに対応したCSIドライバーが必要です。 今回構築したストレージはRHELで立てた汎用的なNFSサーバーなので専用のCSIドライバーがありません。 そこで今回は、汎用的なNFSサーバーをバックエンドに使用しPVの動的プロビジョニングを行うことができる「NFS Subdir External Provisioner(以下、NFSプロビジョナー)」を利用します。

このNFSプロビジョナーはKuberentes SIGsでホストされているリポジトリの1つです。OSSで開発されておりApache-2.0 licenseに従い無償で利用できます。

kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.

なお、このNFSプロビジョナーは汎用的なNFSサーバーをバックエンドに利用できる反面、高度な機能には対応していません(ストレージの機能を使ったVolume CLoneなど)。

Support for "CSI Volume Cloning" · Issue #182 · kubernetes-sigs/nfs-subdir-external-provisioner

実稼働環境ではスナップショットやボリュームクローニングに対応したCSIドライバを提供しているストレージベンダーなどの製品をご利用ください。

1-2 NFSプロビジョナーの動作

NFSプロビジョナーの動作の流れは下記の通りです

NFSプロビジョナーの動作
NFSプロビジョナーの動作

1-3 NFSプロビジョナーのインストール

NFSプロビジョナーをインストールする流れは下記のとおりです。

  1. NFSプロビジョナー用のプロジェクトを作成
  2. サービスアカウントの作成
  3. Helmのインストール
  4. NFSプロビジョナーのインストール

現時点ではコマンドの詳細を深く理解する必要はありません。まずはおまじない的にコマンドをコピペして実行してください。

(1)NFSプロビジョナー用のプロジェクトを作成

oc new-projectコマンドでNFSプロビジョナー用のプロジェクトを作成します。 プロジェクト名はnfs-subdir-external-provisionerとします。

$ oc new-project nfs-subdir-external-provisioner

(2)サービスアカウントの作成

NFSプロビジョナーのインストールの前にサービスアカウントを作成します。 サービスアカウントは、KubernetesやOpenShiftでシステムコンポーネントやアプリケーションがAPIサーバーと安全に通信するために使用される特殊なアカウントです。

手動で作成したnfs-subdir-external-provisionerサービスアカウントに権限、ラベル、アノテーションを追加します。

$ oc create sa nfs-subdir-external-provisioner
$ oc adm policy add-scc-to-user hostmount-anyuid system:serviceaccount:nfs-subdir-external-provisioner:nfs-subdir-external-provisioner
$ oc label sa nfs-subdir-external-provisioner app.kubernetes.io/managed-by=Helm
$ oc annotate sa nfs-subdir-external-provisioner meta.helm.sh/release-name=nfs-subdir-external-provisioner meta.helm.sh/release-namespace=nfs-subdir-external-provisioner
  • oc adm policy add-scc-to-user:サービスアカウントにhostmount-anyuidというSCCを追加します
  • oc label sa:このサービスアカウントがHelmによって管理されていることを示すラベルを追加する
  • oc annotate sa:サービスアカウントにHelmリリースに関するメタデータをアノテーションとして追加する

これでNFSプロビジョナーをインストールする準備が整いました。

(3)Helmのインストール

NFSプロビジョナーのインストールでHelm*1を使用します。 Helmはパッケージマネージャーの1つで、アプリケーションをパッケージ(Helmではチャートという)としてKuberenetes上に簡単にデプロイできる仕組みです。 今回の構成では踏み台サーバーにHelmをインストールします。Helmのインストールドキュメントは下記です(本記事ではRed Hatが提供しているHelmのバイナリを利用します)。

6.2. Helm のインストール | Red Hat Product Documentation

x86_64の環境にHelmをインストールするコマンド例は下記のとおりです。

$ sudo curl -L https://mirror.openshift.com/pub/openshift-v4/clients/helm/latest/helm-linux-amd64 -o /usr/local/bin/helm
$ sudo chmod +x /usr/local/bin/helm

Helmのインストール後、helmコマンドを実行して動作確認を行います。

$ helm version
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/user/work/auth/kubeconfig
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/user/work/auth/kubeconfig
version.BuildInfo{Version:"v3.14.4+37.el9", GitCommit:"7163c12e65c8c0a40334c0a4b514b991ea37aa21", GitTreeState:"clean", GoVersion:"go1.21.9 (Red Hat 1.21.9-2.el9_4)"}

KUBECONFIG環境変数がセットされていて、かつkubeconfigファイルのパーミッションが所有者以外から読み込み可能になっているとコマンドの出力に警告が出ます。 気になる方はchmodコマンドでパーミッションを変更してください。

$ chmod 600 auth/kubeconfig

(4)NFSプロビジョナーのインストール

NFSプロビジョナーはOpenShiftにインストールします。初めにチャートリポジトリを追加し、その後にインストールを行います。

helm repo addコマンドでNFSプロビジョナーのチャートリポジトリを追加します。

$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
  • ~/.config/helmディレクトリが作成され、参照するリポジトリの情報が保存されます

helm installコマンドでNFSプロビジョナーをインストールします。 --setオプションを使って固有の情報を追加で指定します。

$ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=192.168.1.206 \
--set nfs.path=/mnt/nfs \
--set storageClass.accessMode=ReadWriteMany
  • nfs.server:NFSサーバーのIPアドレス/ホスト名を指定
  • nfs.path:NFSエクスポートを行ったパスを指定
  • storageClass.accessMode:RWXを使用するためReadWriteManyを指定

helm installコマンドを実行すると下記のような応答が出力されます

...
NAME: nfs-subdir-external-provisioner
LAST DEPLOYED: Mon Jul  8 05:15:36 2024
NAMESPACE: nfs-subdir-external-provisioner
STATUS: deployed
REVISION: 1
TEST SUITE: None

NFSプロビジョナーが正常にインストールできたかどうかは次の手順で確認します。

(5)NFSプロビジョナーのインストールの確認

OpenShiftのWebコンソールから「管理者向け表示」のプルダウンを選択し「開発者」を選択します。 これにより開発者向け表示(Developerパースペクティブ)に切り替えることができます。

開発者向け表示(Developerパースペクティブ)に切り替える
開発者向け表示(Developerパースペクティブ)に切り替える

左のメニューから「トポロジー」を選択します。プロジェクトのプルダウンメニューから「nfs-subdir-external-provisioner」を選択します。 画面内に「D」のアイコンがついたnfs-subdir-external-provisionerというオブジェクト(Deployment)が表示されます。 このDeploymentはNFSプロビジョナーのアプリケーションPodの展開と管理を行うリソースです。

NFSプロビジョナーのプロジェクトのトポロジー表示
NFSプロビジョナーのプロジェクトのトポロジー表示

左のメニューからHelmを選択すると、現在選択しているプロジェクトに登録済みのHelmリリース*2の情報が表示されます。

デプロイされたHelmリリースの表示
デプロイされたHelmリリースの表示

「HR」アイコンが付いたHelmリリース名(ここではnfs-subdir-external-provisioner)のリンクを選択します。

Helmリリースの詳細
Helmリリースの詳細

Helmでインストールされたリソースの名前やタイプが一覧で表示されます。先ほど確認したDeploymentのステータス欄にはPodが1つ起動していることが確認できます。 このPodがNFSプロビジョナーを実行する実体(のコンテナ)となります。

1-4 デフォルトストレージクラスの設定

ストレージクラスとはPVの動的プロビジョニングを定義するために使用されます。ユーザーは必要なストレージクラスを指定して永続ボリューム要求(PVC)を作成します。

ストレージクラスの詳細については下記のドキュメントを参照してください。

5.6. デフォルトストレージクラスの管理 | Red Hat Product Documentation

デフォルトストレージクラスとは2つ以上のストレージクラスが存在する場合に標準的に使用されるストレージクラスのことです。 今回の構成ではストレージクラスは1つしか作成されていませんが、明示的に設定をしておくことで他のストレージクラスよりも優先的に利用するようにしておきます。

デフォルトストレージクラスを設定するには下記のコマンドを実行します。 今回はストレージクラス名:nfs-clientに対して通常のコンテナアプリケーションと仮想マシンの両方にデフォルト設定を行います。

$ oc patch storageclass nfs-client -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
$ oc patch storageclass nfs-client -p '{"metadata": {"annotations":{"storageclass.kubevirt.io/is-default-virt-class":"true"}}}'

設定が反映されているか下記のコマンドを実行して確認を行います。 oc getコマンドで引数にstorageclassを指定し、さらに-o yamlオプションを追加して、ストレージクラスの設定内容をYAML形式で出力を行います。

$ oc get storageclass -o yaml

出力結果内のannotations:に先ほど設定した値が反映されているか確認できます。下記の出力結果を展開して内容を確認ください。

出力結果を開く

$ oc get storageclass -o yaml
apiVersion: v1
items:
- allowVolumeExpansion: true
  apiVersion: storage.k8s.io/v1
  kind: StorageClass
  metadata:
    annotations:
      meta.helm.sh/release-name: nfs-subdir-external-provisioner
      meta.helm.sh/release-namespace: nfs-subdir-external-provisioner
      storageclass.kubernetes.io/is-default-class: "true"
      storageclass.kubevirt.io/is-default-virt-class: "true"
    creationTimestamp: "2024-06-28T07:10:00Z"
    labels:
      app: nfs-subdir-external-provisioner
      app.kubernetes.io/managed-by: Helm
      chart: nfs-subdir-external-provisioner-4.0.18
      heritage: Helm
      release: nfs-subdir-external-provisioner
    name: nfs-client
    resourceVersion: "128018"
    uid: fd859079-dcb4-4b15-b1f2-747189033af2
  parameters:
    archiveOnDelete: "true"
  provisioner: cluster.local/nfs-subdir-external-provisioner
  reclaimPolicy: Delete
  volumeBindingMode: Immediate
kind: List
metadata:
  resourceVersion: ""

1-5 動的プロビジョニングの動作テスト

NFSプロビジョナーの設定ができたので実際にサンプルのPodを実行して動的プロビジョニングの動作テストを行います。

(1)サンプルファイルのダウンロード

NFSプロビジョナーのリポジトリで公開されているサンプルのファイルをダウンロードします。 PVCとPodをそれぞれ実行するYAMLファイルをダウンロードします。

$ wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/test-claim.yaml
$ wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/test-pod.yaml
$ ls -d test-claim.yaml test-pod.yaml
test-claim.yaml  test-pod.yaml

(2)PVCの作成

oc createコマンドでYAMLファイルからリソースを作成します。-fオプションで読み込むYAMLファイルを指定します。

今回は前の作業からの流れのままプロジェクトは変更せずに行います。

$ oc create -f test-claim.yaml
persistentvolumeclaim/test-claim created

Webコンソールの管理者向け表示のメニューから「ストレージ>PersistentVolumeClaims」を選択すると、作成されたPVCとバインドされたPVが一覧で表示されます。

サンプルのPVCから作成されたPV
サンプルのPVCから作成されたPV

このサンプルでは下記の情報が確認できます。

  • PVC:test-claim
  • PV:pvc-51702f11-4b99-451f-b2a1-109ab9e35557
  • PVの容量:1 MiB
  • 使用したストレージクラス:nfs-client

踏み台サーバー上のNFSエクスポートディレクトリを確認すると、PV用のディレクトリが自動で作成されていることが分かります。

$ tree /mnt/nfs/
/mnt/nfs/
└── nfs-subdir-external-provisioner-test-claim-pvc-51702f11-4b99-451f-b2a1-109ab9e35557

1 directory, 0 files

NFSサーバー上に作成されるディレクトリの命名規則はPVCのプロジェクト名(Namespace名)-PVC名-PV名になります。

(3)Podの作成

作成されたPVを使用するサンプルのPodを起動します。PVCの作成と同様にoc createコマンドを使用します。

$ oc create -f test-pod.yaml
pod/test-pod created

Webコンソールの管理者向け表示のメニューから「Workloads>Pods」を選択すると、実行中のPodが一覧で表示されます。 サンプルのPod(test-pod)のステータスがCompletedになっており、このPodの実行が正常に完了したことが分かります。

nfs-subdir-external-provisionerプロジェクトで実行中のPod一覧
nfs-subdir-external-provisionerプロジェクトで実行中のPod一覧

Pod名のtest-podのリンクを選択するとPodの詳細画面が表示されます。 test-podコンテナがbusybox:stableコンテナイメージから作成されており、状態がTerminatedになっており、すでに実行が終了していることが確認できます。 終了コードが0になっており、このコンテナの実行が正常に終了したことが示されています。 また、このコンテナではPVはnfs-pvcという名前でボリュームとして扱われており、コンテナ内の/mntディレクトリにマウントされています。

サンプルPodの詳細情報
サンプルPodの詳細情報

このサンプルではコンテナの実行コマンドとしてtouch /mnt/SUCCESSが実行されて成功すればexit 0で終了するようにプログラムされています*3。 そのため、サンプルのPod起動後にNFSサーバー上のディレクトリを確認すると、コンテナの中で作成されたSUCCESSファイルが生成されていることが確認できます。

$ tree /mnt/nfs/
/mnt/nfs/
└── nfs-subdir-external-provisioner-test-claim-pvc-51702f11-4b99-451f-b2a1-109ab9e35557
    └── SUCCESS

1 directory, 1 file

(4)サンプルのPodとPVの削除

作成したサンプルのPodとPVを削除する場合は下記のコマンドを実行します。 oc deleteコマンドでOpenShift上のリソースを削除します。 -fオプションでYAMLファイルを指定し対象のリソースのみを削除できます。-fオプションは複数指定可能で、今回はPodとPVを同時に削除します。

$ oc delete -f test-claim.yaml -f test-pod.yaml

PV削除後のNFSサーバー上の実体ディレクトリは下記のようになります。

$ tree /mnt/nfs/
/mnt/nfs/
└── archived-nfs-subdir-external-provisioner-test-claim-pvc-51702f11-4b99-451f-b2a1-109ab9e35557
    └── SUCCESS

1 directory, 1 file

NFSプロビジョナーのデフォルト動作では、PV削除時のNFSサーバー上の実体ディレクトリはarchived-が追加された名前にリネームされて保持されます。 これはストレージクラスの設定を出力することで確認できます。

OpenShift上のリソースから特定のセクションのパラメーターを取得する場合は、oc getコマンドの出力を-o jsonオプションによりJSON形式で出力し、パイプで繋いでjqコマンドでパースします。 下記のコマンドでストレージクラスのparametersセクションの値のみを取り出すことができます。

$ oc get storageclasses -o json | jq '.items[].parameters'
{
  "archiveOnDelete": "true"
}

parametersセクションにarchiveOnDelete:trueで設定されているため、PVを削除した場合でも実体ディレクトリがアーカイブされて保持されます。 この設定をarchiveOnDelete:falseに変更することで、PVの削除と同時に実体ディレクトリを削除できます。 なお、NFSプロビジョナーのインストール後にストレージクラスのパラメーターは変更できません。 次の項目を参照してNFSプロビジョナーを削除し、再度インストールする時に--set storageClass.archiveOnDelete=falseオプションを追加してコマンドを実行してください。

(5)NFSプロビジョナーの削除

NFSプロビジョナーの削除を行う場合はhelm deleteコマンドを実行します。 helm deleteコマンドに引数としてnfs-subdir-external-provisionerを指定して実行します。

$ helm delete nfs-subdir-external-provisioner
release "nfs-subdir-external-provisioner" uninstalled

合わせてOpenShiftのプロジェクトを削除する場合は下記のコマンドを実行します。 oc delete projectコマンドに引数でプロジェクト名:nfs-subdir-external-provisionerを指定して実行します。

$ oc delete project nfs-subdir-external-provisioner
project.project.openshift.io "nfs-subdir-external-provisioner" deleted

プロジェクトを削除した場合、NFSプロビジョナーを再インストールする場合はサービスアカウントの作成から行う必要があります。

まとめ

汎用的なNFSサーバーをバックエンドとして、PVの動的プロビジョニングを行う方法としてNFSプロビジョナーの構築方法をご紹介しました。 PVの動的プロビジョニングを行うだけであればNFSプロビジョナーで十分ですが、OpenShift Virtualizationで仮想マシンのスナップショット機能には対応していません。 そのため、基本的にはNFSプロビジョナーと同様に構成して、Helmでインストールを行うことができる「NFS CSIドライバー」の利用を推奨します。 詳細は第3回:共有ストレージの作成(NFS CSIドライバーの構築)を参照ください。

*1:Helm

*2:OpenShift上にHelmでデプロイされたアプリケーションやサービスのインスタンスのこと

*3:詳細を知りたい方はtest-pod.yamlファイルの中身を参照ください

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。