Kubernetes PVC と Deployment, StatefulSet の関係を検証してみた

# はじめに

Persistent Volume とは、Kubernetes の Pod でストレージを管理・使用するためのものです。
Persistent Volume を、Deployment・StatefulSet で使用したときに、どのようにPodへ紐づけられるかが不明だったため、検証を通じて理解を深めていきます。
Master1台・Node2台のKubernetesクラスタに対して、NFSを使用してPersistent Volume の検証をします。



# NFSサーバの準備

適当にNFSサーバを準備する
以下のURLを参照

https://qiita.com/sugimount/items/1c1ab9b45b0d862a7dd6



# NFS Clientの準備

Node が NFSマウントを実施するため、Nodeに NFS Client の事前準備を行う
念のため、Master と Node全台 で install をしておく

以下のURLを参照

https://qiita.com/sugimount/items/1c1ab9b45b0d862a7dd6





# Persistent VolumeとDeploymentの紐づけ検証

## Persistent Volumeの作成

KubernetesMaster上で、Persistent Volume を定義するYAMLファイルを作成します

```
cat <<'EOF' > /root/kube_yaml/persistent_volume/persistent_volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0001
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
  nfs:
    server: 192.168.120.230
    path: /mnt/nfsserv
EOF
```

特徴的な各パラメータは以下の通りです

| 項目                               | パラメータ概要     | 内容                                                         |
| ---------------------------------- | ------------------ | ------------------------------------------------------------ |
| spec.capacity.storage              | ストレージ容量     | PVの容量を定義                                               |
| spec.volumeMode                    | PVボリュームの種類 | PVボリュームの種類を指定。"Filesystem" or "Block" の2種類を指定可能。何も指定しない場合は、"FileSystem"がDefaultとなる。<br />Kubernetes 1.9 より、 "Block" がサポートされたため、volumeMode を指定出来るようになった |
| spec.accessModes                   | アクセスモード     | PVへアクセスするモードを定義する。選択可能なアクセスモードは、PVのVolumePluginに依存している。<br />ReadWriteOnce : 1つのNodeがPVをmountすることが出来る。読み書き可能。<br />ReadOnlyMany : 複数のNodeがPVをmountすることが出来る。読み取り専用。<br /> ReadWriteMany : 複数のNodeがPVをmountすることが出来る。読み書き可能 |
| spec.storageClassName              | ストレージクラス名 | Kubernetesクラスタ管理者が定義しているストレージのクラスから、1種類を選択します。<br />ストレージの性質をクラスタ管理者が定義するものが、ストレージクラスです。<br />例えば、fast class は高価な早いストレージと定義し、slow class は安価な遅めなストレージと定義する運用が考えられます |
| spec.persistentVolumeReclaimPolicy | 削除時の動作       | PVを削除したときの動作を指定します。<br />Retain : 削除しない。手動で削除を行う<br />Recycle : 削除して再利用する "rm -rf /voluma_path/*" のイメージ<br />Delete : Volumeを削除 |

PV を作成します

```
kubectl create -f /root/kube_yaml/persistent_volume/persistent_volume.yaml
```



確認します

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pv -o wide
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
pv0001    1Gi        RWO            Recycle          Available             slow                     22s
```

現在の段階では、NFS上には何もFileは作成されていません

```
[root@sugi-nfs nfsserv]# pwd
/mnt/nfsserv
[root@sugi-nfs nfsserv]# 
[root@sugi-nfs nfsserv]# ls -la
total 0
drwxr-xr-x  2 root root  6 Jun  1 11:59 .
drwxr-xr-x. 3 root root 21 Jun  1 11:50 ..
```



## Persistent Volume Claims を作成

PVC(Persistent Volume Claims)とは、PVを要求するためのKubernetesリソースです。
PVには、ストレージ提供側の固有の情報(IPアドレスや、NFSエクスポートポイントなど)が含まれています。
Kubernetesクラスタの利用者がPVを作成しようとすると、ストレージ提供側の固有の情報を知る必要があります。

ストレージ固有の情報を抽象化するために、PVCが存在しています。
PVをKubernetesクラスタの管理者が作成し、PVCを利用者が作成することが想定されています。

PVCを作成するために、以下のYAMLファイルを作成します

```
cat <<'EOF' > /root/kube_yaml/persistent_volume/persistent_volume_claims.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-claim
  annotations:
    volume.kubernetes.io/storage-class: "nfs"
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  storageClassName: slow
  resources:
    requests:
      storage: 1Gi
