k8sのメモリー制限

## Podへのリソース制限

Pod内の各コンテナは、以下のパラメータを指定することでCPUやメモリなどのリソースを管理することができる。

> https://kubernetes.io/ja/docs/concepts/configuration/manage-resources-containers/#resource-requests-and-limits-of-pod-and-container
> - spec.containers[].resources.limits.cpu
> - spec.containers[].resources.limits.memory
> - spec.containers[].resources.limits.hugepages-<size>
> - spec.containers[].resources.requests.cpu
> - spec.containers[].resources.requests.memory
> - spec.containers[].resources.requests.hugepages-<size>


その中で、resources.limits.memoryについては、メモリーに関する制限を制御することができるが、下記の記載があり、ファイルシステムもスコープとなるとのことなので、動作を確認する。

> https://kubernetes.io/ja/docs/concepts/storage/volumes/#emptydir
> 
> emptyDir.mediumフィールドを"Memory"に設定すると、Kubernetesは代わりにtmpfs(RAMベースのファイルシステム)をマウントします。 tmpfsは非常に高速ですが、ディスクと違ってノードのリブート時にクリアされ、書き込んだファイルはコンテナのメモリー制限にカウントされることに注意してください。

## 動作確認

### 事前準備 - k8s clusterの構築

minikubeを使用した。インストールは下記を参照。

https://qiita.com/n4k4y05h1/items/abff8c110e500ae47437

### 事前準備 - minikubeの起動

minikubeを起動する。

```shell: 実行結果
$ minikube start --cpus=4 --memory='4g'
$ alias kubectl="minikube kubectl --"
```

### テスト1 - メモリ

- リソース制限
  - resources.limit=1024MiBを指定
- テスト内容
  - stressコマンドで2GB分のメモリを確保
- テスト結果
  - OOMが発生した

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f test1.yaml
pod/test created
ubuntu@ubuntu:~$ kubectl get pod -w
NAME   READY   STATUS              RESTARTS   AGE
test   0/1     ContainerCreating   0          4s
test   1/1     Running             0          5s
test   0/1     OOMKilled           0          21s
test   1/1     Running             1 (3s ago)   24s
test   0/1     OOMKilled           1 (17s ago)   38s
^C
ubuntu@ubuntu:~$ 
```

<details><summary>test1.yaml</summary>

```yaml: test1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test
    image: ubuntu:latest
    resources:
      limits:
        memory: "1024Mi"
    command: ["sh"]
    args:
      - "-c"
      - "apt-get update && apt-get install stress -y && stress --vm 1 --vm-bytes 2048M --vm-hang 0"
```
</details>

### テスト2 - emptyDir

- リソース制限
  - resources.limit=1024MiBを指定
- テスト内容
  - emptyDirの領域に2GBのファイルを作成
- テスト結果
  - ファイルの作成に成功

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f test2.yaml
pod/test created
ubuntu@ubuntu:~$ kubectl get pod -w
NAME   READY   STATUS              RESTARTS   AGE
test   0/1     ContainerCreating   0          3s
test   1/1     Running             0          5s
test   0/1     Completed           0          6s
test   1/1     Running             1 (4s ago)   9s
test   0/1     Completed           1 (21s ago)   26s
^C
ubuntu@ubuntu:~$ 
```

<details><summary>test2.yaml</summary>

```yaml: test2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test
    image: ubuntu:latest
    command: ["sh"]
    args:
      - "-c"
      - "dd if=/dev/zero of=/tmpdir/2Gfile bs=1024K count=2048"
    resources:
      limits:
        memory: "1024Mi"
    volumeMounts:
      - name: tmpdir
        mountPath: "/tmpdir"
  volumes:
    - name: tmpdir
      emptyDir: {}
```
</details>


### テスト3 - emptyDir (medium: Memory)

- リソース制限
  - resources.limit=1024MiBを指定
- テスト内容
  - emptyDirのmediumにMemoryを指定
  - emptyDirの領域に2GB分のファイルを作成
- テスト結果
  - OOMが発生

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f test3.yaml
pod/test created
ubuntu@ubuntu:~$ kubectl get pod -w
NAME   READY   STATUS              RESTARTS   AGE
test   0/1     ContainerCreating   0          3s
test   1/1     Running             0          7s
test   0/1     OOMKilled           0          14s
test   0/1     RunContainerError   1 (13s ago)   29s
test   1/1     Running             2 (17s ago)   33s
test   0/1     OOMKilled           2 (22s ago)   38s
test   0/1     CrashLoopBackOff    2 (2s ago)    39s
^C
ubuntu@ubuntu:~$ 
```

<details><summary>test3.yaml</summary>

```yaml: test3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test
    image: ubuntu:latest
    command: ["sh"]
    args:
      - "-c"
      - "sleep 5 && dd if=/dev/zero of=/tmpdir/2Gfile bs=1024K count=2048"
    resources:
      limits:
        memory: "1024Mi"
    volumeMounts:
      - name: tmpdir
        mountPath: "/tmpdir"
  volumes:
    - name: tmpdir
      emptyDir:
        medium: Memory
