k8sでNFSマウント出来なくて困った話

はじめに

k8sでNFSマウントしようとすると

1Unable to mount volumes for pod "test_default(xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)": timeout expired waiting for volumes to attach/mount for pod "default"/"test". list of unattached/unmounted volumes=[nfs]

みたいなエラーで怒られて上手くいかなかったのでその原因の調べ方と設定時の注意点のメモ

そもそもどうやってマウントするの?みたいな話は公式のドキュメント見た方がわかりやすいのでそちらに譲ります
DockerホストでNFSをマウントして条件に合致するpodにデータボリュームでNFSの領域をマウントしてるっぽい

環境

相変わらずオンプレです.
物理マシンを2台にUbuntu16.04をインストールし,それぞれMasterとClusterとして設定してあります.
バージョンはv1.9.3です.

1$ kubectl version
2Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.3", GitCommit:"d2835416544f298c919e2ead3be3d0864b52323b", GitTreeState:"clean", BuildDate:"2018-02-07T12:22:21Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}
3Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.3", GitCommit:"d2835416544f298c919e2ead3be3d0864b52323b", GitTreeState:"clean", BuildDate:"2018-02-07T11:55:20Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}

今回はMaster側にNFS Serverを設定しましたが適宜別のマシン等でNFSを提供できるように設定しておきます.
一応exportsは制限なしで設定した上でこの記事を書いていますが仕組み的にDockerをホストしているマシンからさえマウントできれば問題ありません.

1$ tail -n 1 /etc/exports
2/opt/nfs *(rw,sync,no_subtree_check,no_root_squash)

設定ファイル

