Kubernetesで使用できるローカルの永続ボリューム

テクノロジー

前置き

 サイオステクノロジーの中島です。Kubernetesで動かしているコンテナのデータを保存したりする場合は永続ボリューム機能を使用する必要がありますので、完全なローカルで使用する場合について、三パターン(hostpath、NFS、iSCSI)に分けて使用する方法について説明します。

永続ボリューム機能とは

 PersistentVolume(PV)とPersistentVolumeClaim(PVC)のAPIを使用して用意される機能のことで、これら2点を定義することで、Pod内で作成されたデータをコンテナの外に保存することができます。

 詳細は、公式ドキュメント(https://kubernetes.io/ja/docs/concepts/storage/persistent-volumes/)を参照してください。本記事であげた、三つ以外で対応されているプラグインについて記載されています。

試験環境

 以下の構成を仮想環境上に構築して作業するものとします。

 各ノードの状態は以下の通りになります。

$ kubectl get node
NAME      STATUS   ROLES    AGE   VERSION
k8s-mm    Ready    master   40h   v1.19.2
k8s-ns    Ready    nas      40h   v1.19.2
k8s-wk1   Ready    worker   40h   v1.19.2
k8s-wk2   Ready    worker   40h   v1.19.2

hostpathを使用する

 永続ボリュームでhostpathを指定するとそれをマウントしたpodで、それが動作しているノード本体のフォルダパスにマウントされたディスク領域にデータを記載します。この方法は各ノードで動作させるためのライブラリーを追加でインストールする必要がありません。

Kubernetes作業

フォルダ構成

 Kubernetesで動作させるためのファイルのフォルダ構成を以下に示します。

./
├── pod
│    └── hostpath-test-pod.yaml
└── volume
     └── hostpath-volume.yaml

ファイル説明

 上記フォルダ構成内のファイル内のデータを以下に示します。

  • hostpath-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: hostpath-pv
spec:
  capacity:
    storage: 5Gi
  persistentVolumeReclaimPolicy: Retain
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/tmp/data"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: hostpathpvc
  annotations:
    volume.beta.kubernetes.io/persistent-volume: hostpath-pv
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  • hostpath-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: hostpath-pvc-pod
  name: hostpath-pv-pod1
spec:
  affinity:     #起動制限
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
            - key: node-role.kubernetes.io/worker
              operator: In
              values:
                - worker   #起動ノード指定
  containers:
  - name: hostpath-pv-busybox
    image: busybox
    command: ["/bin/sh", "-c"]
    args: [ "tail -f /dev/null" ]
    volumeMounts:
    - name: hostpath-vol1
      mountPath: /var/lib/busybox
      readOnly: false
  volumes:
  - name: hostpath-vol1
    persistentVolumeClaim:
      claimName: hostpathpvc

Kubernetes実行

 以下のコマンドで、永続ボリュームの設定を行う。

$ kubectl apply -f volume

 以下のコマンドでpodを起動させる

$ kubectl apply -f pod

動作確認

以下のコマンドで、起動させたpodが動作しているノードを調べる。

$ kubectl get pod -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP           NODE      NOMINATED NODE   READINESS GATES
hostpath-pv-pod1   1/1     Running   0          8s    10.244.1.9   k8s-wk1   <none>           <none>

 先ほど起動させたpodに入る

$ kubectl exec -it hostpath-pv-pod1 /bin/ash

 podのコンテナでマウントしたフォルダに向けてファイルを作成する。

# echo hello >> /var/lib/busybox/test.txt

 podが実行しているノードで、先ほどの作成したファイルが存在していることを確認する。

$ ssh k8s-wk1 ls -la /tmp/data
合計 12
drwxr-xr-x  2 root root 4096 10月 14 11:01 .
drwxrwxrwt 20 root root 4096 10月 14 11:00 ..
-rw-r--r--  1 root root    6 10月 14 11:01 test.txt

 ファイルの中身を確認する。

$ ssh k8s-wk1 cat /tmp/data/test.txt
hello

 また、podが起動していないWorkerで、フォルダができていないことを確認する。

$ ssh k8s-wk2 ls -la /tmp/data
ls: '/tmp/data' にアクセスできません: そのようなファイルやディレクトリはありません

NFSを使用する

 NFS(Network File System)を使用して、その共有フォルダをpodにマウントすることができます。これを使用すればNFSが動作しているサーバにデータを書き込むことができます。これをKubernetesで動作するには、NFSをマウントするために必要なライブラリをインストールします。なお、NFSは設定するのが容易ですが、速度が遅いことが欠点になります。

事前準備

 k8s-nsをNFSのファイルサーバとするためk8s-nsノードで以下の作業を行いサーバを構築します。

 サーバのインストールを以下のコマンドで行います。

$ sudo apt install -y nfs-kernel-server

 以下のコマンドで、公開するフォルダを作成します。

$ sudo mkdir -p /nfs/data
$ sudo chown nobody.nogroup /nfs/data/

 以下のデータを/etc/exportsの最終行に記載する。

/nfs/data 192.168.0.0/24(rw,sync,fsid=0,crossmnt,no_subtree_check,insecure,all_squash)

 以下のコマンドで、先ほどの設定を有効にする

$ sudo exportfs -ra

 すべてのノードでNFSのフォルダをマウントできるようにライブラリを追加する。

$ sudo apt install -y nfs-common

Kubernetes作業

フォルダ構成

 Kubernetesで実行するためのフォルダ構成を以下に示す。

./
├── pod
│    └── nfs-test-pod.yaml
└── volume
     └── nfs-volume.yaml

ファイル説明

 上記フォルダ構成内のファイル内のデータを以下に示します。

  • nfs-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 5Gi
  persistentVolumeReclaimPolicy: Retain
  accessModes:
    - ReadWriteOnce
  nfs:
    server: 192.168.0.133
    path: "/nfs/data"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfs-pvc
  annotations:
    volume.beta.kubernetes.io/persistent-volume: nfs-pv
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  • nfs-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: nfs-pvc-pod
  name: nfs-pv-pod1
spec:
  affinity:     #起動制限
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
            - key: node-role.kubernetes.io/worker
              operator: In
              values:
                - worker   #起動ノード指定
  containers:
  - name: nfs-pv-busybox
    image: busybox
    command: ["/bin/sh", "-c"]
    args: [ "tail -f /dev/null" ]
    volumeMounts:
    - name: nfs-vol1
      mountPath: /var/lib/busybox
      readOnly: false
  volumes:
  - name: nfs-vol1
    persistentVolumeClaim:
      claimName: nfs-pvc

Kubernetes実行

 以下のコマンドで、永続ボリュームの設定を行う。

$ kubectl apply -f volume

 以下のコマンドでpodを起動させる

$ kubectl apply -f pod

動作確認

 先ほど起動させたpodに入る

$ kubectl exec -it nfs-pv-pod1 /bin/ash

 podのコンテナでマウントしたフォルダに向けてファイルを作成する。

# echo hello >> /var/lib/busybox/test.txt

 podでマウントしたフォルダのポイントに、先ほど作成したファイルが存在していることを確認する。

$ ssh k8s-ns ls -la /nfs/data
合計 12
drwxr-xr-x 2 nobody nogroup 4096 10月 14 11:10 .
drwxr-xr-x 3 root   root    4096 10月 14 10:23 ..
-rw-r--r-- 1 nobody nogroup    6 10月 14 11:10 test.txt

 作成されたファイルの中身を確認する。

$ ssh k8s-ns cat /nfs/data/test.txt
hello

iSCSIを使用する

 iSCSI(Internet Small Computer System Interface)を使用して、共有ディスクをpod内のフォルダにマウントすることができます。これを使用するのにNFSと同じようにライブラリをすべてのノードで導入する必要があります。なお、NFSより高速のストレージを使用することができますがNFSの設定より複雑な設定になります。

事前準備

 サーバとなるk8s-nsノードで以下の作業を行い、iSCSIサーバにします。

$ sudo apt -y install tgt

 5Gのイメージを作成します。

$ sudo mkdir /var/lib/iscsi_disks
$ sudo dd if=/dev/zero of=/var/lib/iscsi_disks/disk01.img count=0 bs=1 seek=5G

 設定ファイルを作成します。

$ sudo sh -c "cat <<EOF> /etc/tgt/conf.d/target01.conf
<target iqn.2020-10.local:k8s-ns.target01>
    backing-store /var/lib/iscsi_disks/disk01.img
    initiator-name iqn.2020-10.local:k8s-mm.initiator01
    # ( username, password は任意のものを設定)
    incominguser username password
</target>
EOF
"

 作成した設定ファイルを有効にします。

$ sudo systemctl restart tgt

 全てのノードで以下のコマンドを実行してiSCSIが実行できるようにします。

$ sudo apt install -y open-iscsi xfsprogs

 以下のコマンドで、設定ファイルを書き換えます。

$ sudo vi /etc/iscsi/initiatorname.iscsi

 設定は以下のように書き換えます。

#InitiatorName=iqn.1993-08.org.debian:01:da97a3f725a0
InitiatorName=iqn.2020-10.local:k8s-mm.initiator01

 以下のコマンドで、認証の設定ファイルを書き換えます。

$ sudo vi /etc/iscsi/iscsid.conf

 以下の通り、一部のコメントアウトを解除して、usernameやpasswordを設定どおり変更する

# To enable CHAP authentication set node.session.auth.authmetho
# to CHAP. The default is None.
node.session.auth.authmethod = CHAP
# To set a CHAP username and password for initiator
# authentication by the target(s), uncomment the following lines:
node.session.auth.username = username
node.session.auth.password = passwordd

 設定を有効にする。

$ sudo systemctl restart iscsid open-iscsi

 接続先の設定を追加する。

$ sudo iscsiadm -m discovery -t sendtargets -p 192.168.0.133

xfsフォーマット

 このままでは、フォーマットされていないため対象となるディスクでxfsフォーマットを行い使用できるようにします。

 まず、どのノードでもいいので、iSCSIをデバイスマウントする。

$ sudo iscsiadm -m node --login

 マウントしたデバイスをxfsフォーマットする

$ sudo mkfs.xfs /dev/sdb

 フォーマットが終わったら、iSCSIをデバイスアンマウントします。

$ sudo iscsiadm -m node --logout

Kubernetes作業

フォルダ構成

 Kubernetesで実行するためのフォルダ構成を以下に示す。

./
├── pod
│    └── iscsi-test-pod.yaml
└── volume
     ├── iscsi-chap-secret.yaml
     └── iscsi-volume.yaml

ファイル説明

 上記フォルダ構成内のファイル内のデータを以下に示します。

  • iscsi-chap-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: iscsi-targetd-chap-secret
type: "kubernetes.io/iscsi-chap"
data:
  discovery.sendtargets.auth.username: dXNlcm5hbWUK
  discovery.sendtargets.auth.password: cGFzc3dvcmQK

 上記の設定で、usernameやpasswordはbase64フォーマットしたデータが記載されています。iSCSIで設定されたusernameやpasswordを必要に応じて変更してください。

  • iscsi-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: iscsi-pv
spec:
  capacity:
    storage: 5Gi
  persistentVolumeReclaimPolicy: Retain
  accessModes:
    - ReadWriteOnce
  iscsi:
    targetPortal: 192.168.0.133:3260
    iqn: iqn.2020-10.local:k8s-ns.target01
    lun: 1
    fsType: xfs
    chapAuthDiscovery: true 
    chapAuthSession: true
    readOnly: false 
    secretRef:
      name: iscsi-targetd-chap-secret
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: iscsi-pvc
  annotations:
    volume.beta.kubernetes.io/persistent-volume: iscsi-pv
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  • iscsi-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: iscsi-pvc-pod
  name: iscsi-pv-pod1
spec:
  containers:
  - name: iscsi-pv-busybox
    image: busybox
    command: ["/bin/sh", "-c"]
    args: [ "tail -f /dev/null" ]
    volumeMounts:
    - name: iscsi-vol1
      mountPath: /var/lib/busybox
      readOnly: false
  volumes:
  - name: iscsi-vol1
    persistentVolumeClaim:
      claimName: iscsi-pvc

Kubernetes実行

以下のコマンドで、永続ボリュームの設定を行う。

$ kubectl apply -f volume

以下のコマンドでpodを起動させる

$ kubectl apply -f pod

動作確認

 先ほど起動したpodに入ります。

$ kubectl exec -it iscsi-pv-pod1 /bin/ash

 pod内にマウントしたフォルダに向けてファイルを作成する。

# echo hello >> /var/lib/busybox/test.txt

 先ほどpodで作成されたファイルが、iSCSIのディスクに作成されていることを確認します。

 確認するため、masterノードにiSCSIのディスクをデバイスマウントする。

$ sudo iscsiadm -m node --login

 /mntフォルダに先ほどデバイスマウントしたディスクをマウントする

$ sudo mount /dev/sdb /mnt

 podが作成ファイルが作成されていることを確認します。

$ ls -la /mnt
合計 8
drwxrwsr-x  2 root 1001   22 10月 14 11:14 .
drwxr-xr-x 20 root root 4096 10月 12 18:33 ..
-rw-r--r--  1 root 1001    6 10月 14 11:14 test.txt

 ファイルの中身を確認します。

$ cat /mnt/test.txt
hello