```
</details>


### テスト4 - hostPath

- リソース制限
  - resources.limit=1024MiBを指定
- テスト内容
  - hostPathの領域に2GBのファイルを作成
- テスト結果
  - ファイル作成に成功

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f test4.yaml
pod/test created
ubuntu@ubuntu:~/$ kubectl get pod -w
NAME   READY   STATUS              RESTARTS   AGE
test   0/1     ContainerCreating   0          4s
test   1/1     Running             0          5s
test   0/1     Completed           0          10s
test   1/1     Running             1 (4s ago)   13s
test   0/1     Completed           1 (14s ago)   23s
^C
ubuntu@ubuntu:~$
```

```shell: 実行結果(別端末)
ubuntu@ubuntu:~$ minikube ssh
docker@minikube:~$ sudo mkdir -p /mnt/tmpdir
docker@minikube:~$ 
docker@minikube:~$ ls /mnt/tmpdir/ -l
total 214456
-rw-r--r-- 1 root root 219602944 Dec  8 12:13 2Gfile
docker@minikube:~$
```

<details><summary>test4.yaml</summary>

```yaml: test4.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test
    image: ubuntu:latest
    command: ["sh"]
    args:
      - "-c"
      - "ls /tmpdir && mount && dd if=/dev/zero of=/tmpdir/2Gfile bs=1024K count=2048"
    resources:
      limits:
        memory: "1024Mi"
    volumeMounts:
      - name: tmpdir
        mountPath: "/tmpdir"
  volumes:
    - name: tmpdir
      hostPath:
        path: /mnt/tmpdir
```
</details>


### テスト5 - hostPath (tmpfs)

- リソース制限
  - resources.limit=1024MiBを指定
- テスト内容
  - hostPath領域をtmpfsに設定
  - hostPathの領域に2GBのファイルを作成
- テスト結果
  - OOMが発生
  - 1GB分のファイルしか作成されなかった

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f test5.yaml
pod/test created
ubuntu@ubuntu:~$ kubectl get pod -w
NAME   READY   STATUS              RESTARTS   AGE
test   0/1     ContainerCreating   0          3s
test   1/1     Running             0          4s
test   0/1     OOMKilled           0          6s
test   0/1     RunContainerError   1 (16s ago)   24s
test   0/1     RunContainerError   2 (16s ago)   42s
^C
ubuntu@ubuntu:~$
```

```shell: 実行結果(別端末)
ubuntu@ubuntu:~$ minikube ssh
docker@minikube:~$ sudo mkdir -p /mnt/tmpdir
docker@minikube:~$ sudo mount -t tmpfs tmpfs /mnt/tmpdir
docker@minikube:~$ mount |grep tmpdir
tmpfs on /mnt/tmpdir type tmpfs (rw,relatime,inode64)
docker@minikube:~$
docker@minikube:~$ ls /mnt/tmpdir/ -l
total 1044352
-rw-r--r-- 1 root root 1069416448 Dec  8 12:21 2Gfile  ## ファイルサイズが約1GB
docker@minikube:~$ 
```

<details><summary>test5.yaml</summary>

```yaml: test5.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test
    image: ubuntu:latest
    command: ["sh"]
    args:
      - "-c"
      - "ls /tmpdir && mount && dd if=/dev/zero of=/tmpdir/2Gfile bs=1024K count=2048"
    resources:
      limits:
        memory: "1024Mi"
    volumeMounts:
      - name: tmpdir
        mountPath: "/tmpdir"
  volumes:
    - name: tmpdir
      hostPath:
        path: /mnt/tmpdir
```
</details>

### テスト結果

今回確認した一覧は以下。

| # | resources.limit | 操作を実施した対象 | 結果 |
|:-:|:-:|:-:|:-:|
| 1 | 1024MiB | Memory           | OOMが発生 |
| 2 | 1024MiB | emptyDir         | ファイル作成成功 |
| 3 | 1024MiB | emptyDir(medium: Memory) | OOMが発生 |
| 4 | 1024MiB | hostPath         | ファイル作成成功 |
| 5 | 1024MiB | hostPath(tmpfs)  | OOMが発生 |

- emptyDirにおいて、medium: Memoryを使用した場合はOOMが発生したため、ドキュメントに記載された通り、emptyDir領域への書き込みもメモリー制限の対象となっていた
- hostPathにおいて、tmpfsをmountした場合についても、同様にメモリー制限の対象となっている模様