AWS EKSクラスタを簡単に構築できるeksctlに、「ノードグループ」機能を追加しようとしている話

この記事は [Kubernetes Advent Calendar 2018](https://qiita.com/advent-calendar/2018/kubernetes) 21日目の記事です。

# TL;DR;

https://github.com/weaveworks/eksctl/pull/332

# eksctlとは

Weaveworksが開発しているOSSで、AWS EKSクラスタおよびその実行環境(VPC, Subnet, Security Group, IAMロール等)とノードグループを作成、スケール、削除することができるgolang製のCLIツールです。

EKSクラスタやその他のリソースは内部的にはCloudFormationスタックによって作成・管理されています。クラスタ（＝マスタとVPCなどのインフラ）に１スタック、そしてノードグループ用に１スタックが作られます。

# ノードグループとは

英語だとNode groupまたはNodegroupと書きます。正式な定義は見つけられなかった、というか、ツールやサービスによって呼び名が異なる（例えばGKEやkube-awsではnode poolと呼んでいる)のですが、「同じnode labels, taints, マシンスペック(machine-type, instance type)を持つノードの集まり」を意味します。

AWSの場合、例えばバッチジョブ用にCPUリソースの潤沢なC4系インスタンスタイプから構成されるノードグループと、Webアプリケーション用にメモリの潤沢なM4系インスタンスタイプから構成するノードグループを分けて、Node LabelsやTaint/TolerationでPodを希望のノードグループに振り分けたりして使います。

# eksctlのノードグループは１個で固定だった

実はeksctlのノードグループは１つで固定でした。これだと、例えばマルチテナントにして、Kubernetes上で稼働っせるサービス毎にマシンスペックを変える、セキュリティ上の都合であるサービス２つを同じノードに同居させないようにする、などの要件が件並み満たせなくなります。

技術的には、CloudFormationなどでノードグループをeksctlが作成したクラスタに追加するようなことは可能なはずですが、手順が煩雑になります。

これまでの経験上も、ノードグループが１個で済むケースはそんなになかったので、必要になる前に追加してみたいと思い、早速コントリビュートしてみました。

それが下記PRです。

https://github.com/weaveworks/eksctl/pull/332

# 複数Nodegroup対応のeksctlを試す

この記事を公開した時点ではまだマージされていないため、以下の手順で自分でeksctlをビルドする必要があります。

```console
$ git clone git@github.com:mumoshu/eksctl.git ~/go/src/github.com/weaveworks/eksctl
$ cd $_
$ git checkout -b nodegroup-resource origin/nodegroup-resource
$ make build
```

ビルドが無事成功したら、プロジェクトルート直下に `eksctl` という実行可能ファイルが生成されているので、それを実行してください。

# クラスタの作成

まず、クラスタ及び最初のノードグループの作成の手順はいままでどおり、`create cluster`コマンドで行うことができます。

```console
$ ./eksctl create cluster --name testcluster
```

`get cluster`でクラスタ一覧、 `get nodegroup --cluster クラスタ名`でノードグループ一覧を見ることができます。

```
$ ./eksctl get cluster
NAME		REGION
test-cluster	us-west-2

$ ./eksctl get nodegroup --cluster testcluster
CLUSTER		NODEGROUP	CREATED			MIN SIZE	MAX SIZE	DESIRED CAPACITY	INSTANCE TYPE	IMAGE ID
testcluster	ng-0		2018-12-21T00:26:40Z	2		2		2			m5.large	ami-094fa4044a2a3cf52
```

# ノードグループの作成

```console
$ ./eksctl create nodegroup --cluster testcluster --node-labels foo=bar ng-1 
```

これで初期ノードグループ `ng-0` に追加で、 `ng-1` という名前のノードグループが作成されます。
作成されたノードグループに所属するnodeは、普段どおり `kubectl get no` で確認することができます。

