[Kubernetes]LimitRangeの動作を確認する 1

#はじめに
今回はリソース制御の一種のLimitRangeの動作を確認します。
LimitRangeはNamespaceごとに設定をして、そのNamespaceに属するPodのデフォルトの上限下限を設定します。
LimitRangeを設定できるリソースは、Container/Pod/PVCで、それぞれに設定できる項目は以下のようになります。

|設定項目|概要|Container|Pod|PVC
|:---|:---|:--:|:--:|:--:
|max|最大リソース|レ|レ|レ
|min|最小リソース|レ|レ|レ
|default|defaultのLimits|レ||
|defaultRequest|defaultのRequests|レ
|maxLimitRequestRatio|Limits / Requestsの割合|レ|レ|

クラウドサービスによっては、デフォルトでLimitRangeが設定されているものもあります。

#Container
動作を確認していきます。まずはContainerの動作を確認します。

##max/min
CPUとメモリを設定できるのですが、CPUだけ設定します。

以下のマニフェストのLimitRangeを作成します。

```limitrange-max_min-con.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: limit-range-max-min-con
  namespace: stg
spec:
  limits:
  - max:
      cpu: "500m"
    min:
      cpu: "200m"
    type: Container
```

namespaceを作成してからapplyします。

```
$ kubectl create namespace stg
namespace/stg created
$ kubectl apply -f limitrange-max_min-con.yaml
limitrange/limit-range-max-min-con created
```
確認します。

```
$ kubectl -n stg get limitranges
NAME                      CREATED AT
limit-range-max-min-con   2020-05-17T12:59:35Z
$ kubectl -n stg describe limitranges
Name:       limit-range-max-min-con
Namespace:  stg
Type        Resource  Min   Max   Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---   ---   ---------------  -------------  -----------------------
Container   cpu       200m  500m  500m             500m           -
```

設定したのは、max/minですが、Default Request/Default Limitも設定されていますね。どちらもmaxの値になっています。

マニュアルには以下のように記載されていて、これは正常な動作のようです。


