Kubernetes: NFSのCSIドライバーを動かして、CSIの動作を調べてみた

# はじめに

Kubernetes上でボリュームを調達してPodにマウントして使う場合に、CSI（Container Storage Interface）と呼ばれるインターフェースを使うことが多いです。例えばAmazon EBSを使いたい場合はAmazon EBS CSI Driver、オンプレミスのKubernetesでOpenEBSを使いたい時はOpenEBS CSI Driver等が利用可能です。CSIを使うと、Kubernetes上でStorageClass、PVC、PV等のリソースにより、様々なストレージを共通の方法で利用できるようになります。

今回はCSIがどんな動きをしているのかを、NFSのCSIドライバー（NFS CSI Driver）を使って調べてみました。利用するCSIドライバーは、Kubernetes CSIのGitHubで公開されている以下のcsi-driver-nfsです。

https://github.com/kubernetes-csi/csi-driver-nfs

# 必要条件

以下が準備できている必要があります。本記事では、それぞれの詳細については触れません。

* Kubernetesクラスターを構築済であること
* Kubernetesのノードからアクセス可能なNFSサーバがあること
* kubectlを実行するマシンに、HelmとHelmfileがインストールされていること

# csi-driver-nfs のHelmチャートのインストール

以下のHelmfileを使ってインストールします。

```yaml:csi-driver-nfs.yaml
repositories:

- name: csi-driver-nfs
  url: https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts

releases:

- name: csi-driver-nfs
  namespace: kube-system
  chart: csi-driver-nfs/csi-driver-nfs
  version: v4.9.0
  values:
  - storageClass:
      create: true
      name: nfs-csi
      parameters:
        server: 10.0.0.5       # 構築済みのNFSサーバのホスト名を記載
        share: /srv/nfs_share  # NFSサーバで /etc/exports で共有しているディレクトリを記載
      mountOptions:
      - nfsvers=4.1
```

インストールコマンド
```
helmfile apply -f csi-driver-nfs.yaml
```

## 作成されたリソースの確認

ワークロードリソースおよびサービスリソースは、以下の DaemonSet、Deployment が作成されています。

```
$ kubectl get deploy,ds -n kube-system -l helm.sh/chart=csi-driver-nfs-v4.9.0
NAMESPACE     NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/csi-nfs-controller   1/1     1            1           2m9s

NAMESPACE     NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/csi-nfs-node   2         2         2       2            2           kubernetes.io/os=linux   2m9s
```

またストレージに関するリソースとして、以下の ``nfs-csi`` というStorageClass が作成されます。

```
 kubectl get storageclass
NAME      PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-csi   nfs.csi.k8s.io   Delete          Immediate           false                  4m43s
```



csi-nfs-controller と csi-nfs-node に関して、各Podにどんなコンテナが作られているかを確認すると、以下のように複数立ち上がっているのが分かります。

**csi-nfs-controller(Deployment) の Pod で使われているコンテナ**
```
$ kubectl get deploy -n kube-system csi-nfs-controller -o jsonpath='{range .spec.template.spec.containers[*]}- Name:  {.name}{"\n"}  Image: {.image}{"\n"}{end}'
- Name:  csi-provisioner
  Image: registry.k8s.io/sig-storage/csi-provisioner:v5.0.2
- Name:  csi-snapshotter
  Image: registry.k8s.io/sig-storage/csi-snapshotter:v8.0.1
- Name:  liveness-probe
  Image: registry.k8s.io/sig-storage/livenessprobe:v2.13.1
- Name:  nfs
  Image: registry.k8s.io/sig-storage/nfsplugin:v4.9.0
```

**csi-nfs-node(DaemonSet) の Pod で使われているコンテナ**
```
$ kubectl get ds -n kube-system csi-nfs-node -o jsonpath='{range .spec.template.spec.containers[*]}- Name:  {.name}{"\n"}  Image: {.image}{"\n"}{end}'
- Name:  liveness-probe
  Image: registry.k8s.io/sig-storage/livenessprobe:v2.13.1
- Name:  node-driver-registrar
  Image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.11.1
- Name:  nfs
  Image: registry.k8s.io/sig-storage/nfsplugin:v4.9.0
```