`get no`がエラーになる場合、kubeconfigの内容が何らかの理由で正しくないことが考えられるため、以下のようにして現在選択されているkubeconfig(KUBECONFIG環境変数の指す先)を更新してください。

```console
$ ./eksctl utils write-kubeconfig --cluster testcluster
```

※今回作成したノードグループに所属するノードには `foo=bar` というラベルが付与されるように、 `--node-labels` フラグを使用しました。ノードグループのデフォルトサイズは 2 なので、以下のように `kubectl get no` を実行すると、全４台のうち今回作成したノードグループに所属する２つのノードのみ、指定したラベル `foo=bar` がついています。

```console
$ kubectl get no --show-labels
NAME                                                STATUS    ROLES     AGE       VERSION   LABELS
ip-192-168-31-112.ap-northeast-1.compute.internal   Ready     <none>    8m        v1.11.5   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=ap-northeast-1,failure-domain.beta.kubernetes.io/zone=ap-northeast-1c,foo=bar,kubernetes.io/hostname=ip-192-168-31-112.ap-northeast-1.compute.internal
ip-192-168-5-50.ap-northeast-1.compute.internal     Ready     <none>    31s       v1.11.5   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=ap-northeast-1,failure-domain.beta.kubernetes.io/zone=ap-northeast-1c,kubernetes.io/hostname=ip-192-168-5-50.ap-northeast-1.compute.internal
ip-192-168-58-165.ap-northeast-1.compute.internal   Ready     <none>    8m        v1.11.5   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=ap-northeast-1,failure-domain.beta.kubernetes.io/zone=ap-northeast-1d,foo=bar,kubernetes.io/hostname=ip-192-168-58-165.ap-northeast-1.compute.internal
ip-192-168-74-189.ap-northeast-1.compute.internal   Ready     <none>    34s       v1.11.5   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=ap-northeast-1,failure-domain.beta.kubernetes.io/zone=ap-northeast-1a,kubernetes.io/hostname=ip-192-168-74-189.ap-northeast-1.compute.internal
```

`get nodegroup` を実行すると、今回追加したものも含めて、すべてのノードグループの情報を得ることができます。

```console
$ ./eksctl get nodegroup --cluster testcluster
CLUSTER		NODEGROUP	CREATED			MIN SIZE	MAX SIZE	DESIRED CAPACITY	INSTANCE TYPE	IMAGE ID
testcluster	ng-0		2018-12-21T00:26:40Z	2		2		2			m5.large	ami-094fa4044a2a3cf52
testcluster	ng-1		2018-12-21T00:38:40Z	2		2		2			m5.large	ami-094fa4044a2a3cf52
```

# ノードグループのスケール

ノードグループのサイズ変更（ノード追加、削除）には `scale` コマンドを利用します。

`--cluster クラスタ名` のようにフラグでクラスタ名を指定し、`--nodes`でノードサイズを指定します。

```
$ ./eksctl scale nodegroup --cluster testcluster --nodes 1 ng-1`
```

# ノードグループの削除

スケールと同様、ノードグループの削除には `scale nodegroup --cluster クラスタ名 ノードグループ名` のようにクラスタ名をフラグで、ノードグループ名を第一引数で指定します。

```
$ ./eksctl delete nodegroup --cluster testcluster ng-1
```

# まとめ

eksctlを使うと、長大なterraform tfファイル、CloudFormationスタックテンプレートを記述しなくても本番運用に耐えうるEKSクラスタを構築することができます。

今回送ったPRで、マルチテナンシーには特に必須と思われるノードグループを複数持てるような機能が追加されます（首尾よくマージされれば）

ノードグループを複数持つという機能は、kops、kube-aws、GKEなど既存のKubernetesクラスタプロビジョニングツールや、AWS以外のマネージド・サービスでは以前よりサポートされている定番機能です。

eksctlに同様の機能を追加することで、EKSでもこれまでのようなマルチテナントに適したノード構成をとることができそうです。

ぜひ試してフィードバックをいただけるとうれしいです!