PVと作成してPVの条件に適合するPVCを作ってそれをpodにマウントしてやればOKです.
volume.beta.kubernetes.io/storage-class はあとでPVCがマウント可能なPVを探す際に条件として扱われるので値を合わせておく必要があります.
空欄にしておけばすべて適合する(はず

PV

 1$ cat nfs-pv.yml
 2apiVersion: v1
 3kind: PersistentVolume
 4metadata:
 5  name: nfs-pv
 6  annotations:
 7    volume.beta.kubernetes.io/storage-class: "nfs"
 8spec:
 9  capacity:
10    storage: 50Gi
11  accessModes:
12    - ReadWriteMany
13  persistentVolumeReclaimPolicy: Retain
14  nfs:
15    server: 192.168.xxx.xxx
16    path: /opt/nfs

作成して確認します.
既にpvc出来てますけど実際は空欄か何かになっています.

1$ kubectl create -f nfs-pv.yml
2$ kubectl get pv
3NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM               STORAGECLASS   REASON    AGE
4nfs-pv      50Gi       RWX            Retain           Bound     default/nfs-pvc   slow                     20m

PVC

合致するPVがないと永遠に使用可能にならないので上で作成したPVに合致するような設定を入れます.

 1$ cat nfs-pvc.yml
 2apiVersion: v1
 3kind: PersistentVolumeClaim
 4metadata:
 5  name: nfs-pvc
 6spec:
 7  accessModes:
 8    - ReadWriteMany
 9  resources:
10    requests:
11      storage: 50Gi
12  storageClassName: slow

こちらも作成して確認します.

1$ kubectl get pvc
2NAME        STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
3nfs-pvc   Bound     nfs-pv      50Gi       RWX            slow           38m

問題なく作成されていればひとまずpodでマウントできるか確認します.

 1$ cat nfs-pod.yml
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: nfs-test
 6spec:
 7  containers:
 8    - name: nfs-test
 9      image: nginx
10      volumeMounts:
11        - name: nfs
12          mountPath: "/var/www/"
13  volumes:
14    - name: nfs
15      persistentVolumeClaim:
16        claimName: nfs-pvc

あとはpod作って問題なく動けば終了です.

 1$ kubectl create -f nfs-pod.yml
 2pod "nfs-test" deleted
 3$ kubectl get pod
 4NAME      READY     STATUS    RESTARTS   AGE
 5nfs-test      1/1       Running   0          42m
 6$ kubectl describe pod nfs-test
 7Events:
 8  Type    Reason                 Age   From                 Message
 9  ----    ------                 ----  ----                 -------
10  Normal  Scheduled              11s   default-scheduler    Successfully assigned demo to ノード名
11  Normal  SuccessfulMountVolume  10s   kubelet, ノード名  MountVolume.SetUp succeeded for volume "nfs-pvc"
12  Normal  SuccessfulMountVolume  10s   kubelet, ノード名  MountVolume.SetUp succeeded for volume "default-token-xxxxxx"
13  Normal  Pulling                9s    kubelet, ノード名  pulling image "nginx"
14  Normal  Pulled                 6s    kubelet, ノード名  Successfully pulled image "nginx"
15  Normal  Created                6s    kubelet, ノード名  Created container
16  Normal  Started                6s    kubelet, ノード名  Started container

適当にファイルおいてみて確認しておわりです.

詰まったとことか

Node には必ず nfs-common が必要

漠然とDocker自体でマウントしているイメージで用意していませんでした.
先にDockerでNFSマウントできるか試したので先入観良くない.
describeすると以下のエラーが出ます.

 1$ kubectl get describe test
 2~省略~
 3Mounting command: systemd-run
 4Mounting arguments: --description=Kubernetes transient mount for /var/lib/kubelet/pods/xxxxxxxx-xxxx-xxxx-xxxxxxxx/volumes/kubernetes.io~nfs/nfs-pv --scope -- mount -t nfs 192.189.xxx.xxx:/opt/nfs /var/lib/kubelet/pods/xxxxxxxx-xxxx-xxxx-xxxxxxxx/volumes/kubernetes.io~nfs/nfs-pv
 5Output: Running scope as unit run-r9da60928545e43c49189115bc75d8d44.scope.
 6mount: wrong fs type, bad option, bad superblock on 192.189.xxx.xxx:/opt/nfs,
 7       missing codepage or helper program, or other error
 8       (for several filesystems (e.g. nfs, cifs) you might
 9       need a /sbin/mount.<type> helper program)
10
11       In some cases useful info is found in syslog - try
12       dmesg | tail or so.

nfs-common入れればマウントできるようになるので解決します.

1$ sudo apt-get install nfs-common

タイムアウトしてしまう

以下のようなエラーでマウント出来ない

1$ kubectl describe pod nfs-test
2~中略~
3Events:
4  Type     Reason                 Age   From                 Message
5  ----     ------                 ----  ----                 -------
6  Normal   Scheduled              2m    default-scheduler    Successfully assigned demo to ノード名
7  Normal   SuccessfulMountVolume  2m    kubelet, ノード名  MountVolume.SetUp succeeded for volume "default-token-xxxxx"
8  Warning  FailedMount            44s   kubelet, ノード名  Unable to mount volumes for pod "nfs-test_default(xxxxx-xxxx-xxxx-xxxxxx)": timeout expired waiting for volumes to attach/mount for pod "default"/"nfs-test". list of unattached/unmounted volumes=[nfs]

もう少し待ってると詳細エラーが出てきます

1Mounting command: systemd-run
2Mounting arguments: --description=Kubernetes transient mount for /var/lib/kubelet/pods/xxxxx-xxxx-xxxx-xxxxxx/volumes/kubernetes.io~xxxxx-xxxx-xxxx-xxxxxx/volumes/kubernetes.io~nfs/nfs-pvc
3Output: Running scope as unit run-xxxxx-xxxx-xxxx-xxxxxx.scope.
4mount.nfs: Connection timed out

メモし損ねましたがこの前後に実行されたmountコマンドが表示されているので実際にマウントできるかテストしましょう.
自分の場合はしょうもないですがnfs-pvのIPアドレスを打ち間違えていたことにここで気付きました.