EOF
```

PVCを作成します

```
kubectl create -f /root/kube_yaml/persistent_volume/persistent_volume_claims.yaml
```

確認します

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pvc -o wide
NAME         STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-claim   Bound     pv0001    1Gi        RWO            slow           17s
```

describe で pvc の詳細を確認すると、pv0001 が 使用されている事がわかります

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl describe pvc test-claim 
Name:          test-claim
Namespace:     default
StorageClass:  slow
Status:        Bound
Volume:        pv0001
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed=yes
               pv.kubernetes.io/bound-by-controller=yes
               volume.kubernetes.io/storage-class=nfs
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      1Gi
Access Modes:  RWO
Events:        <none>
```

PVを確認すると、Available だった STATUS が、 Bound と変化しており、PVCに紐づけられています

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pv -o wide
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                STORAGECLASS   REASON    AGE
pv0001    1Gi        RWO            Recycle          Bound     default/test-claim   slow                     2h
```

## Deployment の作成

Deploymentのために、以下のYAMLファイルを作成します

`spec.template.spec.volumes.persistentVolumeClaim.claimName` でDeploymentで使用するPVCを指定しています。
実際のコンテナに割り当てるために`spec.template.spec.containers.volumeMounts`を指定しています。
PVCをコンテナ内の /persistent-volume に mount する設定となっています。

```
cat <<'EOF' > /root/kube_yaml/persistent_volume/persistent_deployment.yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: persistent-deployment
spec:
  selector:
    matchLabels:
      app: persistest_test
  replicas: 1
  template:
    metadata:
      labels:
        app: persistest_test
    spec:
      containers:
      - name: master
        image: nginx
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /persistent-volume
          name: pvc-volume
      volumes:
      - name: pvc-volume
        persistentVolumeClaim:
          claimName: test-claim
      restartPolicy: Always
EOF
```

deployment を作成します

```
kubectl create -f /root/kube_yaml/persistent_volume/persistent_deployment.yaml
```

