LoginSignup
0
1

More than 3 years have passed since last update.

[Kubernetes]PersistentVolume/PersistentVolumeClaimの動作を確認する 3

Posted at

はじめに

今回はPersistentVolume(PV)のアクセスモードの動作を確認したいと思います。
アクセスモードには以下の3つがあります。

アクセスモード 概要
ReadWriteOnce 単一のNodeで読み取り/書き込みとしてマウントできます
ReadOnlyMany 多数のNodeで読み取り専用としてマウントできます
ReadWriteMany 多数のNodeで読み取り/書き込みとしてマウントできます

ReadWriteManyはこれまで確認してますので、「ReadWriteOnce」「ReadOnlyMany」について確認します。
ReadWriteManyの動作はこちらをご参照ください。

ReadWriteOnce

環境準備

以下のマニフェストのPV/PVC/Podを作成します。

pv-rwo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 500Mi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /share
    server: k8s-client
pvc-rwo.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
  storageClassName: slow
nginx-dep-rwo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dep
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nginx-dep
  template:
    metadata:
      labels:
        app: nginx-dep
    spec:
      containers:
      - image: nginx:latest
        name: nginx-container
        volumeMounts:
        - mountPath: /cache
          name: cache-pv
      volumes:
      - name: cache-pv
        persistentVolumeClaim:
          claimName: myclaim
          readOnly: false
$ kubectl apply -f pv-rwo.yaml
persistentvolume/pv0003 created
$ kubectl apply -f pvc-rwo.yaml
persistentvolumeclaim/myclaim created
$ kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
pv0003   500Mi      RWO            Recycle          Bound    default/myclaim   slow                    55s
$ kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Bound    pv0003   500Mi      RWO            slow           9s
$ kubectl apply -f nginx-dep-rwo.yaml
deployment.apps/nginx-dep created
$ kubectl get pod -o wide
NAME                         READY   STATUS      RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx-dep-54b4455fbd-75vfj   1/1     Running     0          16s   192.168.79.79    k8s-worker01   <none>           <none>
nginx-dep-54b4455fbd-bkmsm   1/1     Running     0          16s   192.168.69.208   k8s-worker02   <none>           <none>
nginx-dep-54b4455fbd-hfsbs   1/1     Running     0          16s   192.168.79.65    k8s-worker01   <none>           <none>
nginx-dep-54b4455fbd-kc9dn   1/1     Running     0          16s   192.168.69.221   k8s-worker02   <none>           <none>

動作確認

1つのPVを4つのPodで共用した形になっています。また4つのPodはそれぞれworker01/worker02に分散してデプロイされています。

別ノードにデプロイされている2つのPodからPVに書き込んでみます。

$ kubectl exec -it nginx-dep-54b4455fbd-75vfj touch /cache/testfile
$ kubectl exec -it nginx-dep-54b4455fbd-75vfj ls /cache/
testfile
$ kubectl exec -it nginx-dep-54b4455fbd-bkmsm touch /cache/testfile2
$ kubectl exec -it nginx-dep-54b4455fbd-75vfj ls /cache/
testfile  testfile2

書き込みできましたね。。。
調べてみると、ReadWriteOnceは各Podからのアクセスを制御するものではないようです。

参考
https://www.kimullaa.com/entry/2020/02/20/212517

また、GCPのマニュアルですが、ReadWriteOnceはDeployment(ReplicaSet)では使用しないで、StatefulSetで使用するものだと書かれています。

Deployment はステートレス アプリケーション用に設計されているため、Deployment のすべてのレプリカで同じ PersistentVolumeClaim が共有されます。作成されたレプリカ Pod はそれぞれ同一であるため、この設定では ReadOnlyMany モードと ReadWriteMany モードのボリュームだけが動作します。
・・・中略・・・
この場合は ReadWriteOnce ボリュームで StatefulSet を使用します。

https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes?hl=ja#deployments_vs_statefulsets

StatefulSetの作成

DeploymentからStatefulSetに変えて、再度確認します。
まず、Deploymentは削除しておきます。

$ kubectl delete -f nginx-dep-rwo.yaml
deployment.apps "nginx-dep" deleted

以下のマニフェストのStatefulSetをapplyします。

nginx-statefulset-rwo.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "slow"
      resources:
        requests:
          storage: 500Mi
$ kubectl apply -f nginx-statefulset-rwo.yaml
statefulset.apps/web created
$ kubectl get statefulsets
NAME   READY   AGE
web    0/3     22s
$ kubectl get pod
web-0                 0/1     Pending     0          27s
$ kubectl describe pod web-0
Name:           web-0
・・・
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  46s (x2 over 46s)  default-scheduler  error while running "VolumeBinding" filter plugin for pod "web-0": pod has unbound immediate PersistentVolumeClaims

PodがPendingになっているので調べてみると、PVCのBoundに失敗しているようです。

いったん削除します。

$ kubectl delete -f nginx-statefulset-rwo.yaml
statefulset.apps "web" deleted
$ kubectl get pvc
NAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim     Bound     pv0003   500Mi      RWO            slow           23h
www-web-0   Pending                                      slow           2m40s
$ kubectl delete pvc www-web-0
persistentvolumeclaim "www-web-0" deleted

