【EKS】k8sとTerraformにおける責務分割
こんにちは!
プラットフォーム開発チームでバックエンドエンジニアをしている、むらってぃー(@canon1ky)です。
最近リモートのお昼休みは、ピアノで紅蓮華を練習しています!
さて、本記事はEKSクラスタ構築に纏わるお話です。
先日、テイクアウト基盤の大手クライアント用サービスに対し、ElasticBeanstalkから、EKSの環境へのリプレースを行いました。
インフラ管理として、TerraformとKubernetesを用いています。
TerraformとKubernetesは、どちらもInfrastructure as Codeの文脈で語られるものです。 しかし、どちらも特性は異なり、異なったユースケースで利用します。
今回はTerraformとKubernetes、それぞれにどんな責務を持たせ、EKSの環境を構築したのかを紹介します!
TerraformでEKSクラスタを構築する際に必要な土台の話
まず、コンテナが乗る土台であるEKSクラスタを構築するためには、いくつかやり方があります。
・A. eksctlを使う
・B. AWSマネジメントコンソールから手動でクラスタを作る
・C. AWS CLIを使う
・D. CloudFormationやTerraformを使う
このうち、AとDに触れさせていただきます。
Aの eksctl は、EKSの操作に特化したコマンドです。
eksctlでクラスタを作るときには、ネットワークやセキュリティグループの構成まで良い感じにやってくれます。
しかし、CloudFormationやTerraformでAWSのインフラを管理している場合は、EKSとその周辺のリソースはその管理から外れてしまいます。
一方、DのCloudFormationやTerraformを使う場合についてです。
この場合にはEKSクラスタを作成する際に、マスターノード(EKS本体)やワーカーノードが乗るためのネットワークや、セキュリティグループなどをあらかじめ用意しておく必要があります。
つまり、Kubernetesによってコンテナが管理されるための土台を、eksctlに比べて細かく定義してあげる必要があります。
TerraformとKubernetesは別のリポジトリに乗せる
Kubernetesはコンテナオーケストレーションのためのツールです。
一方、Terraformは、AWSのリソースなどのさまざまなインフラ管理に使われるツールです。
Kubernetes Providerを使えば、TerraformでもPodやDeploymentなどのKubernetesリソースを管理できます。
しかし、TerraformはAWS環境の管理に使っており、使用するAWSサービスの種類はそこそこな量でした。
Kubernetes側で管理するアプリケーションも、かなりの数のPodの種類がありました。
そのため、TerraformではAWSサービスのみを管理する方針になりました。
また、Terraformの変更適用と、Kubernetesの変更適用は、発生する時系列が異なります。
・Terraform: アプリケーションの変更とは別に、インフラに変更が発生する場合にのみデプロイが発生
・Kubernetes: アプリケーション変更のリリース時に、デプロイが発生
このような理由から、TerraformとKubernetesは管理のしやすさ観点で、リポジトリを分ける形になりました。
また、CDを使う際にもKubernetes用リポジトリを分けておくと管理がしやすいというメリットがあります。
変更適用時に起こり得ると予測した懸念点
TerraformとKubernetesそれぞれのリポジトリを分けることが決まりましたが、1つ懸念点がありました。
リソースの適用順序の問題です。
例えば下記のリソースは、TerraformかKubernetesのどちらで用意しますでしょうか?
・ワーカーノードとして機能するEC2インスタンス
・Ingressとして機能するELB
・Ingressへ貼られるRoute53レコード
いずれもAWSサービス、およびリソースの1つですが、Kubernetesリソースの配置によって動的に変わるものです。
これらをTerraformで管理するとしましょう。
Route53レコードをTerraformで管理する場合、
1.TerraformでEKSの土台を作る
2.Kubernetesリソースのデプロイを行う
3.TerraformでRoute53レコードを貼る
となります。
↓ EKSクラスタ内のALBにDNSレコードが貼られるイメージ図
土台管理に使用するTerraformの変更が、Kubernetesの変更手順の後に、もう一度必要な形になっています。
つまり、Terraformの変更適用がKubernetesの変更適用に依存している形です。
このようにしてしまうと、アプリケーション側の管理とインフラ側のデプロイ手順が煩雑になります。
そのため手軽に環境を複製できるといった、Infrastructure as Codeの恩恵の1つがなくなってしまいますね。
さらには、Kubernetesの挙動によって動的に変わるものがTerraform側に定義されるので、いわゆる「ハードコーディング」という形になってしまいます。
しかし、Kubernetesの動きによって、動的に前述のリソースが用意されるのであればどうでしょうか。
すると、手順的には、
1.TerraformでEKSの土台を作る
2.Kubernetesでリソースのデプロイを行う
のシンプルな形になります。
したがって、TerraformとKubernetesで管理する責務を下記のように定義しました。
・あらかじめ用意しておく必要のあるAWSリソースと、EKSの土台 → Terraform
・アプリケーションのデプロイ以降のステップで生成されるべきリソース → Kubernetes
Terraformで管理するリソースの詳細
さて、それぞれの責務が定義できたところで、双方で管理するリソースの詳細を説明します。
Terraformでは、AWSリソースを定義します。
・VPC・Subnet
・SQS
・RDS
・EKS本体
・EKSのワーカーノードグループ
・Route53ホストゾーン etc..
EKSのワーカーノードグループは、ワーカーノードに対して設定するAutoScalingグループです。
・どのサブネットに置くか
・EC2インスタンスのインスタンスサイズ
・EC2インスタンスのオートスケールに対する最小・最大台数
を設定するものです。
こちらを土台として用意しておくことで、Podのスケーリングに合わせて自動でEC2インスタンスがスケールされます。
Route53ホストゾーンに関しては、Kubernetesを乗せる前にあらかじめ用意しておく必要があります。 こちらはTerraform側で管理し、DNSレコードはKubernetes側で用意します。
サブネット、AutoScalingグループに対しては、後のKubernetesリソースで使うために、
・Subnetへの タグ付け
・Auto Scalingグループへの タグ付け
を行っておきます。
Kubernetesで管理するリソースの詳細
Kubernetes側では、DeploymentやIngressなど、基本的にKubernetes側で用意されているリソースを管理します。
それに加えて、下記のリソースを管理に入れます。
・Cluster AutoScaler
・Ingress Controller
・ExternalDNS
まずは、 Cluster AutoScaler です。
こちらはPodのスケーリングに合わせて、ワーカーノードのスケーリングを自動的に行ってくれるものです。
Cluster AutoScalerに、AutoScalingグループのタグを指定しておくと、AutoScalingグループと紐づくサブネットにワーカーノードがスケーリングされます。
次に、 Ingress Controller です。
こちらはIngressの作成に合わせて、ALBやその周辺のリソースを作成するものです。
Ingress Controllerにサブネットのタグを指定しておくと、タグをたどって指定されたサブネットにALBを作成してくれます。
最後に、 ExternalDNS です。
こちらはIngressの作成に合わせて、DNSレコードをALBに貼ってくれるものです。
ExternalDNSにRoute53ホストゾーンのIDと、ホストゾーンに指定したベースのドメインを指定しておきます。
すると、ExternalDNSに指定したDNSレコードを、Ingressに対して貼ってくれます。
さいごに
今回はTerraformとKubernetes、それぞれにどんな責務を持たせ、EKSの環境を構築したのかを紹介しました!
EKSの環境の構築方法には複数のやり方があり、ユースケースに合わせて最適なやり方を選ぶのが良いでしょう。 本記事が、EKSの環境を構築する上で少しでもお役に立てたら幸いです。
また、Showcase Gigで急成長するプロダクトを一緒に作る 仲間を募集 しています! 興味を持ってくださったら、一緒にプロダクト開発しましょう!