deploymentが作成され、Pod が作成されます

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pods -o wide
NAME                                    READY     STATUS    RESTARTS   AGE       IP            NODE
persistent-deployment-b9db64785-7fq4z   1/1       Running   0          47s       10.244.1.29   sugi-kubernetes110-node01.localdomain
```

node01 上で df を確認すると、NFSサーバをmount していることがわかります

```
[root@sugi-kubernetes110-node01 ~]# df -h
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/cl-root            14G  3.5G   10G  26% /
devtmpfs                      1.9G     0  1.9G   0% /dev
tmpfs                         1.9G     0  1.9G   0% /dev/shm
tmpfs                         1.9G  129M  1.8G   7% /run
tmpfs                         1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/sda1                    1014M  289M  726M  29% /boot
tmpfs                         1.9G   12K  1.9G   1% /var/lib/kubelet/pods/436d9ed6-4ae3-11e8-bbe9-0050569817ee/volumes/kubernetes.io~secret/kube-proxy-token-c9qtq
tmpfs                         1.9G   12K  1.9G   1% /var/lib/kubelet/pods/436dce14-4ae3-11e8-bbe9-0050569817ee/volumes/kubernetes.io~secret/flannel-token-6pnqp
tmpfs                         380M     0  380M   0% /run/user/0
tmpfs                         1.9G   12K  1.9G   1% /var/lib/kubelet/pods/2f404ff6-6562-11e8-8767-0050569817ee/volumes/kubernetes.io~secret/default-token-q65hj
192.168.120.230:/mnt/nfsserv   14G  1.5G   12G  11% /var/lib/kubelet/pods/2f404ff6-6562-11e8-8767-0050569817ee/volumes/kubernetes.io~nfs/pv0001
```

なお、node01 上で docker 一覧を確認し

```
[root@sugi-kubernetes110-node01 ~]# docker ps
CONTAINER ID        IMAGE                                                                                     COMMAND                  CREATED             STATUS              PORTS               NAMES
b7dea7029d25        docker.io/nginx@sha256:0fb320e2a1b1620b4905facb3447e3d84ad36da0b2c8aa8fe3a5a81d1187b884   "nginx -g 'daemon ..."   4 minutes ago       Up 4 minutes                            k8s_master_persistent-deployment-b9db64785-7fq4z_default_2f404ff6-6562-11e8-8767-0050569817ee_0
13deb2cc4164        k8s.gcr.io/pause-amd64:3.1                                                                "/pause"                 4 minutes ago       Up 4 minutes                            k8s_POD_persistent-deployment-b9db64785-7fq4z_default_2f404ff6-6562-11e8-8767-0050569817ee_0
b9d65d4ddb1c        2b736d06ca4c                                                                              "/opt/bin/flanneld..."   4 weeks ago         Up 4 weeks                              k8s_kube-flannel_kube-flannel-ds-d92qj_kube-system_436dce14-4ae3-11e8-bbe9-0050569817ee_1
5592ed89cbe0        77019aa0531a                                                                              "/usr/local/bin/ku..."   4 weeks ago         Up 4 weeks                              k8s_kube-proxy_kube-proxy-khhwf_kube-system_436d9ed6-4ae3-11e8-bbe9-0050569817ee_1
496d9d63cddd        k8s.gcr.io/pause-amd64:3.1                                                                "/pause"                 4 weeks ago         Up 4 weeks                              k8s_POD_kube-flannel-ds-d92qj_kube-system_436dce14-4ae3-11e8-bbe9-0050569817ee_1
fab2fd0c0a3b        k8s.gcr.io/pause-amd64:3.1                                                                "/pause"                 4 weeks ago         Up 4 weeks                              k8s_POD_kube-proxy-khhwf_kube-system_436d9ed6-4ae3-11e8-bbe9-0050569817ee_1
```



該当のコンテナの詳細情報を表示すると、NFSでmount しているvolume を使用していることが分かります

```
# docker inspect b7dea7029d25

... snip ....

        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/2f404ff6-6562-11e8-8767-0050569817ee/etc-hosts",
                "Destination": "/etc/hosts",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/2f404ff6-6562-11e8-8767-0050569817ee/containers/master/1abcb732",
                "Destination": "/dev/termination-log",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/2f404ff6-6562-11e8-8767-0050569817ee/volumes/kubernetes.io~nfs/pv0001",
                "Destination": "/persistent-volume",    ← ココを見る
                "Mode": "rslave",
                "RW": true,
                "Propagation": "rslave"
            },
```

nginx pod にログインします

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl exec -it persistent-deployment-b9db64785-7fq4z bash
root@persistent-deployment-b9db64785-7fq4z:/# 
```

pod 内でも正常にmountされていることを確認できます

**pod内からNFSサーバのIPアドレスが見えますね。StorageのTypeにもよりますが、Pod利用者にストレージ側のIPアドレスが知られても問題ないようにする観点も必要かもしれません**

```
root@persistent-deployment-b9db64785-7fq4z:/# df -h
Filesystem                    Size  Used Avail Use% Mounted on
overlay                        14G  3.5G   10G  26% /
tmpfs                         1.9G     0  1.9G   0% /dev
tmpfs                         1.9G     0  1.9G   0% /sys/fs/cgroup
192.168.120.230:/mnt/nfsserv   14G  1.5G   12G  11% /persistent-volume
/dev/mapper/cl-root            14G  3.5G   10G  26% /etc/hosts
shm                            64M     0   64M   0% /dev/shm
tmpfs                         1.9G   12K  1.9G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                         1.9G     0  1.9G   0% /proc/scsi
tmpfs                         1.9G     0  1.9G   0% /sys/firmware
```

pod 内でファイルを作成します