この状態を図にしてみましょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/15e44676-7c75-0989-d3d0-90e84e79d5c1.png" width=100%>

色分けしたそれぞれのコンテナは、以下の機能を持ちます。

### Kubernetes CSI Sidecar Container（オレンジ色）

NFSドライバに限らず、他のCSIドライバでも共通に利用するサイドカーコンテナです。Kubernetes APIと通信して、その内容を後述のCSI driver containerに伝えます。正式な情報は[こちら](https://kubernetes-csi.github.io/docs/sidecar-containers.html)を参照ください。

### Third-party CSI Driver Container（水色）

本記事の例では「NFS用のCSIプラグインとしてNFSストレージ固有に使われるコンテナ」ですが、一般的には CSI Driver と呼ばれています。サイドカーコンテナから届いたリクエストに応じて、実際のストレージにボリュームを作ったりマウントしたりします。
こちらはサイドカーコンテナとは異なり、利用するストレージによって各ベンダーから提供されるもの（例えばAmazon EBS用とかCephFS用とか）を使います。
<br>

CSIドライバーはこのように、「ストレージ固有のCSI Driver」と「Kubernetes APIと通信するサイドカーコンテナ」が連携して動作する仕組みになっています。各コンテナで役割を分けることで、CSI driverを開発するベンダーは Kubernetes API の仕様や通信を気にせずに、ストレージ固有のロジックに集中して実装できるメリットがあります。

# PVCを作ってみる

それでは、さきほどインストールした NFS CSI driver を使ってPVCを作ってみましょう。
以下のマニフェストを用意します。`storageClassName` を `nfs-csi` に指定するのがポイントです。

```yaml:nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
  namespace: default
spec:
  storageClassName: nfs-csi
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
```

実行コマンド

```
$ kubectl apply -f nfs-pvc.yaml
persistentvolumeclaim/nfs-pvc created
```

PVCだけでなく、動的プロビジョニングによりPVも作られました。
```
$ kubectl get pvc,pv -n default
NAME                            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/nfs-pvc   Bound    pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a   1Gi        RWX            nfs-csi        <unset>                 6h9m

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a   1Gi        RWX            Delete           Bound    default/nfs-pvc   nfs-csi        <unset>                          6h9m
```

NFSサーバが起動しているホスト上の端末でも、次のようにPVに対応するディレクトリが作られたのを確認できます。

```
[host-of-nfs-server]$ ls -l /srv/nfs_share/
total 4
drwxr-xr-x 2 nobody nogroup 4096 Nov  8 22:29 pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a
```

## どのようにしてボリュームが作られたのか？

PVCが作られた際に、CSIドライバーを使ってボリュームがどのように作られるかを図にしてみました。ボリューム作成で関係するのは ``csi-nfs-controller`` のDeploymentリソースのみです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/d1c55422-10a3-3c02-861d-ac6d9f2c87e7.png" width=100%>

PVCが作られると、``csi-provisioner``コンテナ がPVCが作られたというイベントを検知します。その内容をCSI Driverの ``nfs``コンテナ に通知して、NFSボリュームが作られるという流れです。

上記の流れを、実際にログで確認してみましょう。

### ログで確認： (1)PVC作成を検知 

``csi-provisioner``のログを確認すると、

```
kubectl logs -n kube-system deploy/csi-nfs-controller -c csi-provisioner
```

以下ログの1行目で、PVC作成のイベントを検知しているのがわかります。

```
I1108 22:29:25.621276       1 event.go:389] "Event occurred" object="default/nfs-pvc" fieldPath="" kind="PersistentVolumeClaim" apiVersion="v1" type="Normal" reason="Provisioning" message="External provisioner is provisioning volume for claim \"default/nfs-pvc\""
I1108 22:29:26.169109       1 controller.go:955] successfully created PV pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a for PVC nfs-pvc and csi volume name 10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##
I1108 22:29:26.179005       1 event.go:389] "Event occurred" object="default/nfs-pvc" fieldPath="" kind="PersistentVolumeClaim" apiVersion="v1" type="Normal" reason="ProvisioningSucceeded" message="Successfully provisioned volume pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a"
```

### ログで確認： (2)ボリューム作成リクエスト ~ (3)ボリューム作成 ~ (4)PV作成

``nfs``のログを確認すると、

```
kubectl logs -n kube-system deploy/csi-nfs-controller -c nfs
```
以下のログが出力されます。
```
I1108 22:29:25.622630       1 utils.go:110] GRPC call: /csi.v1.Controller/CreateVolume
I1108 22:29:25.622698       1 utils.go:111] GRPC request: {"capacity_range":{"required_bytes":1073741824},"name":"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a","parameters":{"csi.storage.k8s.io/pv/name":"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a","csi.storage.k8s.io/pvc/name":"nfs-pvc","csi.storage.k8s.io/pvc/namespace":"default","server":"10.0.0.5","share":"/srv/nfs_share"},"volume_capabilities":[{"AccessType":{"Mount":{"mount_flags":["nfsvers=4.1"]}},"access_mode":{"mode":5}}]}
I1108 22:29:25.623128       1 controllerserver.go:496] internally mounting 10.0.0.5:/srv/nfs_share at /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a
I1108 22:29:25.623316       1 nodeserver.go:132] NodePublishVolume: volumeID(10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##) source(10.0.0.5:/srv/nfs_share) targetPath(/tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a) mountflags([nfsvers=4.1])
I1108 22:29:25.625159       1 mount_linux.go:243] Detected OS without systemd
I1108 22:29:25.625191       1 mount_linux.go:218] Mounting cmd (mount) with arguments (-t nfs -o nfsvers=4.1 10.0.0.5:/srv/nfs_share /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a)
I1108 22:29:26.136750       1 nodeserver.go:149] skip chmod on targetPath(/tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a) since mountPermissions is set as 0
I1108 22:29:26.136795       1 nodeserver.go:151] volume(10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##) mount 10.0.0.5:/srv/nfs_share on /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a succeeded
I1108 22:29:26.140767       1 controllerserver.go:511] internally unmounting /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a
I1108 22:29:26.140808       1 nodeserver.go:172] NodeUnpublishVolume: unmounting volume 10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a## on /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a
I1108 22:29:26.140819       1 nodeserver.go:177] force unmount 10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a## on /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a
I1108 22:29:26.141001       1 mount_helper_common.go:56] unmounting "/tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a" (corruptedMount: false, mounterCanSkipMountPointChecks: true)
I1108 22:29:26.141020       1 mount_linux.go:789] Unmounting /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a
I1108 22:29:26.164058       1 mount_helper_common.go:150] Deleting path "/tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a"
I1108 22:29:26.166352       1 nodeserver.go:185] NodeUnpublishVolume: unmount volume 10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a## on /tmp/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a successfully
I1108 22:29:26.166567       1 utils.go:117] GRPC response: {"volume":{"volume_context":{"csi.storage.k8s.io/pv/name":"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a","csi.storage.k8s.io/pvc/name":"nfs-pvc","csi.storage.k8s.io/pvc/namespace":"default","server":"10.0.0.5","share":"/srv/nfs_share","subdir":"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a"},"volume_id":"10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##"}}
```

ログの各箇所で、以下が実行されたことを確認できます。

* (2) ボリューム作成リクエスト : 1行目
    * ``csi-provisioner``からgRPCで、CreateVolumeというリクエストが来ている
* (3) ボリューム作成 : 3~15行目
    * ``/tmp`` ディレクトリに一時的にNFSをマウントして、``pvc-7d13...`` という名前のボリュームを作成している
* (4) PV作成 : 2,16行目
    * gRPCでPV作成のリクエストをしてレスポンスが返っている

# PodにNFSボリュームをマウントしてみる

続いて、PVCを経由してPodにNFSボリュームをマウントしてみます。

以下のマニフェストを使います。

```yaml:mnt-nfs-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mnt-nfs-pod
  namespace: default
spec:
  containers:
  - name: mnt-nfs-pod
    image: busybox
    command:
    - tail
    - -f
    - /dev/null
    volumeMounts:
    - name: nfs-volume
      mountPath: /data
  volumes:
  - name: nfs-volume
    persistentVolumeClaim:
      claimName: nfs-pvc
```

Podを作成します。
```
kubectl apply -f mnt-nfs-pod.yaml
```
Podが作成されて、Pod内の ``/data`` ディレクトリにNFSボリュームがマウントされたことが確認できます。

```
$ kubectl get pod -n default
NAME          READY   STATUS    RESTARTS   AGE
mnt-nfs-pod   1/1     Running   0          41s

$ kubectl exec -n default mnt-nfs-pod -- df -h | grep /data
                         14.4G      8.8G      5.5G  62% /data
```

## どのようにしてボリュームがPodにマウントされたのか？

こちらもCSI Driverを使ってボリュームがPodにマウントされる様子を図示してみます。Podの配置が決まったノードで起動しているkubeletと、``csi-nfs-node``のPodが今回は登場します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/5f0900c1-8af3-32c4-00e4-f579e69893c1.png" width=100%>

Podがデプロイされるノードが決まると、そのノードで稼働しているkubeletが ``csi-nfs-node``の``nfs``コンテナ経由で提供されるマウントポイントを呼び出します。それを受けて、``nfs``コンテナが ``mnt-nfs-pod``のPodの ``/data`` ディレクトリに対してマウントを実行します。

### ログで確認： (1)マウントポイント呼出

起動したPodのNode上で kubelet のログを確認します。

```
journalctl -xeu kubelet
```

以下ログ（各行の先頭部分は非表示）の1,4行目に、NFSボリュームのマウントに関連しそうなメッセージが出ています。

```
I1109 04:44:35.529999     765 reconciler_common.go:245] "operationExecutor.VerifyControllerAttachedVolume started for volume \"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a\" (UniqueName: \"kubernetes.io/csi/nfs.csi.k8s.io^10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##\") pod \"mnt-nfs-pod\" (UID: \"ea906b1b-7336-406f-8bb4-d8e13ef81d04\") " pod="default/mnt-nfs-pod"
I1109 04:44:35.530088     765 reconciler_common.go:245] "operationExecutor.VerifyControllerAttachedVolume started for volume \"kube-api-access-2jjmj\" (UniqueName: \"kubernetes.io/projected/ea906b1b-7336-406f-8bb4-d8e13ef81d04-kube-api-access-2jjmj\") pod \"mnt-nfs-pod\" (UID: \"ea906b1b-7336-406f-8bb4-d8e13ef81d04\") " pod="default/mnt-nfs-pod"
I1109 04:44:35.639210     765 csi_attacher.go:380] kubernetes.io/csi: attacher.MountDevice STAGE_UNSTAGE_VOLUME capability not set. Skipping MountDevice...
I1109 04:44:35.639278     765 operation_generator.go:580] "MountVolume.MountDevice succeeded for volume \"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a\" (UniqueName: \"kubernetes.io/csi/nfs.csi.k8s.io^10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##\") pod \"mnt-nfs-pod\" (UID: \"ea906b1b-7336-406f-8bb4-d8e13ef81d04\") device mount path \"/var/lib/kubelet/plugins/kubernetes.io/csi/nfs.csi.k8s.io/5263efb4ed712e05427adcaa418778b03e13c046edc3ea4a9ab867ea11f8cd8d/globalmount\"" pod="default/mnt-nfs-pod"
I1109 04:44:38.587628     765 pod_startup_latency_tracker.go:104] "Observed pod startup duration" pod="default/mnt-nfs-pod" podStartSLOduration=2.312397567 podStartE2EDuration="3.587609387s" podCreationTimestamp="2024-11-09 04:44:35 +0000 UTC" firstStartedPulling="2024-11-09 04:44:36.81953173 +0000 UTC m=+479.945761594" lastFinishedPulling="2024-11-09 04:44:38.09474355 +0000 UTC m=+481.220973414" observedRunningTime="2024-11-09 04:44:38.586733896 +0000 UTC m=+481.712963780" watchObservedRunningTime="2024-11-09 04:44:38.587609387 +0000 UTC m=+481.713839271"
```

### ログで確認： (2)マウント実行

csi-nfs-nodeのログを見てみます。

```
kubectl logs -n kube-system ds/csi-nfs-node -c nfs
```

NodePublishVolume というgRPCのリクエストをkubeletから受けて、``-t nfs``のオプションでマウントを実行しているのがわかります。

```
I1109 04:44:35.655828       1 utils.go:110] GRPC call: /csi.v1.Node/NodePublishVolume
I1109 04:44:35.656029       1 utils.go:111] GRPC request: {"target_path":"/var/lib/kubelet/pods/ea906b1b-7336-406f-8bb4-d8e13ef81d04/volumes/kubernetes.io~csi/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a/mount","volume_capability":{"AccessType":{"Mount":{"mount_flags":["nfsvers=4.1"]}},"access_mode":{"mode":5}},"volume_context":{"csi.storage.k8s.io/pv/name":"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a","csi.storage.k8s.io/pvc/name":"nfs-pvc","csi.storage.k8s.io/pvc/namespace":"default","server":"10.0.0.5","share":"/srv/nfs_share","storage.kubernetes.io/csiProvisionerIdentity":"1731104072010-4747-nfs.csi.k8s.io","subdir":"pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a"},"volume_id":"10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##"}
I1109 04:44:35.658545       1 nodeserver.go:132] NodePublishVolume: volumeID(10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##) source(10.0.0.5:/srv/nfs_share/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a) targetPath(/var/lib/kubelet/pods/ea906b1b-7336-406f-8bb4-d8e13ef81d04/volumes/kubernetes.io~csi/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a/mount) mountflags([nfsvers=4.1])
I1109 04:44:35.659827       1 mount_linux.go:243] Detected OS without systemd
I1109 04:44:35.660546       1 mount_linux.go:218] Mounting cmd (mount) with arguments (-t nfs -o nfsvers=4.1 10.0.0.5:/srv/nfs_share/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a /var/lib/kubelet/pods/ea906b1b-7336-406f-8bb4-d8e13ef81d04/volumes/kubernetes.io~csi/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a/mount)
I1109 04:44:36.190344       1 nodeserver.go:149] skip chmod on targetPath(/var/lib/kubelet/pods/ea906b1b-7336-406f-8bb4-d8e13ef81d04/volumes/kubernetes.io~csi/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a/mount) since mountPermissions is set as 0
I1109 04:44:36.190476       1 nodeserver.go:151] volume(10.0.0.5#srv/nfs_share#pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a##) mount 10.0.0.5:/srv/nfs_share/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a on /var/lib/kubelet/pods/ea906b1b-7336-406f-8bb4-d8e13ef81d04/volumes/kubernetes.io~csi/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a/mount succeeded
I1109 04:44:36.190503       1 utils.go:117] GRPC response: {}
```

ちなみにマウント先のパスが、

``/var/lib/kubelet/pods/ea906b1b-7336-406f-8bb4-d8e13ef81d04/volumes/kubernetes.io~csi/pvc-7d13ebab-8f44-4d9e-bc62-9d77eae1ec2a/mount/``

という非常に長い名前になっていますが、パスの途中に出てくる ``ea906b1b...`` は ``mnt-nfs-pod`` のPodのUIDと一致します。

```
$ kubectl get po -n default mnt-nfs-pod -o jsonpath='{.metadata.uid}'
ea906b1b-7336-406f-8bb4-d8e13ef81d04
```

したがって、CSI経由で動的プロビジョニングによりPodにマウントされたパスは、ノード上だと

``/var/lib/kubelet/pods/[pod-uid]/volumes/kubernetes.io~csi/[pv-name]/mount/``

に格納されるようです。

# おわりに

本記事では、CSIドライバー経由でPVCを作成してPodにマウントした場合の動きを実際にKubernetesリソースを作成して追ってみました。ただ今回の内容で、CSIドライバーで必須の全ての動作を説明しているわけではない（例えば ``csi-nfs-node`` の ``node-driver-registrar`` コンテナの説明はスキップしている）ことにご注意ください。