>The output shows the minimum and maximum CPU constraints as expected. But notice that even though you didn’t specify default values in the configuration file for the LimitRange, they were created automatically.
>[Configure Minimum and Maximum CPU Constraints for a Namespace](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/cpu-constraint-namespace/#create-a-limitrange-and-a-pod)

以下のマニフェストのPod（Deployment）を作成します。
ここでは特にリソース制御の設定はしていません。

```nginx1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx1
  namespace: stg
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
        - name: nginx
          image: nginx:latest
```
applyして確認します。

```
$ kubectl apply -f nginx1.yaml
deployment.apps/nginx1 created
$ kubectl get pod -o wide
No resources found in default namespace.
$ kubectl -n stg get pod -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx1-5589d85476-5mtq7   1/1     Running   0          28s   192.168.69.194   k8s-worker02   <none>           <none>
nginx1-5589d85476-rvkdr   1/1     Running   0          28s   192.168.79.65    k8s-worker01   <none>           <none>
$ kubectl -n stg describe pod nginx1-5589d85476-rvkdr
Name:         nginx1-5589d85476-rvkdr
Namespace:    stg
・・・
Containers:
  nginx:
・・・
    Limits:
      cpu:  500m
    Requests:
      cpu:        500m
・・・
```

LimitsとRequestsの値だけ設定されていますね。max/minの値は設定値としては設定されていないようです。

##default/defaultRequest
max/minを設定したら、Default Request/Default Limitも設定されていました。
max/minとdefault/defaultRequestの違いがわからなくなってしまったのですが、ひとまずdefault/defaultRequestの動作を確認してから考えたいと思います。

以下のマニフェストのLimitRangeを作成します。namespaceは分けておきました。

```limitrange-default-con.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: limitrange-default-con
  namespace: dev
spec:
  limits:
  - default:
      cpu: 500m
    defaultRequest:
      cpu: 300m
    type: Container
```

namespaceを作成してからapplyします。

```
$ kubectl create namespace dev
namespace/dev created
$ kubectl apply -f limitrange-default-con.yaml
limitrange/limitrange-default-con created
```

確認します。

```
$ kubectl describe limitranges -A
Name:       limitrange-default-con
Namespace:  dev
Type        Resource  Min  Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---  ---  ---------------  -------------  -----------------------
Container   cpu       -    -    300m             500m           -


Name:       limit-range-max-min-con
Namespace:  stg
Type        Resource  Min   Max   Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---   ---   ---------------  -------------  -----------------------
Container   cpu       200m  500m  500m             500m           -
```

Default Request/Default Limitのみ設定されていますね。
念のため、Podを作成して確認してみます。マニフェストは、nginx1.yamlのnamespaceとnameを変えただけです。

```
 kubectl apply -f nginx2.yaml
deployment.apps/nginx2 created
$ kubectl -n dev describe pod nginx2-5589d85476-fjdz7
Name:         nginx2-5589d85476-fjdz7
・・・
Containers:
  nginx:
・・・
    Limits:
      cpu:  500m
    Requests:
      cpu:        300m
・・・
```
想定通り、作成できますね。

###max/minとdefault/defaultRequestの違いを確認する。
ここまでの検証では、max/minとdefault/defaultRequestの違いがよくわかりませんでした。
もう少し詳細に確認します。

設定値を一度整理しておきます。

|Pod|namespace|max|min|default|defaultRequest
|:---|:---|:---|:---|:---|:---
|nginx1|stg|500m|200m|500m*|500m*
|nginx2|dev|-|-|500m|300m
\* 自動で設定された

---

minの値を下回るrequestsの値をPodに指定してデプロイしてみます。

```nginx3.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx3
  namespace: stg
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          resources:
            requests:
              cpu: 100m
```

```
$ kubectl apply -f nginx3.yaml
deployment.apps/nginx3 created
$ kubectl -n stg get deployments.apps
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
nginx1   2/2     2            2           24h
nginx3   0/2     0            0           26s
```

Deploymentはデプロイされているのですが、Podが作成されていません。
詳細を確認します。

```
$ kubectl -n stg describe deployments.apps nginx3
Name:                   nginx3
・・・
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  55s   deployment-controller  Scaled up replica set nginx3-785d4ccb57 to 2
```

Deploymentは問題なさそうです。
ReplicaSetを確認します。

```
$ kubectl -n stg get replicasets.apps
NAME                DESIRED   CURRENT   READY   AGE
nginx1-5589d85476   2         2         2       24h
nginx3-785d4ccb57   2         0         0       109s
$ kubectl -n stg describe replicasets.apps nginx3-785d4ccb57
Name:           nginx3-785d4ccb57
Namespace:      stg
・・・
Events:
  Type     Reason        Age                  From                   Message
  ----     ------        ----                 ----                   -------
  Warning  FailedCreate  2m18s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-469gj" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m18s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-9cgnn" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m18s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-rlwsm" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m18s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-b2ntn" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m17s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-xk8wp" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m17s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-8h7p5" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m17s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-mkwn4" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m17s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-x7fx6" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  2m16s                replicaset-controller  Error creating: pods "nginx3-785d4ccb57-v9jt8" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
  Warning  FailedCreate  56s (x6 over 2m15s)  replicaset-controller  (combined from similar events): Error creating: pods "nginx3-785d4ccb57-xqwcc" is forbidden: minimum cpu usage per Container is 200m, but request is 100m
```

requestsとしてminで設定した200mを下回る100mを指定したため、Podの起動に失敗していますね。
ちなみに、requestsを200m以上にするとPodまで起動します。

---

念のためminが設定されていないnamaspace:devで、defaultRequestを下回る値に設定してデプロイできるか確認します。

```nginx4.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx4
  namespace: dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          resources:
            requests:
              cpu: 200m
```

```
$ kubectl apply -f nginx4.yaml
deployment.apps/nginx4 created
$ kubectl -n dev get pod
NAME                      READY   STATUS    RESTARTS   AGE
nginx2-5589d85476-fjdz7   1/1     Running   0          48m
nginx2-5589d85476-m6n9r   1/1     Running   0          48m
nginx4-5544cfc499-466jb   1/1     Running   0          18s
nginx4-5544cfc499-x2cxd   1/1     Running   0          18s
$ kubectl -n dev describe pod nginx4-5544cfc499-466jb
Name:         nginx4-5544cfc499-466jb
Namespace:    dev
・・・
Containers:
  nginx:
・・・
    Limits:
      cpu:  500m
    Requests:
      cpu:        200m
・・・
```

defaultRequestは300mで設定していますが、Requestsでそれ以下に設定することも可能です。

---

まとめると、max/minとdefault/defaultRequestの動作は以下のようになるようです。

* Pod作成時にLimits/Requestsを指定していなかったら、LimitRangeのdefault/defaultRequestの値がコンテナに設定される。
* Pod作成時にLimits/Requestsを指定したら、その値が優先される。
* LimitRangeのmax/minを設定していたら、Pod作成時にmax以上のLimits/min以下のRequestsを指定するとPodの起動に失敗する。

##maxLimitRequestRatio
最後にmaxLimitRequestRatioの動作を確認します。

以下のマニフェストのLimitRangeを作成します。

```limitrange-ratio-con.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: limitlange-ratio-con
  namespace: prd
spec:
  limits:
  - maxLimitRequestRatio:
      cpu: 2
    type: Container
```

namespaceを作成してから、applyします。

```
$ kubectl create namespace prd
namespace/prd created
$ kubectl apply -f limitrange-ratio-con.yaml
limitrange/limitlange-ratio-con created
```

確認します。

```
$ kubectl describe limitranges -n prd
Name:       limitlange-ratio-con
Namespace:  prd
Type        Resource  Min  Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---  ---  ---------------  -------------  -----------------------
Container   cpu       -    -    -                -              2
```
Max Limit/Request Ratioだけが設定されていますね。

Podをデプロイして確認します。まずはlimits/requestsどちらも設定しないPodをデプロイしてみます。

```nginx5.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx5
  namespace: prd
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
        - name: nginx
          image: nginx:latest
```

```
$ kubectl apply -f nginx5.yaml
deployment.apps/nginx5 created
$ kubectl -n prd get deployments.apps
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
nginx5   0/2     0            0           31s
$ kubectl -n prd describe replicasets.apps nginx5-5589d85476
Name:           nginx5-5589d85476
Namespace:      prd
・・・
Events:
  Type     Reason        Age               From                   Message
  ----     ------        ----              ----                   -------
  Warning  FailedCreate  47s               replicaset-controller  Error creating: pods "nginx5-5589d85476-cx82p" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  47s               replicaset-controller  Error creating: pods "nginx5-5589d85476-66bj2" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  47s               replicaset-controller  Error creating: pods "nginx5-5589d85476-qhwcd" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  47s               replicaset-controller  Error creating: pods "nginx5-5589d85476-8znms" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  47s               replicaset-controller  Error creating: pods "nginx5-5589d85476-xnqcr" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  47s               replicaset-controller  Error creating: pods "nginx5-5589d85476-d9v2z" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  46s               replicaset-controller  Error creating: pods "nginx5-5589d85476-t5x45" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  46s               replicaset-controller  Error creating: pods "nginx5-5589d85476-4xbnv" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  46s               replicaset-controller  Error creating: pods "nginx5-5589d85476-zlk62" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
  Warning  FailedCreate  6s (x5 over 44s)  replicaset-controller  (combined from similar events): Error creating: pods "nginx5-5589d85476-gh4x5" is forbidden: cpu max limit to request ratio per Container is 2, but no request is specified or request is 0
```
Podのデプロイに失敗しています。limits/requestsを設定しないといけないようです。

色々なパターンで試しましたが、以下のような動作になりました。

|limits|requests|Podデプロイ可否|備考
|:---|:---|:---|:---
|設定しない|設定しない|失敗
|設定しない|設定する|失敗
|設定する|設定しない|成功|「requestsの値＝limitsの値」になる
|設定する|設定する|成功|limits/requestsの割合がmaxLimitRequestRatio以内である必要がある。maxLimitRequestRatioを超えると、Podのデプロイに失敗する。

#まとめ
マニュアルや本を読んだだけではわからないことも、実際にやってみることで理解が深まりますね。
リソース制限をかけないと、コンテナはあるだけリソースを使いますので、環境やシステムごとにデフォルトの制限を設定するLimitRangeは大切ですね。

今回はコンテナしか検証できませんでしたので、PodとPVCは次回検証したいと思います。