```
root@persistent-deployment-b9db64785-7fq4z:/persistent-volume# touch test_from_pod
root@persistent-deployment-b9db64785-7fq4z:/persistent-volume# pwd
/persistent-volume
root@persistent-deployment-b9db64785-7fq4z:/persistent-volume# 
root@persistent-deployment-b9db64785-7fq4z:/persistent-volume# ls -la
total 0
drwxr-xr-x 2 root root 27 Jun  1 06:26 .
drwxr-xr-x 1 root root 53 Jun  1 06:08 ..
-rw-r--r-- 1 root root  0 Jun  1 06:26 test_from_pod
```

NFSサーバ上でも、上記の作成されたファイルが確認できます
NFSサーバのExportPointと、PVは1対1で対応している事がわかります (NFSのDynamicProvisionerを使用すると、ExportPointが自動的に作成されるのかな?)

```
[root@sugi-nfs nfsserv]# ls -la
total 0
drwxr-xr-x  2 root root 27 Jun  1 15:26 .
drwxr-xr-x. 3 root root 21 Jun  1 11:50 ..
-rw-r--r--  1 root root  0 Jun  1 15:26 test_from_pod
[root@sugi-nfs nfsserv]# 
[root@sugi-nfs nfsserv]# pwd
/mnt/nfsserv
```

ここで、DeploymentのReplicaを1から2にするとどうなるのでしょうか。

```
cat <<'EOF' > /root/kube_yaml/persistent_volume/persistent_deployment.yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: persistent-deployment
spec:
  selector:
    matchLabels:
      app: persistest_test
  replicas: 2
  template:
    metadata:
      labels:
        app: persistest_test
    spec:
      containers:
      - name: master
        image: nginx
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /persistent-volume
          name: pvc-volume
      volumes:
      - name: pvc-volume
        persistentVolumeClaim:
          claimName: test-claim
      restartPolicy: Always
EOF
```

apply で更新する

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl apply -f /root/kube_yaml/persistent_volume/persistent_deployment.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.apps "persistent-deployment" configured
```

確認

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get replicaset 
NAME                              DESIRED   CURRENT   READY     AGE
persistent-deployment-b9db64785   2         2         2         44m
```



podも確認

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pods -o wide
NAME                                    READY     STATUS    RESTARTS   AGE       IP            NODE
persistent-deployment-b9db64785-7fq4z   1/1       Running   0          44m       10.244.1.29   sugi-kubernetes110-node01.localdomain
persistent-deployment-b9db64785-rtbk7   1/1       Running   0          2m        10.244.2.28   sugi-kubernetes110-node02.localdomain
```

なんと、PVを **ReadWriteOnce**として作成していましたが、**複数のNodeに接続**がされています。
node01 と node02 のそれぞれのコンテナ上でファイルを作成することが出来ます。
バグなのかなんなのかはよくわかりません。。。

2番目のPodでも正常に書き込める

```
root@persistent-deployment-b9db64785-rtbk7:/persistent-volume# touch test_from_pod02
root@persistent-deployment-b9db64785-rtbk7:/persistent-volume# ls -la
total 0
drwxr-xr-x 2 root root 50 Jun  1 06:59 .
drwxr-xr-x 1 root root 53 Jun  1 06:50 ..
-rw-r--r-- 1 root root  0 Jun  1 06:26 test_from_pod
-rw-r--r-- 1 root root  0 Jun  1 06:59 test_from_pod02
root@persistent-deployment-b9db64785-rtbk7:/persistent-volume# 
root@persistent-deployment-b9db64785-rtbk7:/persistent-volume# pwd
/persistent-volume
```



## Pod をオートヒーリングしたときのPVとの関係を確認

Podの1個目を削除して、ReplicaSetによりオートヒーリングを発生させます。

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl delete pod persistent-deployment-b9db64785-7fq4z
pod "persistent-deployment-b9db64785-7fq4z" deleted
```

