EKSでkubectl topやHorizontal Pod Autoscaler (HPA) が使えなかった理由 ※今は使えます

# 2018/12/31 追記

[Amazon EKS Platform Version 2 のご紹介](https://aws.amazon.com/jp/about-aws/whats-new/2018/08/introducing-amazon-eks-platform-version-2/) の通り、2018年8月の時点でEKSはHPAに対応しました。
[こちら](https://qiita.com/os1ma/items/7b48decb71d0c1f9ea3e) の記事で動作確認まで実施しました。

# 概要

EKSでkubectl topコマンドを実行すると、以下のようなエラーが発生しました。

```
$ kubectl top node
Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)
```
原因を調べていった結果、EKSではkubectl topやHorizontal Pod Autoscaler (HPA) が使えないようだったので、その理由を調べました。

# kubectl topのエラーへの対応

上記のエラーメッセージは[Heapster](https://github.com/kubernetes/heapster)を入れれば解決するように見えますが、Heapsterはすでにdeprecatedでした。
そこで、[Metrics Server](https://github.com/kubernetes-incubator/metrics-server)をデプロイしました。

```
$ git clone https://github.com/kubernetes-incubator/metrics-server.git
$ cd metrics-server
$ kubectl create -f deploy/1.8+/
clusterrolebinding.rbac.authorization.k8s.io "metrics-server:system:auth-delegator" created
rolebinding.rbac.authorization.k8s.io "metrics-server-auth-reader" created
apiservice.apiregistration.k8s.io "v1beta1.metrics.k8s.io" created
serviceaccount "metrics-server" created
deployment.extensions "metrics-server" created
service "metrics-server" created
clusterrole.rbac.authorization.k8s.io "system:metrics-server" created
clusterrolebinding.rbac.authorization.k8s.io "system:metrics-server" created
```

Metric Serverがデプロイされたか確認すると、CrashLoopBackOffになっていました。

```
$ kubectl -n kube-system get po
NAME                              READY     STATUS             RESTARTS   AGE
aws-node-b8pbd                    1/1       Running            1          1h
aws-node-lmmqd                    1/1       Running            0          1h
aws-node-zk96m                    1/1       Running            1          1h
kube-dns-7cc87d595-vb7qr          3/3       Running            0          1h
kube-proxy-6sqbh                  1/1       Running            0          1h
kube-proxy-b29vj                  1/1       Running            0          1h
kube-proxy-m868n                  1/1       Running            0          1h
metrics-server-6fbfb84cdd-nqrgb   0/1       CrashLoopBackOff   21         1h
```

ログを見てみると...

```
$ kubectl -n kube-system logs metrics-server-6fbfb84cdd-nqrgb
I0726 12:44:02.490157       1 heapster.go:71] /metrics-server --source=kubernetes.summary_api:''
I0726 12:44:02.490284       1 heapster.go:72] Metrics Server version v0.2.1
I0726 12:44:02.490459       1 configs.go:61] Using Kubernetes client with master "https://10.100.0.1:443" and version 
I0726 12:44:02.490492       1 configs.go:62] Using kubelet port 10255
I0726 12:44:02.491452       1 heapster.go:128] Starting with Metric Sink
I0726 12:44:02.867833       1 serving.go:308] Generated self-signed cert (apiserver.local.config/certificates/apiserver.crt, apiserver.local.c
onfig/certificates/apiserver.key)
W0726 12:44:03.222800       1 authentication.go:222] Unable to get configmap/extension-apiserver-authentication in kube-system.  Usually fixed
 by 'kubectl create rolebinding -n kube-system ROLE_NAME --role=extension-apiserver-authentication-reader --serviceaccount=YOUR_NS:YOUR_SA'
F0726 12:44:03.222895       1 heapster.go:97] Could not create the API server: configmaps "extension-apiserver-authentication" not found
```

ConfigMapにextension-apiserver-authenticationがないことが原因のようです。

[Metric ServerのIssues](https://github.com/kubernetes-incubator/metrics-server/issues/80)でも同様のエラーが報告されています。

> I just got off a chat with AWS support. They confirmed that HPA is not supported in EKS yet. If anyone knows of a workaround, I would love to hear about it.

どうやらEKSがHPAをサポートしていないことと関係があるようですが、その繋がりがよく分かりません。
そこで、HPAの仕組みを調べました。

# HPAの仕組み

[KubernetesのドキュメントのHorizontal Pod Autoscalerのページ](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-APIs)を見てみると...

> By default, the HorizontalPodAutoscaler controller retrieves metrics from a series of APIs. In order for it to access these APIs, cluster administrators must ensure that:
>
> - The API aggregation layer is enabled.
>
> - The corresponding APIs are registered:
>
>     - For resource metrics, this is the metrics.k8s.io API, generally provided by metrics-server. It can be launched as a cluster addon.
>
>     - For custom metrics, this is the custom.metrics.k8s.io API. It’s provided by “adapter” API servers provided by metrics solution vendors. Check with your metrics pipeline, or the list of known solutions. If you would like to write your own, check out the boilerplate to get started.
>
>     - For external metrics, this is the external.metrics.k8s.io API. It may be provided by the custom metrics adapters provided above.
>
> - The --horizontal-pod-autoscaler-use-rest-clients is true or unset. Setting this to false switches to Heapster-based autoscaling, which is deprecated.

HPAはデフォルトでAPIからメトリックを収集するのですが、収集対象のAPIを使うには以下の3点を満たす必要があるようです。

* API aggregation layerが有効になっていること
* metrics.k8s.io API、custom.metrics.k8s.io API、external.metrics.k8s.io APIのうち、該当のAPIが有効になっていること
* オプションがtrueか未設定であること

1つ目の条件に登場するAPI aggregation layerとはなんなのでしょうか。

# API aggregation layerとは

[公式ドキュメントのaggregation layerについてのページ](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/)を見てみると...

> The aggregation layer allows Kubernetes to be extended with additional APIs, beyond what is offered by the core Kubernetes APIs.

aggregation layerにより、KubernetesにAPIを追加することができるとのことです。

> - Then, setup an extension api-server to work with the aggregation layer.

また、aggregation layerを使うには、extension api-serverを設定するようにと書かれています。
Metric Serverのエラーログに出力されていたextension-apiserver-authenticationと何か関係があるのでしょうか。

# extension api-serverとは

[extension api-serverの設定についてのページ](https://kubernetes.io/docs/tasks/access-kubernetes-api/setup-extension-api-server/)によると...

> Create a Kubernetes role binding from the service account in your namespace to the `extension-apiserver-authentication-reader` role. This allows your extension api-server to access the `extension-apiserver-authentication` configmap.

extension api-server設定手順の中には、extension-apiserver-authenticationにアクセスするためにRoleBindingを作るようにと書かれています。
ということは、extension api-serverを設定するために、extension-apiserver-authenticationが必要になるようです。
extension-apiserver-authenticationは、どのようにして作られるものなのでしょうか。

# extension-apiserver-authenticationはいつ作られるのか

[Service Catalogのドキュメントのauth.md](https://github.com/kubernetes-incubator/service-catalog/blob/master/docs/auth.md)によると...

> By default, a main Kubernetes API server configured with the --client-ca-file option automatically creates a ConfigMap called extension-apiserver-authentication in the kube-system namespace, populated with the the client CA file. 

extension-apiserver-authenticationは、API Serverのオプションによって自動的に作成されるようです。
どうやら、EKSのAPI Serverは、extension-apiserver-authenticationが作られるように設定されていないようです。

# 結論
EKSでkubectl topやHPAが使えない理由をまとめると以下の通りです。

* EKSはAPI Serverのオプションでextension-apiserver-authenticationを用意していない。
* extension-apiserver-authenticationがないため、extension api-serverを設定することができない。
* extension api-serverを設定することができないため、Metric Serverがデプロイできない
* Metric Serverがデプロイできないため、kubectl topもHPAも使えない。

[Service CatalogのIssues](https://github.com/kubernetes-incubator/service-catalog/issues/2120)によれば、同じ理由でService Catalogも使えないようです。