nfsサーバを構築しKubernetesからストレージとして利用してみた

2022年7月2日

概要

こんにちは。

Kubernetesのpodは動作しているnodeにマウントしてデータを残すことは可能ですが、podが別nodeに存在していた場合、再利用がおこなえないので外部ストレージとしてnfsサーバを使用します。

nfsサーバの環境は、AlmaLinuxを使用し、Kubernetes環境は、Ubuntuを使用します。

nfsサーバを構築し、PersistentVolume(PV)とPersistentVolumeClaim(PVC)を作成し、作成したリソースをpodから使用します。

PV、PVCは永続化領域を要求するリソースです。

詳細は以下を参考にしてください。

NFSサーバ側での操作

NFSサーバインストール

NFSサーバのインストールおよびサービス開始と自動起動設定をします。

dnf install nfs-utils

・
・[中略]
・
インストール済み:
  gssproxy-0.8.0-19.el8.aarch64 keyutils-1.5.10-9.el8.aarch64  libverto-libevent-0.3.0-5.el8.aarch64 nfs-utils-1:2.3.3-46.el8.aarch64 python3-pyyaml-3.12-12.el8.aarch64
  quota-1:4.04-14.el8.aarch64   quota-nls-1:4.04-14.el8.noarch rpcbind-1.2.5-8.el8.aarch64

完了しました!

→NFSサーバのインストール。

systemctl --now enable nfs-server

Created symlink /etc/systemd/system/multi-user.target.wants/nfs-server.service → /usr/lib/systemd/system/nfs-server.service.

→NFSサーバインストールおよび自動起動有効化

共有するディレクトリの公開設定

筆者は、公開するディレクトリとして、 /export/nfs としています。

mkdir -p /export/nfs

→共有先ディレクトリ作成

cp -p /etc/exports /etc/exports.org

→設定ファイルのバックアップ。

cp -p /etc/exports /etc/exports_$(date +%Y%m%d)

→設定ファイルのバックアップ。

公開するディレクトリ、公開を許可するネットワークや権限を指定します。

設定はそれぞれの環境にあわせてください。

echo "/export/nfs 192.168.1.0/24(rw,sync,no_root_squash)" > /etc/exports

  • 192.168.1.0/24 公開先ホストネットワークを指定
  • (rw,sync,no_root_squash) 読み書きを許可し、即座に反映、クライアントのrootアクセスをサーバ上のrootとして扱う。

設定反映

exportfs -a

→先ほどの設定をエクスポートする。

systemctl restart nfs-server.service

→nfsサーバ再起動

exportfs

/export/nfs     192.168.1.0/24

→エクスポートされたことを確認。

podで使用する領域を作成

pod毎に領域を分割して使用できるようにしたいので、 /export/nfs 配下に pv0001 というディレクトリを作成しこちらの領域をKubernetes側で使用します。

mkdir /export/nfs/pv0001

→k8sで利用するpv領域を作成します。

k8s側でnfs領域をマウントするため、 apt-get install nfs-common コマンドで、必要なパッケージをワーカーノードおよび全クラスターにインストールします。(k8s側 OSはUbuntuを使用しております。)

※上記パッケージをインストールしないと、pod側でマウントができない可能性があります。

Kubernetes側での操作

マニフェスト作成

k8s側でpv、pvc、deployマニフェストを作成します。

mkdir pv-test
cd pv-test/

PV、PVCの動作イメージは以下を参考にしてください。

KubernetesのConfig&Storageリソース(その2)

PVリソース作成

server: 192.168.1.110 の部分は、先ほどのnfsサーバのIPを指定します。

path: /export/nfs/pv0001 の部分は、先ほど作成したpv領域を指定します。

vi create-persistent-volume.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0001
  annotations:
    volume.beta.kubernetes.io/storage-class: "slow"
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    server: 192.168.1.110
    path: /export/nfs/pv0001

kubectl create -f create-persistent-volume.yaml

→pvを作成します。

STATUSがAvailableになれば問題ありません。

ディレクトリが存在しないなど何かしら問題がある場合にはAvailableにならないので注意。

kubectl get pv

NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv0001   5Gi        RWO            Recycle          Available           slow                    32m

PVCリソースの作成

今度は、作成したpvを利用するpvcを作成します。

pvで annotations を指定しているので pvc でも必ず指定します。

annotations や accessModes がpv作成時の定義とマッチしないと割り当てに失敗します。

vi create-persitent-claim.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: centos-pv-claim
  labels:
    app: centos-pv-test
  annotations:
    "volume.beta.kubernetes.io/storage-class": "slow"
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