新たなPodが作成されます

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pods -o wide
NAME                                    READY     STATUS    RESTARTS   AGE       IP            NODE
persistent-deployment-b9db64785-rtbk7   1/1       Running   0          53m       10.244.2.28   sugi-kubernetes110-node02.localdomain
persistent-deployment-b9db64785-vfcd5   1/1       Running   0          27s       10.244.1.30   sugi-kubernetes110-node01.localdomain
```

オートヒーリングされたPodを確認すると、こちらでも引き続き PV を使用していることがわかります。
削除前に作っていたファイルが確認できます

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl exec -it persistent-deployment-b9db64785-vfcd5 bash
root@persistent-deployment-b9db64785-vfcd5:/# ls -la /persistent-volume/
total 0
drwxr-xr-x 2 root root 50 Jun  1 06:59 .
drwxr-xr-x 1 root root 53 Jun  1 07:43 ..
-rw-r--r-- 1 root root  0 Jun  1 06:26 test_from_pod
-rw-r--r-- 1 root root  0 Jun  1 06:59 test_from_pod02
```





## DeploymentとPVCの関係まとめ

Deploymentで作成されたPodは全て、同一のPVを参照する動作となる。
今回はNFSをPVとして作成したため、ReadWriteAnyが許されており、複数PodからMountが出来ている。
しかし、AWSElasticBlockStoreやAWSElasticBlockStoreでは、ReadWriteManyが出来ないため、
DeploymentにPVを紐づけると、Replicaを2以上にすることは出来ないと予想出来る。

