家のラボをほとんど処分をしたが、まだ若干残っている。NASもぐっと集約して、NASでCSI Driverが動けばいいやと。ちょっと前からQNAPのCSI Driverがあったのだが、気がついたらSnapshotまでサポートをしていた。
NetAppのTridentをベースにしているので、ほとんどTrident。最新のバージョンだと、iSCSIだけではなく、SMBも使える。
早速動かしてみた。
事前準備
- Kubernetesのバージョンは1.24.0-1.32
- QTS/QTS heroは、5.0.0以上
- QNAPのStorage Poolに空きが必要
以下の構成は、21.80TBのStrage Pool 1にDataVol1として4.07TBが確保されている。QNAP CSIは、残りの17.73TBの領域を使う。(TS-464ではなく、撤去したTS-453Beを初期化したもの。)
httpsの証明書に特に制限はない。(デフォルトの自己証明書で問題なし。)
クレデンシャルには、管理者権限が必要(Admin権限をもつ一般ユーザ)
サポートしているバックエンドは、
- SMB共有(PVC毎に新しくLUNが作られ、SMB共有が作成される。File StationからPVCの内部の参照が可能)
- iSCSI LUN (PVC毎に新しくLUNが作られ、iSCSI Targetが作成される)
iSCSIを使う場合は、QNAP側でiSCSIのサービスが動作していること。動作していない場合は、オンにしておく。
オフだった場合は、以下のダイアログが出てくるのでOKをクリック
サービスがオンになっていることを確認
以下、動作確認は、k3sで行った。
ただし、Longhornのために入れたSnapshot Controller v8.2.0 とバッティングするかと思ったら問題なかった。
Tridentのインストール
QNAPのgitをクローンする。(最小限)、その後、helmでインストール
git clone https://github.com/qnap-dev/QNAP-CSI-PlugIn.git --depth 1
cd QNAP-CSI-PlugIn
helm install qnap-trident ./Helm/trident -n trident --create-namespace
sleep 10
kubectl wait --namespace trident --for=condition=available --timeout=120s deployment -l app=operator.trident.qnap.io
sleep 50
kubectl wait --namespace trident --for=condition=available --timeout=120s deployment -l app=controller.csi.trident.qnap.io
kubectl get deployment -n trident
NAME READY UP-TO-DATE AVAILABLE AGE
trident-controller 1/1 1 1 6m44s
trident-operator 1/1 1 1 7m31s
kubectl get service -n trident
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
trident-csi ClusterIP 10.43.156.252 <none> 34571/TCP,9220/TCP 6m9s
kubectl get csidriver csi.trident.qnap.io
NAME ATTACHREQUIRED PODINFOONMOUNT STORAGECAPACITY TOKENREQUESTS REQUIRESREPUBLISH MODES AGE
csi.trident.qnap.io true false false <unset> false Persistent 5m58s
スナップショットコントローラーの導入 (スナップショットコントローラーが無い場合のみ)
Snapshot-controller:v5.0.0がインストールされる。
Longhornで必要となる、v8.2.0でも動いてしまった。
if ! kubectl get pod -n kube-system -l app.kubernetes.io/name=snapshot-controller --no-headers 2>/dev/null | grep -q .; then
kubectl apply -k VolumeSnapshot
fi
customresourcedefinition.apiextensions.k8s.io/volumesnapshotclasses.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotcontents.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshots.snapshot.storage.k8s.io created
serviceaccount/snapshot-controller created
role.rbac.authorization.k8s.io/snapshot-controller-leaderelection created
clusterrole.rbac.authorization.k8s.io/snapshot-controller-runner created
rolebinding.rbac.authorization.k8s.io/snapshot-controller-leaderelection created
clusterrolebinding.rbac.authorization.k8s.io/snapshot-controller-role created
deployment.apps/snapshot-controller created
ボリュームスナップショットクラスの作成
kubectl apply -f Samples/Snapshot/VolumeSnapshotClass.yaml
kubectl get volumesnapshotclasses trident-snapshotclass
NAME DRIVER DELETIONPOLICY AGE
trident-snapshotclass csi.trident.qnap.io Delete csi.trident.qnap.io Delete 26s
便利なのでツールをインストールしておく。
cp bin/linux-amd64/tridentctl /usr/local/bin/
tridentctl completion bash > /etc/bash_completion.d/tridentctl
source /etc/bash_completion.d/tridentctl
以下、iSCSI BackendとSMB Backendの両方を作る。
iSCSI Backend
apt -y install open-iscsi
cat << 'EOF' > iscsi-backend.yaml
apiVersion: v1
kind: Secret
metadata:
name: backend-qts-secret # Required. Name your secret.
namespace: trident
type: Opaque
stringData:
username: qnapuser # Required. Your NAS username.
password: PASSWORD # Required. Your NAS password.
storageAddress: 192.168.x.y # Required. Your NAS IP address.
—
apiVersion: trident.qnap.io/v1
kind: TridentBackendConfig
metadata:
name: backend-qts-iscsi # Required. Name your backend in Kubernetes.
namespace: trident
spec:
version: 1
storageDriverName: qnap-iscsi #Required. Support 'qnap-nas'(latest) or 'qnap-iscsi’
backendName: qts-iscsi # Required. Name your backend in QNAP CSI.
networkInterfaces:
credentials:
name: backend-qts-secret # Required. Enter the secret name set in metadata.name.
debugTraceFlags:
method: true
storage: # Required. Define one or more virtual pools.
- serviceLevel: "ISCSIVirtualPool1" # Required. Name your virtual pool.
labels: # Required. Define custom labels for your virtual pool.
performance: performance1
features: # Optional. Define features for your virtual pool.
tiering: Disable
EOF
kubectl apply -f iscsi-backend.yaml
iSCSIのバックエンドが展開できたかの確認
kubectl get tridentbackendconfig -n trident
NAME BACKEND NAME BACKEND UUID PHASE STATUS
backend-qts-iscsi qts-iscsi 458286e1-1fd3-4ee4-8080-9068fd18dac3 Bound Success
tridentctl -n trident get backend
+———–+—————-+————————————–+——–+————+————+
| NAME | STORAGE DRIVER | UUID | STATE | USER-STATE | VOLUMES |
+———–+—————-+————————————–+——–+————+————+
| qts-iscsi | qnap-iscsi | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | online | normal | 0 |
+———–+—————-+————————————–+——–+————+————+
kubectl get pods -n trident
NAME READY STATUS RESTARTS AGE
trident-controller-fc5859d6b-zhsf7 6/6 Running 0 5m6s
trident-node-linux-q7759 2/2 Running 2 (4m ago) 5m6s
trident-operator-7b76ffb76b-ctrfq 1/1 Running 0 5m53s
StrageClassの作成
cat << 'EOF' > sc_iscsi.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: qnap-iscsi
provisioner: csi.trident.qnap.io
parameters:
selector: "performance=performance1" # Required. Corresponds to the labels in the virtual pool.
fsType: "ext4" # Optional. You can choose to enter ext4 (default), xfs, or ext3.
allowVolumeExpansion: true
EOF
kubectl apply -f sc_iscsi.yaml
kubectl get sc qnap-iscsi
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
qnap-iscsi csi.trident.qnap.io Delete Immediate true 3m27s
tridentctl -n trident get storageclass
+——————+
| NAME |
+——————+
| qnap-iscsi |
+——————+
iSCSIでPVCを作るテスト
作成前
cat << 'EOF' > pvc-iscsi.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc1
annotations: # Required. Define features for your volume.
trident.qnap.io/Threshold: “90”
trident.qnap.io/ThinAllocate: “true”
spec:
accessModes:
- ReadWriteOnce # Required. iSCSI: ReadWriteOnce, Samba: ReadWriteMany
resources:
requests:
storage: 10Gi # Required. Specify your resource size.
storageClassName: qnap-iscsi # Required. Corresponds to the StorageClass name.
EOF
kubectl create ns qnap-iscsi-test
kubectl -n qnap-iscsi-test apply -f pvc-iscsi.yaml
sleep 30
作成後
kubectl -n qnap-iscsi-test get pvc -o wide
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE VOLUMEMODE
pvc1 Bound pvc-6ad59d68-ac13-4f6d-99e3-dff93f0fec85 10Gi RWO qnap-iscsi <unset> 4m33s Filesystem
tridentctl -n trident get backend
+———–+—————-+————————————–+——–+————+————+
| NAME | STORAGE DRIVER | UUID | STATE | USER-STATE | VOLUMES |
+———–+—————-+————————————–+——–+————+————+
| qts-iscsi | qnap-iscsi | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | online | normal | 1 |
+———–+—————-+————————————–+——–+————+————+
tridentctl -n trident get volume
+——————————————+——–+—————+———-+————————————–+——-+————+
| NAME | SIZE | STORAGE CLASS | PROTOCOL | BACKEND UUID | STATE | MANAGED |
+——————————————+——–+—————+———-+————————————–+——-+————+
| pvc-6ad59d68-ac13-4f6d-99e3-dff93f0fec85 | 10 GiB | qnap-iscsi | block | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | | true |
+——————————————+——–+—————+———-+————————————–+——-+————+
iSCSIのスナップショットの作成
cat << 'EOF' > pvc-snapshot-iscsi.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: pvc-snapshot
spec:
volumeSnapshotClassName: trident-snapshotclass
source:
persistentVolumeClaimName: pvc1
EOF
kubectl -n qnap-iscsi-test apply -f pvc-snapshot-iscsi.yaml
kubectl -n qnap-iscsi-test get volumesnapshot
NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE
pvc-snapshot true pvc1 10Gi trident-snapshotclass snapcontent-7eccb0a1-d475-426b-a558-7873a0bccedf 1s 16s
QNAP側でSnapshotが確認できる。
tridentctl -n trident get snapshot
+———————————————–+——————————————+————+
| NAME | VOLUME | MANAGED |
+———————————————–+——————————————+————+
| snapshot-7eccb0a1-d475-426b-a558-7873a0bccedf | pvc-6ad59d68-ac13-4f6d-99e3-dff93f0fec85 | true |
+———————————————–+——————————————+————+
kubectl -n qnap-iscsi-test delete volumesnapshot pvc-snapshot
kubectl -n qnap-iscsi-test delete pvc pvc1
kubectl delete ns qnap-iscsi-test
作成されたものはすべて削除される。
tridentctl -n trident get backend
+———–+—————-+————————————–+——–+————+————+
| NAME | STORAGE DRIVER | UUID | STATE | USER-STATE | VOLUMES |
+———–+—————-+————————————–+——–+————+————+
| qts-iscsi | qnap-iscsi | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | online | normal | 0 |
+———–+—————-+————————————–+——–+————+————+
tridentctl -n trident get snapshot
+——+——–+————+
| NAME | VOLUME | MANAGED |
+——+——–+————+
+——+——–+————+
tridentctl -n trident get volume
+——+——+—————+———-+————–+——-+————+
| NAME | SIZE | STORAGE CLASS | PROTOCOL | BACKEND UUID | STATE | MANAGED |
+——+——+—————+———-+————–+——-+————+
+——+——+—————+———-+————–+——-+————+
SMB Backend
SMBを使う場合の注意点
SMBは、ReadWriteManyで作成しようとする。WordpressのMariaDBは、ReadWriteManyをサポートしないなど、制限がある場合があるので注意をして使う必要がある。
cat << 'EOF' > smb-backend.yaml
apiVersion: v1
kind: Secret
metadata:
name: backend-qts-secret # Required. Name your secret.
namespace: trident
type: Opaque
stringData:
username: qnapuser # Required. Your NAS username.
password: PASSWORD # Required. Your NAS password.
storageAddress: 192.168.x.y # Required. Your NAS IP address.
—
apiVersion: trident.qnap.io/v1
kind: TridentBackendConfig
metadata:
name: backend-qts-smb # Required. Name your backend in Kubernetes.
namespace: trident
spec:
version: 1
storageDriverName: qnap-nas #Required. Support 'qnap-nas'(latest) or 'qnap-iscsi’
backendName: qts-smb # Required. Name your backend in QNAP CSI.
networkInterfaces:
credentials:
name: backend-qts-secret # Required. Enter the secret name set in metadata.name.
debugTraceFlags:
method: true
storage: # Required. Define one or more virtual pools.
- serviceLevel: "SMBVirtualPool1" # Required. Name your virtual pool.
labels: # Required. Define custom labels for your virtual pool.
performance: performance1
features: # Optional. Define features for your virtual pool.
tiering: Disable
EOF
kubectl apply -f smb-backend.yaml
SMBのバックエンドが展開できたかの確認 (この場合、すでにiSCSIバックエンドがいる)
kubectl get tridentbackendconfig -n trident
NAME BACKEND NAME BACKEND UUID PHASE STATUS
backend-qts-iscsi qts-iscsi 458286e1-1fd3-4ee4-8080-9068fd18dac3 Bound Success
backend-qts-smb qts-smb b188abd8-d9b9-4052-ba70-7feccfb8a904 Bound Success
tridentctl -n trident get backend
+———–+—————-+————————————–+——–+————+————+
| NAME | STORAGE DRIVER | UUID | STATE | USER-STATE | VOLUMES |
+———–+—————-+————————————–+——–+————+————+
| qts-iscsi | qnap-iscsi | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | online | normal | 0 |
| qts-smb | qnap-nas | b188abd8-d9b9-4052-ba70-7feccfb8a904 | online | normal | 0 |
+———–+—————-+————————————–+——–+————+————+
kubectl get pods -n trident
NAME READY STATUS RESTARTS AGE
trident-controller-fc5859d6b-zhsf7 6/6 Running 0 18m
trident-node-linux-q7759 2/2 Running 2 (17m ago) 18m
trident-operator-7b76ffb76b-ctrfq 1/1 Running 0 19m
StrageClassの作成
SMBの場合は、secretも必要
cat << 'EOF' > smb_user_secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: qts-csi-smb #Required. Name your secert for Samba.
namespace: trident
type: Opaque
stringData:
username: qnapuser
password: PASSWORD
EOF
kubectl apply -f pvc-iscsi.yaml
cat << 'EOF' > sc_smb.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: qnap-smb
provisioner: csi.trident.qnap.io
parameters:
selector: "performance=performance1" # Required. Corresponds to the labels in the virtual pool.
trident.qnap.io/fileProtocol: "smb”
csi.storage.k8s.io/node-stage-secret-name: "qts-csi-smb" # Required. It must match the metadata.name in the Secret file.
csi.storage.k8s.io/node-stage-secret-namespace: "trident" # Required. It must match the metadata.namespace in the Secret file.
allowVolumeExpansion: true
EOF
kubectl apply -f smb_user_secret.yaml
kubectl apply -f sc_smb.yaml
kubectl get sc qnap-smb
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
qnap-smb csi.trident.qnap.io Delete Immediate true 0s
tridentctl -n trident get storageclass
+——————+
| NAME |
+——————+
| qnap-iscsi |
| qnap-smb |
+——————+
SMBでPVCを作るテスト
qnap-smbでPVCを作る時は、必ずReadWriteManyにして作ること。
作成前
ReadWriteManyの指定が入っていることに注意。
cat << 'EOF' > pvc-smb.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc1
annotations: # Required. Define features for your volume.
trident.qnap.io/Threshold: “90”
trident.qnap.io/ThinAllocate: “true”
trident.qnap.io/SharedFolderRecycleBin: “false”
spec:
accessModes:
- ReadWriteMany # Required. iSCSI: ReadWriteOnce, Samba: ReadWriteMany
resources:
requests:
storage: 10Gi # Required. Specify your resource size.
storageClassName: qnap-smb # Required. Corresponds to the StorageClass name.
EOF
kubectl create ns qnap-smb-test
kubectl -n qnap-smb-test apply -f pvc-smb.yaml
sleep 30
作成後
kubectl -n qnap-smb-test get pvc -o wide
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE VOLUMEMODE
pvc1 Bound pvc-80cc0406-f0d2-45d8-b7df-a6e71d19e536 10Gi RWX qnap-smb <unset> 56s Filesystem
tridentctl -n trident get backend
+———–+—————-+————————————–+——–+————+————+
| NAME | STORAGE DRIVER | UUID | STATE | USER-STATE | VOLUMES |
+———–+—————-+————————————–+——–+————+————+
| qts-iscsi | qnap-iscsi | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | online | normal | 1 |
| qts-smb | qnap-nas | b188abd8-d9b9-4052-ba70-7feccfb8a904 | online | normal | 0 |
+———–+—————-+————————————–+——–+————+————+
tridentctl -n trident get volume
+——————————————+——–+—————+———-+————————————–+——-+————+
| NAME | SIZE | STORAGE CLASS | PROTOCOL | BACKEND UUID | STATE | MANAGED |
+——————————————+——–+—————+———-+————————————–+——-+————+
| pvc-80cc0406-f0d2-45d8-b7df-a6e71d19e536 | 10 GiB | qnap-smb | file | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | | true |
+——————————————+——–+—————+———-+————————————–+——-+————+
SMBのスナップショットの作成
cat << 'EOF' > pvc-snapshot-smb.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: pvc-snapshot
spec:
volumeSnapshotClassName: trident-snapshotclass
source:
persistentVolumeClaimName: pvc1
EOF
kubectl -n qnap-smb-test apply -f pvc-snapshot-smb.yaml
kubectl -n qnap-smb-test get volumesnapshot
NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE
pvc-snapshot false pvc1 trident-snapshotclass snapcontent-1217bc99-a1ef-45b9-840d-f20617655132 8s
QNAP側でSnapshotが確認できる。
tridentctl -n trident get snapshot
+———————————————–+——————————————+————+
| NAME | VOLUME | MANAGED |
+———————————————–+——————————————+————+
| snapshot-1217bc99-a1ef-45b9-840d-f20617655132 | pvc-80cc0406-f0d2-45d8-b7df-a6e71d19e536 | true |
+———————————————–+——————————————+————+
kubectl -n qnap-smb-test delete volumesnapshot pvc-snapshot
kubectl -n qnap-smb-test delete pvc pvc1
kubectl delete ns qnap-smb-test
作成されたものはすべて削除される。
tridentctl -n trident get backend
+———–+—————-+————————————–+——–+————+————+
| NAME | STORAGE DRIVER | UUID | STATE | USER-STATE | VOLUMES |
+———–+—————-+————————————–+——–+————+————+
| qts-iscsi | qnap-iscsi | 458286e1-1fd3-4ee4-8080-9068fd18dac3 | online | normal | 0 |
| qts-smb | qnap-nas | b188abd8-d9b9-4052-ba70-7feccfb8a904 | online | normal | 0 |
+———–+—————-+————————————–+——–+————+————+
tridentctl -n trident get snapshot
+——+——–+————+
| NAME | VOLUME | MANAGED |
+——+——–+————+
+——+——–+————+
tridentctl -n trident get volume
+——+——+—————+———-+————–+——-+————+
| NAME | SIZE | STORAGE CLASS | PROTOCOL | BACKEND UUID | STATE | MANAGED |
+——+——+—————+———-+————–+——-+————+
+——+——+—————+———-+————–+——-+————+
動作はできたが、まだ、少し不安定かもしれない。手元の別のチェックツールだとiSCSIもSMBもダメだった。また、SMBは、ReadWriteManyしかサポートをしないので使えない場合もあるのでよく検討する必要がある。ただ、File Stationから中身が覗けるのはありかもしれない。