kubectl apply -f create-persitent-claim.yaml

→pvcを作成します。

pvc(PersistentVolumeClaim)pv(PersistentVolume) の確保に失敗すると、ステータスは Pending のままになります。

STATUSがBound状態であれば問題ありません。

kubectl get pvc

NAME              STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
centos-pv-claim   Bound    pv0001   5Gi        RWO            slow           29s

PODのデプロイ

作成したpvcを利用するpodをデプロイします。

volumes: -> persistentVolumeClaim: -> claimName: は pvc で指定した metadata: -> name: の値を設定します。

vi centos8-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: centos-pv-test-centos8
  labels:
    app: centos-pv-test
spec:
  selector:
    matchLabels:
      app: centos-pv-test
      tier: centos8
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: centos-pv-test
        tier: centos8
    spec:
      containers:
      - image: centos:8
        name: centos8
        command:
          - "/sbin/init"
        volumeMounts:
        - name: centos8-persistent-storage
          mountPath: /tmp
        securityContext:
          allowPrivilegeEscalation: true
          capabilities: {}
          privileged: true
          readOnlyRootFilesystem: false
          seLinuxOptions: {}
      volumes:
      - name: centos8-persistent-storage
        persistentVolumeClaim:
          claimName: centos-pv-claim

kubectl apply -f centos8-deployment.yaml --record

→podを作成します。

作成したpodのSTATUSがRunningになっていることを確認します。

kubectl get pod

NAME                                      READY   STATUS    RESTARTS   AGE
centos-pv-test-centos8-685fdfd555-78nck   1/1     Running   0          29s

実際にpodに入ってマウントされているか確認します。

dfコマンドで無事にマウントされていることが確認できました。

kubectl exec --stdin --tty centos-pv-test-centos8-685fdfd555-78nck -- bash

[root@centos-pv-test-centos8-685fdfd555-78nck /]# df -PTh

・
・{中略}
・
192.168.1.110:/export/nfs/pv0001 nfs4      29G  1.9G   27G   7% /tmp
・
・{中略}
・

試しにマウント領域でtestファイルを作成してます。

[root@centos-pv-test-centos8-685fdfd555-78nck /]# touch /tmp/test

nfsサーバ側で確認するとtestファイルができていることが確認できました。

ls -la /export/nfs/pv0001/

-rw-r--r-- 1 root root    0  2月  8 23:32 test

→nfsサーバ側から見ています。

podを削除します。

削除後も、マウント先のファイルは残り続けます。

kubectl delete -f centos8-deployment.yaml

※PV、PVCリソースを削除すると、NFSマウント領域、ココで言うと、 /var/nfs/pv0001/ 配下のファイルやディレクトリが削除されるので注意してください。

自動マウント処理

筆者の場合、materクラスターでnfsサーバのファイル管理したいのでk8sシステム側とは別に、自動マウントしたいと思います。

cp -p /etc/fstab /etc/fstab.org

cp -p /etc/fstab /etc/fstab_$(date +%Y%m%d)

fstabにまず記載します。

192.168.1.110はnfsサーバのIPになります。

vi /etc/fstab

192.168.1.110:/export/nfs /var/nfs nfs defaults 0 0

自動マウントに必要なパッケージをインストールします。

apt -y install autofs

Creating config file /etc/auto.master with new version

Creating config file /etc/auto.net with new version

Creating config file /etc/auto.misc with new version

Creating config file /etc/auto.smb with new version

Creating config file /etc/autofs.conf with new version

Creating config file /etc/default/autofs with new version
update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults
Created symlink /etc/systemd/system/multi-user.target.wants/autofs.service → /lib/systemd/system/autofs.service.
man-db (2.9.3-2) のトリガを処理しています ...
systemd (246.6-1ubuntu1.7) のトリガを処理しています ...

cp -p /etc/auto.master /etc/auto.master.org

cp -p /etc/auto.master /etc/auto.master_$(date +%Y%m%d)

最下行に追加します。

vi /etc/auto.master

/-    /etc/auto.mount

/etc/auto.mount は新規で作成する形となります。

vi /etc/auto.mount

/var/nfs -fstype=nfs,rw 192.168.1.110:/export/nfs

systemctl restart autofs

→設定を適用します。

cat /proc/mounts | grep "/var/nfs"

/etc/auto.mount /var/nfs autofs rw,relatime,fd=6,pgrp=2220,timeout=300,minproto=5,maxproto=5,direct,pipe_ino=69741 0 0

