1. 背景
- コンテナで稼働するアプリケーションでRWX(複数ノードからの読み書きが可能)なストレージが必要な場合はBlock Storageは使用できず、Object Storageはアプリ側の接続方法を変える必要があるため、File storageが必要なアプリケーションがまだまだ存在する。
- IBM CloudのOpenShiftクラスターをVPC(Virtual Private Cloud)インフラストラクチャーで利用する場合、File Storage for VPCというソリューションが存在するが、承認されたユーザーだけが利用できることや使えるリージョンが限られることなど、利用するにはまだ敷居が高い。
- OpenShift Container Storage (新しい名前はOpenShift Data Foundation)もあるが、必要なクラスターのリソースなどの要件が色々あり、これも気軽に利用できるとは言い難い。
- File storageとして、NFSサーバーを利用する方法もあるが、動的プロビジョニングができないため、管理者が事前にNFSエクスポートを準備するなど管理に手間がかかる。
- 調べたところNFSサーバーの動的プロビジョニングに関する情報(以下、「3. 参考にさせていただいた情報」の1.および2.)が公開されているため利用してみる。
2. 目的
- NSFサーバーを構築する。
- OpenShiftクラスターからNFSサーバーの動的プロビジョニングを可能にする。
3. 参考にさせていただいた情報
- kubernetes-sigs/nfs-subdir-external-provisioner
- How do I create a storage class for NFS dynamic storage provisioning in an OpenShift environment?
- Db2 11.5.4 on OpenShift をデプロイしてみた - NFS構成 -
- OpenShift Container Platform>4.6>ストレージ>3.11. NFS を使用した永続ストレージ
- NFS : サーバーの設定
- CentOS 8 でNFSサーバー構築
- Red Hat Enterprise Linux>8>ファイルシステムの管理>第3章 NFS 共有のマウント
- Red Hat Enterprise Linux>8>ファイルシステムの管理>第4章 NFS 共有のエクスポート
- Kubernetes標準のストレージ機能をおさらいしよう
4.環境構成
今回は以下のようにIBM Cloud上のOpenShiftクラスターと仮想サーバーを利用する構成で検証した。
- IBM CloudのVirttual Private Cloud環境
- Virtual Server Instance(VSI) -Bastion(踏み台)サーバー
- NFSサーバーとして構築し、ファイルシステムの1つをNFSボリュームとして共有する。
- Red Hat OpenShift on IBM Cloud クラスター
- ワーカーノード 3台
- podはいずれかのワーカーノードで稼働する。
- 共有されたNFSボリュームをPersistent Volumeとしてマウントして利用する。
- ワーカーノード 3台
- Virtual Server Instance(VSI) -Bastion(踏み台)サーバー
動的プロビジョニングの利用の流れは以下の図のイメージとなる。
5. 手順
5.1. NFSサーバーの設定
- VSIへログインし、NFSサーバを利用するために必要なnfs-utilsパッケージをインストールする。
sudo dnf -y install nfs-utils
- VSIにディレクトリーを作成する。
- ここでは例として
/work/nfsdir/roksNFS-dynamic
というディレクトリーとする。VSIにマウントしているパスに合わせてパスは変更いただきたい。 - VSIの追加ストレージをマウントする手順はIBM Cloud の 仮想サーバーに 追加ストレージ(ポータルブル・ストレージ)をマウントするという記事が参考になる。
- ここでは例として
sudo mkdir -p /work/nfsdir/roksNFS-dynamic
- 設定ファイル /etc/exports を編集してNFS共有を構成する。
- ワーカーノードのIPアドレスはサブネットのアドレス範囲から動的に割り当てられるため、CIDR表記にする。
/<NFS共有するディレクトリー> <openshiftワーカーノード1のIPアドレスのCIDR表記>(rw,sync,no_root_squash,no_all_squash) <openshiftワーカーノード2のIPアドレスのCIDR表記>(rw,sync,no_root_squash,no_all_squash) <openshiftワーカーノード3のIPアドレスのCIDR表記>(rw,sync,no_root_squash,no_all_squash)
実行例
$ sudo vi /etc/exports
$ sudo cat /etc/exports
/work/nfsdir/roksNFS-dynamic 10.240.0.0/24(rw,sync,no_root_squash,no_all_squash) 10.240.64.0/24(rw,sync,no_root_squash,no_all_squash) 10.240.128.0/24(rw,sync,no_root_squash,no_all_squash)
- /etc/exports の設定を反映し、確認する。
exportfs -ra
exportfs
実行例
$ sudo exportfs -ra
$ sudo exportfs -v
/work/nfsdir/roksNFS-dynamic
10.240.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/work/nfsdir/roksNFS-dynamic
10.240.64.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/work/nfsdir/roksNFS-dynamic
10.240.128.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
rpcbindサービスの状態を確認する。以下の例ではmaskedになっている。
$ systemctl list-unit-files -t service | grep rpcbind
rpcbind.service masked
maskedになっている場合はサービスの手動起動禁止のため、マスキング解除してrpcbindサービスを起動できるようにする。
sudo systemctl unmask rpcbind
実行例
$ sudo systemctl unmask rpcbind
Removed /etc/systemd/system/rpcbind.service.
rpcbindサービスのステータスがdisabledになったことを確認。
$ systemctl list-unit-files -t service | grep rpcbind
rpcbind.service disabled
- rpcbindサービスを起動する。
sudo service rpcbind start
実行例
$ sudo service rpcbind start
Redirecting to /bin/systemctl start rpcbind.service
- rpcbindサービスを有効にしておく。
systemctl enable --now rpcbind
実行例
$ sudo systemctl enable --now rpcbind
Created symlink /etc/systemd/system/multi-user.target.wants/rpcbind.service → /usr/lib/systemd/system/rpcbind.service.
$ systemctl list-unit-files -t service | grep rpcbind
rpcbind.service enabled
- NFSサービスを起動する。
sudo systemctl start nfs-server
- NFSサービスを自動起動するように以下のコマンドを実行する。
sudo systemctl enable --now nfs-server
実行例
$ sudo systemctl start nfs-server
$ sudo systemctl enable --now nfs-server
Created symlink /etc/systemd/system/multi-user.target.wants/nfs-server.service → /usr/lib/systemd/system/nfs-server.service.
$ sudo systemctl list-unit-files -t service | grep nfs-server
nfs-server.service enabled
- ファイアーウォールでNFSを許可する設定を行う。
firewall-cmd --add-service=nfs --permanent
firewall-cmd --add-service={nfs3,mountd,rpc-bind} --permanent
firewall-cmd --reload
実行例
$ sudo firewall-cmd --add-service=nfs --permanent
success
$ sudo firewall-cmd --add-service={nfs3,mountd,rpc-bind} --permanent
success
$ sudo firewall-cmd --reload
success
5.2. NFSサーバーの動的プロビジョニング設定
- OpenShiftクラスターにNSF用のプロジェクト
nfs-test
を作成する。
oc new-project nfs-test
ここからは、以下に沿って進める
-
How do I create a storage class for NFS dynamic storage provisioning in an OpenShift environment?
-
Service AccoutやRole設定のためのrabc.yamlファイルの作成
-
Gitリポジトリーからファイルを取得する。
git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
-
rabc.yamlファイル内のnamespaceをdefaultからnfs-testへ変更する。
rabc.yamlapiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner # provisionerをデプロイするプロジェクトに変更する namespace: nfs-test --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # provisionerをデプロイするプロジェクトに変更する namespace: nfs-test roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # provisionerをデプロイするプロジェクトに変更する namespace: nfs-test rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # provisionerをデプロイするプロジェクトに変更する namespace: nfs-test subjects: - kind: ServiceAccount name: nfs-client-provisioner # provisionerをデプロイするプロジェクトに変更する namespace: nfs-test roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io
-
-
rbac.yamlを適用する。
oc apply -f rbac.yaml
実行例
$ oc apply -f rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
- SCC (Security Context Constraints) の設定を行う。
- SCCの設定にはOpenShiftクラスターの管理者権限が必要なため、権限のあるユーザーで実施する。
oc adm policy add-scc-to-user hostmount-anyuid system:serviceaccount:nfs-test:nfs-client-provisioner
実行例
$ oc adm policy add-scc-to-user hostmount-anyuid system:serviceaccount:fs-test:nfs-client-provisioner
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:hostmount-anyuid added: "nfs-client-provisioner"
- Provisioner用のdeployment.yamlを以下のように変更する。
- metadata.namespaceをdefaultからnfs-testに変更
- spec.template.spec.containers.envのname.PROVISIONER_NAMEのvalueをわかりやすいように
nfs-storage
に変更 - spec.template.spec.containers.envのname.NFS_SERVERのvalueとspec.template.spec.containers.volumes.nfs.serverの値をNFSサーバーのIPアドレス
10.240.0.11
に変更 - spec.template.spec.containers.envのNFS_PATHのvalueとspec.template.spec.containers.volumes.nfs.pathの値を作成したNFS共有のパス
/work/nfsdir/roksNFS-dynamic
に変更
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# namespaceをdefaultから作成したネームスペースへ変更
namespace: nfs-test
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: nfs-storage # provisioner名を指定する
- name: NFS_SERVER
value: 10.240.0.11 # NFSサーバーのホスト名またはIPアドレスに変更
- name: NFS_PATH
value: /work/nfsdir/roksNFS-dynamic # 作成したNFS共有のパスに変更
volumes:
- name: nfs-client-root
nfs:
server: 10.240.0.11 # NFSサーバーのホスト名またはIPアドレスに変更
path: /work/nfsdir/roksNFS-dynamic # 作成したNFS共有のパスに変更
- Provisioner用のdeploymentをデプロイする。
oc apply -f deployment.yaml
実行例
$ oc apply -f deployment.yaml
deployment.apps/nfs-client-provisioner created
- deploymentの状態を確認する。
oc get deployment
deploymentが1/1 READYとなり、nfs-client-provisionerのpodが起動したことを確認。
実行例
$ oc get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-provisioner 1/1 1 1 49m
$ oc get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-84745899cf-nwtpr 1/1 Running 0 41s
- storage classのyamlファイルを作成する。
- matadata.nameに名前を
managed-nfs-storage
と指定する。 - provisionerはdeploymentの env PROVISIONER_NAMEと合わせて
nfs-storage
とする。
- matadata.nameに名前を
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage # storage class名を指定
provisioner: nfs-storage # ここはdeploymentのenv PROVISIONER_NAMEと同じ値にする
parameters:
archiveOnDelete: "false"
- nfs-client-provisionerのstorage classをデプロイする。
oc apply -f nfs-storageclass.yaml
実行例
$ oc project
Using project "nfs-test" on server "***".
$ oc apply -f nfs-storageclass.yaml
I0810 00:57:53.003659 580455 request.go:645] Throttling request took 1.088788215s, request: GET:***/apis/ws.cpd.ibm.com/v1beta1?timeout=32s
storageclass.storage.k8s.io/managed-nfs-storage created
- storage class
managed-nfs-storage
が作成されたことを確認
$ oc get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
ibmc-vpc-block-10iops-tier (default) vpc.block.csi.ibm.io Delete Immediate false 11d
ibmc-vpc-block-5iops-tier vpc.block.csi.ibm.io Delete Immediate false 11d
ibmc-vpc-block-custom vpc.block.csi.ibm.io Delete Immediate false 11d
ibmc-vpc-block-general-purpose vpc.block.csi.ibm.io Delete Immediate false 11d
ibmc-vpc-block-metro-10iops-tier vpc.block.csi.ibm.io Delete WaitForFirstConsumer false 11d
ibmc-vpc-block-metro-5iops-tier vpc.block.csi.ibm.io Delete WaitForFirstConsumer false 11d
ibmc-vpc-block-metro-custom vpc.block.csi.ibm.io Delete WaitForFirstConsumer false 11d
ibmc-vpc-block-metro-general-purpose vpc.block.csi.ibm.io Delete WaitForFirstConsumer false 11d
ibmc-vpc-block-metro-retain-10iops-tier vpc.block.csi.ibm.io Retain WaitForFirstConsumer false 11d
ibmc-vpc-block-metro-retain-5iops-tier vpc.block.csi.ibm.io Retain WaitForFirstConsumer false 11d
ibmc-vpc-block-metro-retain-custom vpc.block.csi.ibm.io Retain WaitForFirstConsumer false 11d
ibmc-vpc-block-metro-retain-general-purpose vpc.block.csi.ibm.io Retain WaitForFirstConsumer false 11d
ibmc-vpc-block-retain-10iops-tier vpc.block.csi.ibm.io Retain Immediate false 11d
ibmc-vpc-block-retain-5iops-tier vpc.block.csi.ibm.io Retain Immediate false 11d
ibmc-vpc-block-retain-custom vpc.block.csi.ibm.io Retain Immediate false 11d
ibmc-vpc-block-retain-general-purpose vpc.block.csi.ibm.io Retain Immediate false 11d
managed-nfs-storage nfs-storage Delete Immediate false 92s
ocs-storagecluster-ceph-rbd openshift-storage.rbd.csi.ceph.com Delete Immediate true 5d10h
ocs-storagecluster-cephfs openshift-storage.cephfs.csi.ceph.com Delete Immediate true 5d10h
openshift-storage.noobaa.io openshift-storage.noobaa.io/obc Delete Immediate false 5d10h
5.3. 動的プロビジョニングの稼働確認
nfs-subdir-external-provisionerリポジトリーのREADMEに記載されている手順で動作確認を行う。
- テスト用のPVCとpodのyamlを用意する。
- ここでのポイントは、PVCのyamlでstorageClassNameに作成した
managed-nfs-storage
を指定することである。これによって、NFS動的プロビジョニング用のprovisionerがPVC用のディレクトリーを作成して利用できるようにする。
- ここでのポイントは、PVCのyamlでstorageClassNameに作成した
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
storageClassName: managed-nfs-storage
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: gcr.io/google_containers/busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
- テスト用のPVCとpodをデプロイする
oc apply -f test-claim.yaml -f test-pod.yaml
ログ
$ oc apply -f test-claim.yaml -f test-pod.yaml
persistentvolumeclaim/test-claim created
pod/test-pod created
- PVCとpodが作成されたことを確認する。
$ oc get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim Bound pvc-7e915759-a87a-4969-958b-72d62fa97c0a 1Mi RWX managed-nfs-storage 57s
$ oc get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-84745899cf-nwtpr 1/1 Running 0 3d15h
test-pod 0/1 Completed 0 60s
- NSF共有のディレクトリにSUCCESSファイルが作成されていることを確認する。
- 動的プロビジョニング用のNFS共有ディレクトリー以下にpvc名のディレクトリーが作成され、その下にファイルが作られている。
# pwd
/work/nfsdir/roksNFS-dynamic/nfs-test-test-claim-pvc-7e915759-a87a-4969-958b-72d62fa97c0a
# ls -la
total 0
drwxrwxrwx. 2 root root 21 Aug 10 01:03 .
drwxr-x---. 3 root root 74 Aug 10 01:03 ..
-rw-r--r--. 1 root root 0 Aug 10 01:03 SUCCESS
- テスト用のPVCとpodを削除する。
oc delete -f test-claim.yaml -f test-pod.yaml