![001.png](https://qiita-image-store.s3.amazonaws.com/0/104247/4f6a75ba-248d-487f-aa66-c42efc717a72.png)



Pod に障害が発生して、オートヒーリングを実施した際にも、PV は引き続き同じものをmountすることが出来ます。

![002.png](https://qiita-image-store.s3.amazonaws.com/0/104247/8bdc116a-90a1-f88a-1ca0-4db796976ec3.png)


# Persistent VolumeとStatefulSetの紐づけ検証



## NFSサーバでPV用の領域をExport

StatefulSet として2個のPod を作成します。その前準備として、PV を2個作成するために、NFS Export を2個設定します

```
[root@sugi-nfs mnt]# mkdir /mnt/pv002
[root@sugi-nfs mnt]# mkdir /mnt/pv003
```



```
[root@sugi-nfs mnt]# vi /etc/exports
/mnt/pv002 *(rw,async,no_root_squash)
/mnt/pv003 *(rw,async,no_root_squash)
```



export point を再読み込み

```
[root@sugi-nfs mnt]# exportfs -ra
[root@sugi-nfs mnt]# exportfs -v
/mnt/pv002      <world>(rw,async,wdelay,hide,no_subtree_check,sec=sys,secure,no_root_squash,no_all_squash)
/mnt/pv003      <world>(rw,async,wdelay,hide,no_subtree_check,sec=sys,secure,no_root_squash,no_all_squash)
```





## Persistent Volume の作成



```
cat <<'EOF' > /root/kube_yaml/persistent_volume/persistent_volume_002.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  # storageClassName: slow
  mountOptions:
    - hard
  nfs:
    server: 192.168.120.230
    path: /mnt/pv002
EOF
```

```
cat <<'EOF' > /root/kube_yaml/persistent_volume/persistent_volume_003.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  # storageClassName: slow
  mountOptions:
    - hard
  nfs:
    server: 192.168.120.230
    path: /mnt/pv003
EOF
```

PVを作成します

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl create -f /root/kube_yaml/persistent_volume/persistent_volume_002.yaml
persistentvolume "pv002" created
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl create -f /root/kube_yaml/persistent_volume/persistent_volume_003.yaml
persistentvolume "pv003" created
```

確認します

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                STORAGECLASS   REASON    AGE
pv0001    1Gi        RWO            Recycle          Bound       default/test-claim   slow                     4h
pv002     1Gi        RWO            Recycle          Available                                                 8s
pv003     1Gi        RWO            Recycle          Available                                                 6s
```



## StatefulSetの作成

StatefulSet の YAML を定義します

```
cat <<'EOF' > /root/kube_yaml/persistent_volume/persistent_volume_statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: persistent-stateset
spec:
  serviceName: nginx-service
  replicas: 2
  selector:
    matchLabels:
      app: persistent-stateful
  template:
    metadata:
      labels:
        app: persistent-stateful
    spec:
      containers:
        - name: nginx-container
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
          - name: pvc-volume
            mountPath: /persistent-volume
  volumeClaimTemplates:
  - metadata:
      name: pvc-volume
    spec:
      accessModes:
      - ReadWriteOnce
      volumeMode: Filesystem
      resources:
        requests:
          storage: 1Gi
EOF
```

StatefulSet を作成します

```
kubectl create -f /root/kube_yaml/persistent_volume/persistent_volume_statefulset.yaml
```



```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get statefulset -o wide
NAME                  DESIRED   CURRENT   AGE       CONTAINERS        IMAGES
persistent-stateset   2         2         29s       nginx-container   nginx
```

pvcが自動的に作成されています

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pvc -o wide
NAME                               STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-volume-persistent-stateset-0   Bound     pv002     1Gi        RWO                           1m
pvc-volume-persistent-stateset-1   Bound     pv003     1Gi        RWO                           51s
test-claim                         Bound     pv0001    1Gi        RWO            slow           2h
```

PVの一覧でも、PVCに bound されていることを確認できます

Deployment とは違い、Pod ごとに PV が接続されています

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pv -o wide
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                                      STORAGECLASS   REASON    AGE
pv0001    1Gi        RWO            Recycle          Bound     default/test-claim                         slow                     4h
pv002     1Gi        RWO            Recycle          Bound     default/pvc-volume-persistent-stateset-0                            18m
pv003     1Gi        RWO            Recycle          Bound     default/pvc-volume-persistent-stateset-1                            18m
```

StatefulSet の Pod も作成されています

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pods -o wide
NAME                    READY     STATUS    RESTARTS   AGE       IP            NODE
persistent-stateset-0   1/1       Running   0          2m        10.244.1.32   sugi-kubernetes110-node01.localdomain
persistent-stateset-1   1/1       Running   0          2m        10.244.2.31   sugi-kubernetes110-node02.localdomain
```

Pod に割り当てられている PVC を確認すると、PVC が紐づけされていることがわかります

```
# kubectl describe pod persistent-stateset-0

snip 

Volumes:
  pvc-volume:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  pvc-volume-persistent-stateset-0
    ReadOnly:   false
  default-token-q65hj:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-q65hj
    Optional:    false
```

```
# kubectl describe pod persistent-stateset-1

snip

Volumes:
  pvc-volume:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  pvc-volume-persistent-stateset-1
    ReadOnly:   false
  default-token-q65hj:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-q65hj
    Optional:    false
```

それぞれのPodにログインし、test file を作成します

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl exec -it persistent-stateset-0 bash
root@persistent-stateset-0:/# df -h
Filesystem                  Size  Used Avail Use% Mounted on
overlay                      14G  3.5G   10G  26% /
tmpfs                       1.9G     0  1.9G   0% /dev
tmpfs                       1.9G     0  1.9G   0% /sys/fs/cgroup
192.168.120.230:/mnt/pv002   14G  1.5G   12G  11% /persistent-volume
/dev/mapper/cl-root          14G  3.5G   10G  26% /etc/hosts
shm                          64M     0   64M   0% /dev/shm
tmpfs                       1.9G   12K  1.9G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                       1.9G     0  1.9G   0% /proc/scsi
tmpfs                       1.9G     0  1.9G   0% /sys/firmware
root@persistent-stateset-0:/# touch /persistent-volume/testfile-frompod-0 
root@persistent-stateset-0:/# ls -la /persistent-volume/
total 0
drwxr-xr-x 2 root root 32 Jun  1 08:57 .
drwxr-xr-x 1 root root 65 Jun  1 08:48 ..
-rw-r--r-- 1 root root  0 Jun  1 08:57 testfile-frompod-0
```

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl exec -it persistent-stateset-1 bash
root@persistent-stateset-1:/# df -h
Filesystem                  Size  Used Avail Use% Mounted on
overlay                      14G  4.1G  9.4G  31% /
tmpfs                       1.9G     0  1.9G   0% /dev
tmpfs                       1.9G     0  1.9G   0% /sys/fs/cgroup
192.168.120.230:/mnt/pv003   14G  1.5G   12G  11% /persistent-volume
/dev/mapper/cl-root          14G  4.1G  9.4G  31% /etc/hosts
shm                          64M     0   64M   0% /dev/shm
tmpfs                       1.9G   12K  1.9G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                       1.9G     0  1.9G   0% /proc/scsi
tmpfs                       1.9G     0  1.9G   0% /sys/firmware
root@persistent-stateset-1:/# touch /persistent-volume/testfile-frompod-1
root@persistent-stateset-1:/# ls -la /persistent-volume/
total 0
drwxr-xr-x 2 root root 32 Jun  1 08:57 .
drwxr-xr-x 1 root root 53 Jun  1 08:48 ..
-rw-r--r-- 1 root root  0 Jun  1 08:57 testfile-frompod-1
```

NFSサーバを確認すると、それぞれの Export Point で、test file が作成されていることを確認できます

```
[root@sugi-nfs mnt]# ls -la /mnt/pv002/
total 0
drwxr-xr-x  2 root root 32 Jun  1 17:57 .
drwxr-xr-x. 5 root root 47 Jun  1 17:10 ..
-rw-r--r--  1 root root  0 Jun  1 17:57 testfile-frompod-0
[root@sugi-nfs mnt]# 
[root@sugi-nfs mnt]# ls -la /mnt/pv003/
total 0
drwxr-xr-x  2 root root 32 Jun  1 17:57 .
drwxr-xr-x. 5 root root 47 Jun  1 17:10 ..
-rw-r--r--  1 root root  0 Jun  1 17:57 testfile-frompod-1
```



## Pod をオートヒーリングしたときのPVとの関係を確認

Podの1個目を削除して、StatefulSet によりオートヒーリングを発生させます。

削除した直後に Pod がオートヒーリングされることを確認できます

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl delete pod persistent-stateset-0
pod "persistent-stateset-0" deleted
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# 
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pod
NAME                    READY     STATUS        RESTARTS   AGE
persistent-stateset-0   0/1       Terminating   0          14m
persistent-stateset-1   1/1       Running       0          14m
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# 
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pod
NAME                    READY     STATUS        RESTARTS   AGE
persistent-stateset-0   0/1       Terminating   0          14m
persistent-stateset-1   1/1       Running       0          14m
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# 
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pod
NAME                    READY     STATUS        RESTARTS   AGE
persistent-stateset-0   0/1       Terminating   0          14m
persistent-stateset-1   1/1       Running       0          14m
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# 
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pod
NAME                    READY     STATUS    RESTARTS   AGE
persistent-stateset-0   0/1       Pending   0          0s
persistent-stateset-1   1/1       Running   0          14m
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# 
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pod
NAME                    READY     STATUS              RESTARTS   AGE
persistent-stateset-0   0/1       ContainerCreating   0          2s
persistent-stateset-1   1/1       Running             0          14m
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# 
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl get pod
NAME                    READY     STATUS              RESTARTS   AGE
persistent-stateset-0   0/1       ContainerCreating   0          3s
persistent-stateset-1   1/1       Running             0          14m
```

オートヒーリングされたPodを確認すると、こちらでも引き続き PV を使用していることがわかります。
削除前に作っていたファイルが確認できます

```
[root@sugi-kubernetes110-master01 ~(default kubernetes-admin)]# kubectl exec -it persistent-stateset-0 bash
root@persistent-stateset-0:/# ls -la /persistent-volume/
total 0
drwxr-xr-x 2 root root 32 Jun  1 08:57 .
drwxr-xr-x 1 root root 53 Jun  1 09:02 ..
-rw-r--r-- 1 root root  0 Jun  1 08:57 testfile-frompod-0
```



## StatefulSet と PVC の関係まとめ

StatefulSet で作成された Pod は、それぞれ単一の PV をマウントしています
Deployment では、全てのPodで1個のPV をマウントしている違いがあります


![003.png](https://qiita-image-store.s3.amazonaws.com/0/104247/70680056-b429-c832-fd6c-e617a2dfcf88.png)



Pod に障害が発生し、オートヒーリングを実施した際にも、同一のPVを引き続き mount するため、データの永続性を担保することが出来ます。

![004.png](https://qiita-image-store.s3.amazonaws.com/0/104247/db9384f8-4714-3dc4-c45e-2e27d47192c4.png)


# 参考URL

https://kubernetes.io/docs/concepts/storage/persistent-volumes/