seichi-onp-k8s に TrueNAS Scale iSCSI の CSI ドライバーを導入した

Note

このドキュメントは Claude Code を用いて作業しながら生成したものです。

GiganticMinecraft/seichi_infra での実装例を題材にしていますが、democratic-csi で TrueNAS Scale を iSCSI バックエンドとして使用する方法を広く紹介することを主な目的としています。秘匿情報の管理や ArgoCD との連携といった seichi_infra 固有の構成はそのまま適用できない場合がありますが、CSI ドライバーの設定や TrueNAS Scale 側の権限設定については汎用的な参考になるはずです。

はじめに

オンプレミスの Kubernetes クラスター (seichi-onp-k8s) に、TrueNAS Scale をバックエンドとした iSCSI の動的ストレージプロビジョニングを導入しました。CSI ドライバーには democratic-csi を採用しています。

全体構成

democratic-csi は Helm chart で提供されており、接続設定(TrueNAS の API キーや ZFS データセットのパス等)を Kubernetes Secret として渡すことで動作します。seichi_infra では GitOps パターン(ArgoCD + Terraform + GitHub Actions)を用いてこれを管理しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
GitHub Actions Secret (TF_VAR_ONP_K8S_DEMOCRATIC_CSI_SC_TRUENAS_03_DRIVER_CONFIG)
  ↓ terraform apply (main マージ時に自動実行)
Kubernetes Secret: democratic-csi/democratic-csi-driver-config-sc-truenas-03
  ↓ ArgoCD が参照
democratic-csi Helm chart v0.15.1
StorageClass: sc-truenas-03-iscsi
VolumeSnapshotClass: sc-truenas-03-iscsi-vsc
TrueNAS Scale (freenas-api-iscsi ドライバー / iSCSI)

実装の詳細

1. CSI ドライバーの設定

democratic-csi を Helm でインストールする際の最小限の設定は以下の通りです。接続設定(API キー等)は existingConfigSecret で既存の Kubernetes Secret を参照する形にしており、Helm values に秘匿情報を直接書かないようにしています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
csiDriver:
  name: "org.democratic-csi.sc-truenas-03"  # クラスター内で一意な名前

driver:
  existingConfigSecret: democratic-csi-driver-config-sc-truenas-03
  # NOTE: existingConfigSecret 使用時も driver フィールドの指定が必要
  config:
    driver: freenas-api-iscsi

storageClasses:
  - name: sc-truenas-03-iscsi
    defaultClass: false
    reclaimPolicy: Delete
    volumeBindingMode: Immediate
    allowVolumeExpansion: true
    parameters:
      fsType: ext4

volumeSnapshotClasses:
  - name: sc-truenas-03-iscsi-vsc
    deletionPolicy: Delete
    parameters:
      fsType: ext4  # chart テンプレートのバグ回避 (空 map だと parameters: null になる)

seichi_infra での ArgoCD Application 定義は app-of-other-apps/democratic-csi-sc-truenas-03.yaml を参照してください。

2. 接続設定(Kubernetes Secret の中身)

existingConfigSecret で参照する Secret には以下の形式の YAML を driver-config-file.yaml というキーで格納します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
driver: freenas-api-iscsi
httpConnection:
  protocol: https
  host: 192.168.16.234   # TrueNAS Scale の IP アドレス
  port: 443
  apiKey: <TRUENAS_API_KEY>
zfs:
  datasetParentName: pool-01/dataset-seichi-onp-k8s-01/volumes
  detachedSnapshotsDatasetParentName: pool-01/dataset-seichi-onp-k8s-01/snapshots
iscsi:
  targetPortal: 192.168.16.234:3260
  namePrefix: csi-
  nameSuffix: "-seichi-onp-k8s"  # 複数クラスターを使う場合に区別しやすくするため付与
  targetGroups:
    - targetGroupPortalGroup: 1
      targetGroupInitiatorGroup: 2
      targetGroupAuthType: None

Note

seichi_infra での秘匿情報管理について seichi_infra では GitHub Actions Repository Secret に TF_VAR_ プレフィックスで登録した値が、CI スクリプト経由で自動的に Terraform 変数として渡され、onp_cluster_secrets.tf が Kubernetes Secret を作成・更新します。詳細は cluster-boot-up/democratic-csi-sc-truenas-03.md を参照してください。

3. TrueNAS Scale 側の事前設定

iSCSI サービスの有効化

Services から iSCSI サービスを有効化し、起動しておく必要があります。

iSCSI Portal Group

