QNAP CSI Driver

投稿者: | 6月 22, 2025

家のラボをほとんど処分をしたが、まだ若干残っている。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で行った。

https://gist.githubusercontent.com/masezou/65c29fcff3a761335506b908f97228a3/raw/dcf905d38b7c2c26df974be3b6979f5609176bb5/k3s-setup.sh

ただし、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から中身が覗けるのはありかもしれない。

コメントを残す