PodやDeploymentと違って、StatefulSetのマニフェストの中でPVを要求しているんですね。知らなかった・・・
ちなみに、StatefulSetで作成されるPVCはStatefulSetを削除しても残ります。PVCは個別に削除する必要があります。


myclaimを削除して、再度StatefulSetをapplyします。

$ kubectl delete -f pvc-rwo.yaml
persistentvolumeclaim "myclaim" deleted
$ kubectl apply -f nginx-statefulset-rwo.yaml
statefulset.apps/web created
$ kubectl get statefulsets -o wide
NAME   READY   AGE    CONTAINERS   IMAGES
web    1/4     100s   nginx        k8s.gcr.io/nginx-slim:0.8
$ kubectl get pod
web-0                 1/1     Running     0          84s
web-1                 0/1     Pending     0          12s

2つ目のPodがPendingになっています。

$ kubectl get pvc
NAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound     pv0003   500Mi      RWO            slow           8m51s
www-web-1   Pending                                      slow           7m39s

PVCを確認すると、2つ目のPVCがPendingになってますね。
PVCは1つなのかと思いましたが、1つのPodに1つのPVCが作成されるようです。ってことは、PVもPodの数分必要になるということですね。


PVを全部で3つにしました。

$ kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
pv0001   500Mi      RWO            Recycle          Bound       default/www-web-0   slow                    24s
pv0002   500Mi      RWO            Recycle          Bound       default/www-web-1   slow                    24s
pv0003   500Mi      RWO            Recycle          Available   default/www-web-2   slow                    18s
$ kubectl get pvc
NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pv0001   500Mi      RWO            slow           21s
www-web-1   Bound    pv0002   500Mi      RWO            slow           17s
www-web-2   Bound    pv0003   500Mi      RWO            slow           14s
$ kubectl get pod -o wide
web-0                 1/1     Running     0          31s   192.168.79.86    k8s-worker01   <none>           <none>
web-1                 1/1     Running     0          27s   192.168.69.218   k8s-worker02   <none>           <none>
web-2                 1/1     Running     0          24s   192.168.79.91    k8s-worker01   <none>           <none>

今度はすべてのPodがデプロイできました。
ReadWriteOnceは単一の「ノード」からRead/Writeを許可するので、同一ノード内の複数PodからのRead/Writeは可能なのかと思っていましたが、単一ノードではなく単一「Pod」と思っていた方がよさそうですね。
そもそもStatefulSetで使用する時点でPodとPVが1対1になりますし。

ReadOnlyMany

次にReadOnlyManyの動作を確認します。

環境準備

以下のマニフェストのPV/PVC/Podを作成します。

pv-rox.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 500Mi
  volumeMode: Filesystem
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /share
    server: k8s-client
pvc-rox.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 500Mi
  storageClassName: slow
nginx-dep-rox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dep
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nginx-dep
  template:
    metadata:
      labels:
        app: nginx-dep
    spec:
      containers:
      - image: nginx:latest
        name: nginx-container
        volumeMounts:
        - mountPath: /cache
          name: cache-pv
      volumes:
      - name: cache-pv
        persistentVolumeClaim:
          claimName: myclaim
          readOnly: true
$ kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
pv0003   500Mi      ROX            Recycle          Bound    default/myclaim   slow                    15s
$ kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Bound    pv0003   500Mi      ROX            slow           11s
$ kubectl get pod -o wide
NAME                         READY   STATUS      RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
nginx-dep-6d787c9bd7-5r7w5   1/1     Running     0          84s     192.168.79.96    k8s-worker01   <none>           <none>
nginx-dep-6d787c9bd7-6l4fx   1/1     Running     0          84s     192.168.69.239   k8s-worker02   <none>           <none>
nginx-dep-6d787c9bd7-9b2rk   1/1     Running     0          84s     192.168.79.100   k8s-worker01   <none>           <none>
nginx-dep-6d787c9bd7-l5qd4   1/1     Running     0          84s     192.168.69.238   k8s-worker02   <none>           <none>

動作確認

あらかじめNFS ServerのShareしたディレクトリにテスト用のファイルを置いておきます。
そのファイルを複数のPodから読み込めることを確認します。

$ kubectl exec -it nginx-dep-6d787c9bd7-5r7w5 cat /cache/testfile
NFS Server
$ kubectl exec -it nginx-dep-6d787c9bd7-6l4fx cat /cache/testfile
NFS Server

別々のworkerノードにデプロイされているPodから読み込めましたね。
念のため、書き込みできないことも確認しておきます。

$ kubectl exec -it nginx-dep-6d787c9bd7-5r7w5 touch /cache/aaaa
touch: cannot touch '/cache/aaaa': Read-only file system
command terminated with exit code 1
$ kubectl exec -it nginx-dep-6d787c9bd7-6l4fx touch /cache/aaaa
touch: cannot touch '/cache/aaaa': Read-only file system
command terminated with exit code 1

まとめ

ReadWriteOnceは想定とは違った動きでした。やはりやってみないとわからないものです。
でも、そのおかげでStatefulSetの動作も確認できました。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1