[Kubernetes]Volumeの動作を確認する

#はじめに
今回はVolumeのリソースを確認したいと思います。
Volumeには色々な種類がありますが、検証環境がPC1台ですので、できるものの動作を確認します。

>[Types of Volumes](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes)

#emptyDir
emptyDirはworkerノードの領域をコンテナからマウントして使用します。Podが削除されるとその領域は削除されます。
ユースケースとして、以下がマニュアルに記載されています。わかるようなわからないようなという感じですが。

>* scratch space, such as for a disk-based merge sort
>* checkpointing a long computation for recovery from crashes
>* holding files that a content-manager Container fetches while a webserver Container serves the data

以下のマニフェストを作成しました。「mountPath」と「name」にマウントポイントと名前を指定します。

```emptyDir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-emptydir
spec:
  containers:
  - image: nginx:latest
    name: test-emptydir
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
```

このマニフェストをapplyします。

```
$ kubectl apply -f emptyDir.yaml
pod/test-emptydir created
$ kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
test-emptydir   1/1     Running   0          3m46s   192.168.79.101   k8s-worker01   <none>           <none>
```

ログインして確認します。

```
$ kubectl exec -it test-emptydir /bin/bash
root@test-emptydir:/# df -k
Filesystem              1K-blocks    Used Available Use% Mounted on
overlay                  17811456 7913692   9897764  45% /
tmpfs                       65536       0     65536   0% /dev
tmpfs                     1457088       0   1457088   0% /sys/fs/cgroup
/dev/mapper/centos-root  17811456 7913692   9897764  45% /cache
shm                         65536       0     65536   0% /dev/shm
tmpfs                     1457088      12   1457076   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                     1457088       0   1457088   0% /proc/acpi
tmpfs                     1457088       0   1457088   0% /proc/scsi
tmpfs                     1457088       0   1457088   0% /sys/firmware
root@test-emptydir:/# touch /cache/testfile
root@test-emptydir:/# ls /cache/testfile
/cache/testfile
```
/cacheに/dev/mapper/centos-rootがマウントされていますね。
ファイルも作成できます。

workerノードも確認してみます。
worker01にデプロイされていますので、worker01を確認します。

```
[k8s-worker01 ~]$ df -k
ファイルシス            1K-ブロック    使用  使用可 使用% マウント位置
devtmpfs                    1445272       0 1445272    0% /dev
tmpfs                       1457088       0 1457088    0% /dev/shm
tmpfs                       1457088    9640 1447448    1% /run
tmpfs                       1457088       0 1457088    0% /sys/fs/cgroup
/dev/mapper/centos-root    17811456 7913820 9897636   45% /
/dev/sda1                   1038336  204504  833832   20% /boot
tmpfs                        291420       0  291420    0% /run/user/1000
```
rootファイルシステムがそのままマウントされていますが、workerノードのrootファイルシステムは参照できないようです。

今度は1GBのファイルを作ってみます。

```
root@test-emptydir:/# dd if=/dev/zero of=/cache/tmpfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.38459 s, 450 MB/s
root@test-emptydir:/# ls -l /cache/
total 1048576
-rw-r--r--. 1 root root          0 Apr 25 12:40 testfile
-rw-r--r--. 1 root root 1073741824 Apr 26 07:02 tmpfile
root@test-emptydir:/# df -k /cache/
Filesystem              1K-blocks    Used Available Use% Mounted on
/dev/mapper/centos-root  17811456 8963176   8848280  51% /cache
```

worker01の容量も確認します。

```
[k8s-worker01 ~]$ df -k /
ファイルシス            1K-ブロック    使用  使用可 使用% マウント位置
/dev/mapper/centos-root    17811456 8963280 8848176   51% /
```
同じ容量が消費されていることがわかりますね。

Podを削除すると、領域も開放されます。

```
$ kubectl delete -f emptyDir.yaml
pod "test-emptydir" deleted
```
```
[k8s-worker01 ~]$ df -k /
ファイルシス            1K-ブロック    使用  使用可 使用% マウント位置
/dev/mapper/centos-root    17811456 7914956 9896500   45% /
```

---
複数のPodで同じ領域をマウントすることになりますので、ファイルの共有ができるのかも？と思い確認してみます。
ReplicaSetを複数作って、同じworkerノードにデプロイされているPodで共有できるのかを確認します。

```
$ kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
test-emptydir-dep-75f6f5996-2dzzn   1/1     Running   0          56s   192.168.79.103   k8s-worker01   <none>           <none>
test-emptydir-dep-75f6f5996-bxpkn   1/1     Running   0          56s   192.168.79.104   k8s-worker01   <none>           <none>
test-emptydir-dep-75f6f5996-pgrlq   1/1     Running   0          56s   192.168.69.205   k8s-worker02   <none>           <none>
test-emptydir-dep-75f6f5996-wwrp8   1/1     Running   0          56s   192.168.69.207   k8s-worker02   <none>           <none>
```
1つのPodでファイルを作って、そのファイルが別のPodから参照できるのかを確認します。

```
$ kubectl exec -it test-emptydir-dep-75f6f5996-2dzzn touch /cache/testfile
$ kubectl exec -it test-emptydir-dep-75f6f5996-2dzzn ls /cache
testfile
$ kubectl exec -it test-emptydir-dep-75f6f5996-bxpkn ls /cache
```

同じworkerノードにデプロイされているPodでも参照はできませんでした。
同じ領域をマウントしていてもファイルの共有はできないようです。

#hostPath
hostPathはworkerノードのある領域をコンテナからマウントします。emptyDirとの違いは、workerノードの領域を参照できるかどうかです。
ユースケースとしては、以下があげられてます。