→設定が見られることを確認します。

k8s masterクラスター側でいつでもnfsサーバ側のマウント領域を操作できるようになりました。

dev_user@k8s-master:~/script/pv-test$ ls -la /var/nfs/pv0001/

合計 28
drwxrwxrwt 7 root root 4096  2月  8 23:32 .
drwxr-xr-x 3 root root 4096  2月  8 16:58 ..
drwxrwxrwt 2 root root 4096  2月  8 23:19 .ICE-unix
drwxrwxrwt 2 root root 4096  2月  8 23:19 .Test-unix
drwxrwxrwt 2 root root 4096  2月  8 23:19 .X11-unix
drwxrwxrwt 2 root root 4096  2月  8 23:19 .XIM-unix
drwxrwxrwt 2 root root 4096  2月  8 23:19 .font-unix
-rw-r--r-- 1 root root    0  2月  8 23:32 test

トラブルシューティング

timed out waiting for the condition という内容のメッセージが確認できます。

この場合、クライアントからnfsサーバに対して通信が許可されているか確認します。

手っ取り早く確認する方法としてdescribeコマンドで表示される以下コマンドを実行します。

マウント先は確認として /tmp を使用しています。

mount -t nfs 192.168.1.110:/export/nfs/pv0001 /tmp

Mounting command: mount
Mounting arguments: -t nfs 192.168.1.110:/export/nfs/pv0001 /var/lib/kubelet/pods/dec52547-a80b-4216-b273-88a1cf2d3daa/volumes/kubernetes.io~nfs/pv0001

kubectl get pod

NAME                                      READY   STATUS              RESTARTS   AGE
centos-pv-test-centos8-7675596dff-nxb8w   0/1     ContainerCreating   0          22m

kubectl describe pod/centos-pv-test-centos8-7675596dff-nxb8w

・
・[中略]
・
Events:
  Type     Reason       Age                  From               Message
  ----     ------       ----                 ----               -------
  Normal   Scheduled    22m                  default-scheduler  Successfully assigned default/centos-pv-test-centos8-7675596dff-nxb8w to k8s-node-a
  Warning  FailedMount  6m50s (x5 over 20m)  kubelet            Unable to attach or mount volumes: unmounted volumes=[centos8-persistent-storage], unattached volumes=[default-token-46xm2 centos8-persistent-storage]: timed out waiting for the condition
  Warning  FailedMount  92s (x9 over 20m)    kubelet            MountVolume.SetUp failed for volume "pv0001" : mount failed: exit status 32
Mounting command: mount
Mounting arguments: -t nfs 192.168.1.110:/export/nfs/pv0001 /var/lib/kubelet/pods/dec52547-a80b-4216-b273-88a1cf2d3daa/volumes/kubernetes.io~nfs/pv0001
Output: mount.nfs: Connection timed out
  Warning  FailedMount  2s (x5 over 18m)  kubelet  Unable to attach or mount volumes: unmounted volumes=[centos8-persistent-storage], unattached volumes=[centos8-persistent-storage default-token-46xm2]: timed out waiting for the condition

-v オプションを追加で付加しマウントしていみると、timeoutしていることが確認できます。

mount -v -t nfs 192.168.1.110:/export/nfs/pv0001 /tmp/

mount.nfs: timeout set for Tue Feb  8 22:15:19 2022
mount.nfs: trying text-based options 'vers=4.2,addr=192.168.1.110,clientaddr=192.168.1.108'

nfsサーバ側でポートが空いているか確認します。

nmapで確認するとfilteredになっています。

openになっていないといけないのでnfsサーバ側を確認したところ、firewalldが有効になっており通信が届かない状態でしたので停止したところ、openになり無事にマウントできました。

nmap -v -sT 192.168.1.110 -p 2049

PORT     STATE    SERVICE
2049/tcp filtered nfs

nmap -v -sT 192.168.1.110 -p 111

PORT    STATE SERVICE
111/tcp filtered  rpcbind

まとめ

Kubernetesストレージについて触れてみました。

難しいですが、慣れるまで辛抱です。

参考文献

KubernetesでNFSを利用してPersistentStorageを準備する

CentOS 8 でNFSサーバー構築 – LIGLOG INFRA JOURNAL

KubernetesのConfig&Storageリソース(その2)

Kubernetes道場 8日目 – ReplicaSet / Deploymentについて

Kubernetes: Deployment の仕組み

Deployment | Kubernetes

NFS : NFS クライアントの設定