EKS on EC2の本番運用に向けて考えたこと

# 背景
現場でEKSの設計構築を任され、本番環境でのEKS長期運用に向けて色々と検討したことがあったため、せっかくなので備忘録的にまとめました。詳細な実装方法は今回割愛しますが、できれば追って記事にしたいと思います。

※ タイトルにある通り今回は**EKS on EC2**の構成になるため、データプレーンにFargateを使う場合は別の検討が必要です。

# 1. 構成管理
EKSクラスターの構築方法は、$eksctl　create clusterにより簡単に構築したり、マニフェストに記述してデプロイする方法があるが、今回はCloudFormationで構築した。

その理由は主に以下3点
1. eksctlだと多くのリソースが暗黙的に作られるため、構成管理ができない（どういうインフラ構成になっているのか見返すことが大変）
2. マニフェストだとyamlファイルで構成管理できるが、AWSリソースとの結合が困難であったり、CFnと構成管理の範囲をどこで切り分けるかといった問題がある
3. 現場ではCloudFormationでテンプレートを汎用化して管理していたため、EKSもこれに合わせてCFnでできるだけ管理したい

こちらに関しては過去に記事を書いたので、ご興味ある方はどうぞ↓
・[EKSをできるだけCloudFormationで構築した話](https://qiita.com/MAKOTO1995/items/caa951c45ee119e70a60)


# 2. ロギング
### 2.1 コントロールプレーンのログ
まず、EKSクラスター（コントロールプレーン）のログは有効化設定すれば簡単にCloudWatch Logsに出力できる。CloudFormationでも各ログ出力の記述可能。
・[【ドキュメント】Amazon EKS コントロールプレーンのログ記録](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/control-plane-logs.html)

### 2.2 データプレーンのログ
Podは基本的に一時的な存在であり、削除・再起動するとPodに実行中のアプリケーションのログも一緒に消えてしまう。しかし障害対応時にログはもちろん非常に大事なため、ログが永続化されていないのはかなりまずい。
そこで、**Fluent Bit**をデータプレーンにデプロイしてCloudWatch Logsに転送する方法をとりログ永続化を実現した。
・[【ドキュメント】CloudWatch Logs へログを送信する DaemonSet として Fluent Bit を設定する](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs-FluentBit.html)

※ 少し前はログ転送に**Fluentd**が使われていたようだが、今はAWSでは非推奨になっている。

# 3. オートスケーリング
**水平スケーリング（Podのオートスケーリング）**、**垂直スケーリング（ノードEC2のスケーリング）**の2種類ある。拡張性が求められるサービスであれば両方実装する必要があり、今回の案件でも実装した。

### 3.1 水平スケーリング
K8sのオブジェクトである`HPA（Horizontal Pod Autoscaler）`と、Podアプリケーションのメトリクスを監視するための`metrics server`を使用する。
・[【ドキュメント】Kubernetes Metrics Server と Horizontal Pod Autoscaler を、Amazon EKS 上でセットアップする方法](https://aws.amazon.com/jp/premiumsupport/knowledge-center/eks-metrics-server-pod-autoscaler/)

### 3.2 垂直スケーリング
　HPAによりPodのスケーリングは実装できたものの、さらにリクエストが増えPod数スケーリングすると、ワーカーノード（EC2）のリソースが上限に達した時にそれ以上スケーリングできなくなる。そのため、ノードEC2のオートスケーリングも必要となる。
　`Cluster Autoscaler（CA）`をデプロイすることでノードのオートスケーリングを実装する。
・[【ドキュメント】Cluster Auto Scaling をデプロイする](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/cluster-autoscaler.html#ca-deploy)

　ただしCAを使用してオートスケーリングさせる前提として、`セルフマネージドノード`（EC2を手動でEKSクラスターのワーカーノードとして参加させる方法）ではなく、`マネージド型ノードグループ`を使用してEKS側でEC2の起動・削除をできるような構成にしておく必要がある。
　マネージド型ノードグループもCloudFormationでサポートされているため、今回の案件でも記述して構成管理するようにした。
　このあたりの実装方法も後日記事にしたいと思います。


# 4. kubectl操作権限管理
　`eksctlコマンド`の権限管理は、従来通りAWS IAMで行える。
一方、`kubectlコマンド`についてはK8sの認証認可機能である`RBAC（ロールベースアクセス制御）`により管理されており、K8s側での権限管理が必要となる。
　具体的にはEKSクラスター作成直後、クラスター作成者がEKSクラスターに接続し、aws-auth ConfigMapの設定を編集して別IAMユーザ/ロールに権限付与する必要がある。

アクセス権付与方法↓
・[【ドキュメント】Amazon EKS でクラスターを作成した後、他の IAM ユーザーおよびロールにアクセス権を付与するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/amazon-eks-cluster-access/)

　今回構築したEKSクラスターは**プライベートAPIエンドポイントのみ有効化**（VPC内からのみ操作可能）しており、VPC内の踏み台EC2からのみ接続できるようにしている。そのため、踏み台EC2に付与しているロールをConfigMapの設定に追加することとした。
→ 踏み台EC2にログインすればEKS操作可能。

　ただ、上記に加えて**パブリックAPIエンドポイントを有効化**する場合は、踏み台EC2ロール以外もConfigMapに追加していく必要がある。ローカルから接続許可するIAMユーザをいちいちConfigMapに追加していくのは面倒。。
　そこで以下の記事では、IAMユーザではなくIAMロールをConfigMapに追加し、このロールにassumeRoleできる権限を管理する方法としていた。これなら運用も楽になりそう。
・[【Qiita】EKSの管理者権限の管理方法について](https://qiita.com/Ichi0124/items/8e9325f7bb0305cfe843)

# 5. カスタムAMIの適用
　PoCの段階では、[EKS最適化AmazonLinux AMI](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/eks-optimized-ami.html)を使用してワーカーノードEC2を起動していた。
　しかし実際に開発チームがアプリケーションをEKS上にのせる際は、独自でカスタマイズされたAMIを使用することが多いはず。そのためマネージド型ノードグループからEC2を起動する場合にカスタムAMIを使えるか検証した。

・[【ドキュメント】ワーカーノードを Amazon EKS クラスターに参加させる方法を教えてください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/eks-worker-nodes-cluster/)

　結論、UserDataのbootstrap.shの引数に以下を指定することでカスタムAMIの起動・クラスターへの参加ができた。(上記ドキュメントからだとクラスタ名だけ指定で良さげに見えるが、3つとも指定しないと参加に失敗するので要注意)
1. クラスター名
2. `--b64-cluster-ca`: クラスターCA
3. `--apiserver-endpoint`: クラスターのAPI ServerエンドポイントURL

※ EKS上で使えるカスタムAMIの作り方自体は、担当範囲外だったため未調査です。


# 最後に
ダイジェスト的な内容で字ばっかりになってしまいました…。
気乗りした時に詳細な実装方法を書いていきます。