iSCSI の接続受付口となる Portal Group を作成します。Shares > iSCSI > Portals から作成し、待ち受け IP アドレスとポート(デフォルト: 3260)を設定します。接続設定の targetPortal に指定するアドレスがここで設定したものになります。

ZFS データセット

democratic-csi がボリュームとスナップショットを格納する ZFS データセットをあらかじめ作成しておく必要があります。Datasets から以下の2つを作成します。

データセット用途接続設定での対応キー
<pool>/<任意のパス>/volumesPVC として払い出すボリュームの親zfs.datasetParentName
<pool>/<任意のパス>/snapshotsVolumeSnapshot の格納先の親zfs.detachedSnapshotsDatasetParentName

democratic-csi はこれらのデータセット配下にボリュームごとの子データセットを自動で作成・削除します。親データセット自体は手動で用意しておく必要があります。

API キー

API キーは TrueNAS Scale WebUI の Credentials > API Keys から発行します。API キーは発行したユーザーの権限を継承します。democratic-csi は ZFS データセットの作成・削除(ボリューム・スナップショット用)、iSCSI ターゲット・Extent・Target-Extent 関連付けの作成・削除、iSCSI 設定の参照を TrueNAS Scale API 経由で実行するため、これらを行えるユーザーのキーが必要です。

TrueNAS Scale のデフォルト管理者ユーザー(truenas_admin)の API キーを使えば上記すべての権限が得られます。最小権限の観点からは専用サービスアカウントを作成することが望ましいですが、TrueNAS Scale の RBAC は現時点では粒度が粗いため、管理者権限のキーを使うことが現実的な選択になりがちです。

iSCSI Initiator Group

iSCSI では Initiator Group によって「どのホストからの接続を許可するか」を制御します。今回は TrueNAS Scale に Proxmox 向けの iSCSI 設定がすでに存在していたため、以下の2グループを共存させています。

Initiator Group用途設定
ID: 1Proxmox 用Proxmox ホストの IQN を明示指定(それ以外は拒否)
ID: 2k8s 用(新設)全許可(Initiators フィールド空欄)

democratic-csi の接続設定で targetGroupInitiatorGroup: 2 を明示指定することで、democratic-csi が作成する iSCSI ターゲットは最初から Initiator Group 2 に紐付けられます。Proxmox 用のターゲットは Initiator Group 1 に紐付けられているため、ターゲットレベルで分離されており、同一の Portal Group(ID: 1、ポート 3260)を共用しながら Proxmox と k8s のストレージが互いに干渉しない構成になっています。

k8s 用の Initiator Group を全許可にしているのは、k8s ノードの IQN が動的に変わりうることと、ノードを追加するたびに Initiator Group を更新する運用コストを避けるためです。iSCSI ターゲット名に nameSuffix: "-seichi-onp-k8s" を付与することで、k8s 用ボリュームと Proxmox 用ボリュームを名前で区別しています。

既存の iSCSI 設定がない場合は、全許可の Initiator Group を1つ作成するだけで問題ありません。

動作確認

以下の PVC と Pod を作成して動作を確認しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-sc-truenas-03-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: sc-truenas-03-iscsi
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: test-sc-truenas-03-pod
  namespace: default
spec:
  containers:
    - name: test
      image: busybox
      command: ["sh", "-c", "echo 'Hello from sc-truenas-03!' > /data/test.txt && cat /data/test.txt && echo 'Write test PASSED' && sleep 3600"]
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: test-sc-truenas-03-pvc
  restartPolicy: Never
1
2
3
4
5
6
7
$ kubectl get pvc test-sc-truenas-03-pvc
NAME                     STATUS   VOLUME                                     CAPACITY
test-sc-truenas-03-pvc   Bound    pvc-c71022aa-0f2c-41a2-83c3-db43a6eb7c75   1Gi

$ kubectl logs test-sc-truenas-03-pod
Hello from sc-truenas-03!
Write test PASSED

PVC が TrueNAS Scale から動的にプロビジョニングされ、Pod からの読み書きが正常に動作することを確認しました。

まとめ

  • CSI ドライバー: democratic-csi v0.15.1(freenas-api-iscsi ドライバー)
  • StorageClass: sc-truenas-03-iscsi(RWO、ext4、動的プロビジョニング)
  • VolumeSnapshotClass: sc-truenas-03-iscsi-vsc
  • 接続設定は existingConfigSecret で Kubernetes Secret から参照し、Helm values に秘匿情報を含めない
  • TrueNAS Scale 上の既存 Proxmox iSCSI 設定との共存を Initiator Group の分離で実現
Hugo で構築されています。
テーマ StackJimmy によって設計されています。