>* running a Container that needs access to Docker internals; use a hostPath of /var/lib/docker
>* running cAdvisor in a Container; use a hostPath of /sys
<* allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as

以下のマニフェストを作成しました。
workerノードの「/sys」を「/test」でマウントします。
また、「type」は「Directory」を指定していますが、ほかにもいくつかあります。

>[hostPath](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath)

```hostPath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-hostpath
spec:
  containers:
  - image: nginx:latest
    name: test-hostpath
    volumeMounts:
    - mountPath: /test
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      path: /sys
      type: Directory
```
このマニフェストをapplyします。

```
$ kubectl apply -f hostPath.yaml
pod/test-hostpath created
```
ログインして確認します。

```
$ kubectl exec -it test-hostpath /bin/bash
root@test-hostpath:/# ls -l /test/
total 0
drwxr-xr-x.   2 root root 0 Apr 26 08:27 block
drwxr-xr-x.  34 root root 0 Apr 26 08:27 bus
drwxr-xr-x.  52 root root 0 Apr 26 08:27 class
drwxr-xr-x.   4 root root 0 Apr 26 08:27 dev
drwxr-xr-x.  15 root root 0 Apr 26 08:27 devices
drwxr-xr-x.   6 root root 0 Apr 26 08:27 firmware
drwxr-xr-x.   7 root root 0 Apr 26 08:27 fs
drwxr-xr-x.   2 root root 0 Apr 26 08:27 hypervisor
drwxr-xr-x.  10 root root 0 Apr 26 08:27 kernel
drwxr-xr-x. 181 root root 0 Apr 26 08:27 module
drwxr-xr-x.   2 root root 0 Apr 26 08:27 power
```
workerノードの/sysも確認します。同じですね。

```
[k8s-worker01 ~]$ ls -l /sys/
合計 0
drwxr-xr-x.   2 root root 0  4月 26 15:42 block
drwxr-xr-x.  34 root root 0  4月 26 15:42 bus
drwxr-xr-x.  52 root root 0  4月 26 15:42 class
drwxr-xr-x.   4 root root 0  4月 26 15:42 dev
drwxr-xr-x.  15 root root 0  4月 26 15:42 devices
drwxr-xr-x.   6 root root 0  4月 26 15:42 firmware
drwxr-xr-x.   7 root root 0  4月 26 15:42 fs
drwxr-xr-x.   2 root root 0  4月 26 15:42 hypervisor
drwxr-xr-x.  10 root root 0  4月 26 15:42 kernel
drwxr-xr-x. 181 root root 0  4月 26 15:42 module
drwxr-xr-x.   2 root root 0  4月 26 15:43 power
```
コンテナから書き込みができるか確認してみます。

```
root@test-hostpath:/# touch /test/testfile
touch: cannot touch '/test/testfile': Permission denied
```

パーミッションがありませんね。

#downwardAPI
downwardAPIはPodなどの情報をファイルとしてコンテナ内の指定したディレクトリに配置します。
配置できる情報はこちらに記載されています。

>[Capabilities of the Downward API](https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#capabilities-of-the-downward-api)

以下のマニフェストでPod名、namespace、requestCPU数を配置してみます。

```downwardAPI.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-downwardapi
spec:
  containers:
    - name: test-downwordapi
      image: nginx:latest
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "podname"
            fieldRef:
              fieldPath: metadata.name
          - path: "namespace"
            fieldRef:
              fieldPath: metadata.namespace
          - path: "cpu_request"
            resourceFieldRef:
              containerName: test-downwordapi
              resource: requests.cpu
```

```
$ kubectl apply -f downwardAPI.yaml
pod/test-downwardapi created
$ kubectl exec -it test-downwardapi ls /etc/podinfo
cpu_request  namespace  podname
$ kubectl exec -it test-downwardapi cat /etc/podinfo/cpu_request
0
$ kubectl exec -it test-downwardapi cat /etc/podinfo/namespace
default
$ kubectl exec -it test-downwardapi cat /etc/podinfo/podname
test-downwardapi
```

それぞれの値がファイルとして配置され、その中に記載されていることがわかります。


#projected
projectedは以下の4つのボリュームリソースを同じディレクトリにマウントするリソースです。

* secret
* downwardAPI
* configMap
* serviceAccountToken

以下のマニフェストをapplyして確認します。
SecretとConfigMapは以前作成したものを流用します。

```projected.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-projected
spec:
  containers:
  - name: container-test
    image: nginx:latest
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: sample-auth
          items:
            - key: username
              path: secret/data
      - configMap:
          name: sample-configmap2
          items:
            - key: maxmemory
              path: configmap/data
      - downwardAPI:
          items:
            - path: "podname"
              fieldRef:
                fieldPath: metadata.name
```

```
$ kubectl apply -f projected.yaml
pod/test-projected created
$  kubectl exec -it test-projected /bin/bash
root@test-projected:/# cd /projected-volume/
root@test-projected:/projected-volume# ls
configmap  podname  secret
root@test-projected:/projected-volume# cat configmap/data
2mb
root@test-projected:/projected-volume# cat podname
test-projected
root@test-projected:/projected-volume# cat secret/data
user01
```
3つの値が同じマウントポイントにマウントされていることがわかりますね。

#まとめ
今回はVolumeリソースの動作を確認しました。
Volumeはworkerノードのファイルシステムやあらかじめ作成したリソース（ConfigMapなど）をコンテナ上で利用可能とするものです。Volumeというと、私は物理的な領域やディスクを連想しますが、Kubernetesではファイルシステムから上の論理的な領域に近いイメージですね。
言葉から受ける印象から先入観を持たないようにしないといけないです。