EKSでノードグループのAutoScalingグループの最小が0の時に自動スケールする方法

# 概要

　掲載の通りにEKSのノードグループのAuto Scalingグループの最小が0の時にPodを追加した際に自動的にノードが立ち上げる方法を残したいと思います。
「[Cluster Autoscalerの手順](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md)」に記載されておらず、やっと見つけた感じです。

# さっそく手順

ズバリ「[公式で手順](https://eksctl.io/usage/autoscaling/#scaling-up-from-0)」が紹介されています！

簡単に要約しますと、nodeGroupsに`taints`を付与する。そして、Podの`tolerations`でデプロイしたいノードグループの`taints`を指定する。
**※taintsに追加した場合は、tagsへの追加もお忘れなく！**

例) 
　説明は下記のコードに直接コメントとして追加しています。
　案外Cluster AutoScaler用のIAMポリシーに `autoscaling:DescribeTags`、`autoscaling:DescribeLaunchConfigurations`、`ec2:DescribeLaunchTemplateVersions`を付与し忘れがちなのでご注意！ 
　詳細は https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/cluster-autoscaler.html#ca-ng-considerations

```yaml:eks-cluster.yml

# eksのノードグループ
nodeGroups:
  - name: t3small-node
    ...
    labels:
      name: t3small-node
    taints:
      version: "1.0.0:NoSchedule"
      env: "prd:NoSchedule"
    tags:
      # k8s.io/cluster-autoscaler/xxxはAuto Scalingグループのタグ名としても追加されます。
      # ノードグループのlabelを指定することでノードグループとAuto Scalingグループが関連付けられます。
      # ※複数のlabelを指定できるかは未検証
      k8s.io/cluster-autoscaler/node-template/label/name: t3small-node
      # taintsが複数ある場合は、その数分設定する必要があります。
      k8s.io/cluster-autoscaler/node-template/taint/version: "1.0.0:NoSchedule"
      k8s.io/cluster-autoscaler/node-template/taint/env: "prd:NoSchedule"
      # 以下のAuto Scaling用のタグを未設定の時の動作は未確認ですが、付与した状態では動作できました。
      k8s.io/cluster-autoscaler/enabled: "true"
      k8s.io/cluster-autoscaler/クラスタ名: owned
```

```yaml:deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  template:
    spec:
      # taintsで指定されたキーと値を指定することで対象ノードにデプロイされる
      tolerations:
        - key: "version"
          operator: "Equal"
          value: "1.0.0"
          effect: "NoSchedule"
        - key: "env"
          operator: "Equal"
          value: "prd"
          effect: "NoSchedule"
```

# 注意点

## 異なるtaintsで同一のDaemonSetを稼働させたい時

例えば、以下のようにインスタンスタイプ(t3.smallとt3.medium)が異なるノードグループがあるときに、どちらにもDaemonSetを稼働させるには、`tolerations`の`operation: Exists`をうまく使用する必要があります。

```yaml:eks-cluster.yml

# eksのノードグループ
nodeGroups:
  - name: t3small-node
    labels:
      name: t3small-node
    taints:
      type: "t3.small:NoSchedule"
      env: "prd:NoSchedule"
    tags:
      k8s.io/cluster-autoscaler/node-template/label/name: t3small-node
      k8s.io/cluster-autoscaler/node-template/taint/type: "t3.small:NoSchedule"
      k8s.io/cluster-autoscaler/node-template/taint/env: "prd:NoSchedule"
  - name: t3medium-node
    labels:
      name: t3medium-node
    taints:
      type: "t3.medium:NoSchedule"
      env: "prd:NoSchedule"
    tags:
      k8s.io/cluster-autoscaler/node-template/label/name: t3medium-node
      k8s.io/cluster-autoscaler/node-template/taint/type: "t3.medium:NoSchedule"
      k8s.io/cluster-autoscaler/node-template/taint/env: "prd:NoSchedule"
```

`key: type`があればデプロイされる。つまりtypeが`t3.small`か`t3.medium`に関係なくデプロイされます。もし、すべてのtaintsを許容するのであれば、`- operator: Exists`のみでOK！

```yaml:daemonset.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: my-daemonset
spec:
  template:
    spec:
      tolerations:
        - key: "type"
          operator: "Exists"
        - key: "env"
          operator: "Equal"
          value: "prd"
          effect: "NoSchedule"
```

## corednsがPendingになる

ノードグループにtaintsを付与したことにより、corednsのデプロイ先がなくなり、Pending状態になります。なのでcorednsのdeploymentの`tolerations`に上記のようにキーを追加する必要があります。
また、Cluster Autoscalerがcorednsに依存していることもあり、Cluster AutoscalerでDNSエラーが発生したならば、一度AutoscalerのPodを削除すると正常に稼働するようになります。

## Cluster AutoScalerが稼働状態であること

クラスターのスケーリングはCluster AutoScalerによって実現されます。よって、最低限Cluster AutoScalerが稼働してなければならない。今記事のようにAuto Scalingグループの最小が0の場合は、Cluster AutoScalerすらデプロイされず摘みます。
なので、Auto Scalingグループの「希望する容量」を1にするか。`eksctl scale nodegroup`でノードをスケールさせることで対応できます。