LoginSignup
4
3

More than 1 year has passed since last update.

EKSをできるだけCloudFormationで構築した話

Posted at

背景

業務でEKSを含むアーキテクチャの設計構築を任されました。しかしながら周りにEKS経験者がおらず独学で構築方法も学びました。そしてデプロイ後も保守性の高くなるようなEKSの構築方法に大分悩まされました。
そこで直面した課題や解決方法を共有します。

はじめに

具体的なソースコードはGitHubリポジトリで公開しています。
ここでは、試行錯誤の道のりみたいなものを書きます。

今回のゴール

以下のようなEKS on Fargateを含むアーキテクチャを作成したい。
(パブリック/プライベートサブネットは2AZに跨ぐ必要あるのでそれぞれ2つずつ作っているが、図では簡略化)
image.png

EKSクラスターの構築アプローチ

EKSクラスターを構築する方法は大きく以下の2つあると考えられる。

1. EKS側からの構築

・eksctlコマンド
EKS関連のインフラ(クラスター、Fargateプロファイル、VPC等)はeksctlで簡単に構築することができる。一番楽に作るとすれば、以下のコマンドだけでEKSの所属するVPC、サブネット、NAT Gatewayなど色々なものが自動的に作れる。

$ ekctl create cluster

・kubectl
EKS内のアプリケーションはマニフェストで構成管理し、kubectlコマンドでデプロイする。

$ kubectl apply -f manifest.yml

2. AWS側からの構築

・CloudFormation等のIaCで構築する。EKSクラスター自体やFargateプロファイルはCFnテンプレートで構築できるようサポートされている。(ドキュメント

・一方、EKS内のアプリケーションはさすがにCFnで作るわけにはいかず、マニフェストで作成・デプロイする必要がある。

EKS側からの構築に頼る場合の問題点

ALBを前段に置く時

EKSクラスターにインターネットから直接アクセスさせるようなことは少なく、クラスターの前段にALBを配置してロードバランシングさせるような構成が多いと思いはず。
この時、AWS Load Balancer ControllerをクラスターにインストールしてEKS側からALBもデプロイすることが一般的な構築方法だと考えられる。(ドキュメントにもこの構築方法あり
この手法の場合、Ingressマニフェストを記述しkubectl applyするとALBが作成される。そうするとALBが自動的にEKSクラスタと紐付けられる。
image.png

最初はこの、「EKS側からの構築」アプローチで進めていたが、問題が発生した。

ALB(Ingress)とそれにアタッチするリソースの結合が保てない

要件の一つとして、セキュリティのためALBにWAFをアタッチする必要があった。この時、一つの疑問が生じた。
「Ingressマニフェストを更新してEKS側からALBを更新しても、WAFはアタッチは保持されるんだろうか…🤔」
そこで検証してみたが、不安は的中した。。
$ kubectl applyでIngressをデプロイし直すとWAFは外れたり外れなかったりした。
これではEKSのバージョンアップ等、運用中に更新が入った時にWAFが外れてしまい、知らず知らずのうちに当初の構成と違うものになる恐れがある
(バグの可能性あり、今後改善されるかもしれないが)
image.png

現実的な構成として、ALBに関連付けられるリソースはWAF以外にもRoute53, ACM, セキュリティグループなどたくさんある。これらとの結合を保持させるようEKS側で実装させるのは難易度が高い。。

(ただ、WAFのアタッチだけならIngressマニフェストのannotationで記述して保持することができます)

CloudFormationで構築してみた

そこで、「ALBをIngressマニフェストでEKS側から構築するんじゃなくて、CloudFormationでAWS側から構築してEKSと結合できないか?」と考えた。これが実現できればCloudFormationの記述でALBに関連づけられるリソース群(WAF, Route53, SG等)との結合保持も担保できる。
しかも現場でよく使っているCFnテンプレートを簡単に使いまわすことができ、Ingressマニフェストを書く必要なくなり工数削減にもなる。

しかし、ここでも問題が発生した…

1. 問題点:TargetGroupが設定できない

CloudFormationで作成したALBと、EKS側で(マニフェストで)作成したEKSアプリケーションの結合がうまくできなかった。
image.png

EKS on Fargateを用いている場合、ターゲットグループでIPタイプでバックエンドを指定する必要がある。
AWS Load Balancer ControllerでALBをデプロイした際は、この結合をEKS側がよしなにやっており、起動中のPodのIPアドレスを自動でターゲッティングしてくれていた。
しかし、今回ターゲッティングは自動でしてくれない。PodのIPは動的に変わるから手動で指定することも不可能。

2. 解決策:TargetGroupBindingを使用

何か解決策はないか…。とネットを彷徨っていたら、バッチリのものを見つけました。
TargetGroupBinding
これはAWS Load Balancer Controllerのカスタムリソースで、ターゲットグループARNと、ALBにアタッチされているセキュリティグループを書いたマニフェストをデプロイすることで、以下のように実行中のPodを自動でターゲッティングしてくれるというもの。
image.png

これにより、AWS LoadBalancerControllerは使うものの、ALB自体ではなくPodターゲッティングだけEKS側に任せて、ALBはCloudFormationで管理できるようになった。

 まとめ

・ALB-EKSを連携する場合、AWS LoadBalancer ControllerでALBをデプロイする方法が一般的だと思われるが、その時にはALBと他リソース(WAF, Route53等)のアタッチ保持問題が発生する。
・そこで、CloudFormation等AWS側でALBをデプロイし、TargetGroupBindingによりEKSと結合させる手法をとった
・これにより、以下2点の問題が解決できた。
1. ALBとそれにアタッチするリソースとの結合をEKSアップデートがあっても保持させる。
2. 従来の(EKSがないアーキテクチャでの)オペレーション通り、大半のリソースはCloudFormationで管理し、アプリケーションに関連する部分だけK8sマニフェストで記述して構築、管理の工数を削減。

 最後に

今回の構成のCloudFormationやマニフェストファイル、デプロイ手順は私のGitHubリポジトリで公開しています
参考までにどうぞ。

参考1:AWS Load Balancer ControllerのTargetGroupBindingを試す
参考2:TargetGroupBinding を使って AWS EKS で Kubernetes を無停止かつ DNS 切り替え無しでバージョンアップしました

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3