はじめに
こんにちは、SREチームのおかざきです。今回はAWS EKS Fargateを用いて、GithubのPull Requestがオープンされたら専用のコンテナ環境を起動してインフラ面の動作チェックまで全自動で行う仕組みを構築したので、ご紹介します。
※この記事はEmotion Tech Advent Calendar 2021の3日目の記事です。
なぜ作ったか
まず、弊社の既存動作確認環境についてです。 以前のブログ記事に示すように、AWS Elastic BeanstalkのECS EC2で構築されています。 弊社の開発はGitHub flowで行っており、開発したfeatureブランチの動作確認をするときは動作確認環境にCIでビルドされたDockerイメージをデプロイしますが、一つのElastic Beanstalkの管理単位(環境)に一つのブランチのDockerイメージまでしか動かせません。 そのため複数の開発が重なってしまうと、動作確認環境が埋まってしまいました。 メンバー増加により環境が足りなくなると増築するということが繰り返されてきていましたが、今後もメンバーが増える度に対応工数が必要になることや、開発リリースの頻度が多くない時は遊んだままの環境があるという形で課題がありました。
これらの課題に対する提案は以下の通りです。
Pull Requestが切られたら対応するブランチのコンテナ群を自動起動させる
既存環境は元々Elastic BeanstalkのGUIやCLIで管理される前提となっており、環境の増築に稼働が掛かっていました。 そこで環境としてEKSを利用してコンテナ、ALBといった要素を動的に起動する環境を構築しました。 起動したコンテナ群にはブランチ名を元にしたURLを払い出し、それぞれのブランチに対応するコンテナが独立して稼働する動作確認環境として利用できるようにしました。 ブランチ名はその気になると絵文字を利用したり100文字のものを指定できたりとURLとして不適切なものが指定される可能性もあるので、以下のようにブランチ名のハッシュ値をURLとして払い出すようにしています。
URL例:
https://513d284d10194305266c5dc70de6322f-app1.com
EKS、Fargateを利用することでインフラ構築、管理負荷を軽減する
EKSの KubernetesマニフェストおよびTerraformで環境の設定をコード化することで構成管理を容易にすることを目指しました。また、EKSの動作モードとしてFargateを利用することで、EC2のOSのバージョンアップやCPU、メモリの搭載量のチューニングといった対応を無くしたり、Auto Scaling Group等管理対象リソースの削減により構成管理を容易にすることを目指しました。
ただし、社内ではEKSの導入実績がなかったことや他社事例等でKubernetesの運用の大変さに触れられていることで、管理負荷を軽減する点では分からない点が多い状態ではありました。そのため、提案の環境は実験的な意図も込めてKubernetesのバージョンアップ対応をはじめとする大変さやハマりどころを把握し、イメージに対する現実を体感してみることも目的の一つとしました。
なお、課題の解決策としてブランチ戦略をGithub flowからGit-flowにすることも挙がりましたが、この環境構築当時はメンバーが現在よりも少なく、各々が開発をこなすことで精一杯な状況であったため、混乱を避けるためにもブランチ戦略の変更は保留して環境面からアプローチすることにしました。
どうやって作ったか
構成図
本環境の構成イメージを以下に示します。
EKSクラスタ上に複数のブランチに対応するPod群が起動します。
ブランチに紐づくPod群はリソース名にブランチ名のハッシュ値を付与することで、別々のアプリケーションとして稼働させます。方式としては名前空間を用いるのが一般的であると考えますが、Pod内のFluent bitコンテナからログをCloudWatch Logsに書き込むためのサービスアカウントを名前空間作成時に都度定義する必要があるなど、運用上の課題がありそうだったので、リソース名で区別することで異なるブランチのアプリケーションを並行稼働させることにしました。
データベースは費用低減のため各ブランチ毎に共通のインスタンスを利用することにして、インスタンス内にMySQLデータベースをあらかじめ複数作成しておき、ブランチ起動毎に接続するデータベースを決めてPodから接続させるようにしました。MySQLデータベースは同時に動作確認するブランチの数が大きく増えなければ追加不要なので、このような運用にしています。
環境起動時の流れは以下の通りです。
1.GithubActionsでPull Requestがopenされたらデプロイスクリプトを実行します。
2.デプロイスクリプトではkustomizeを用いてDeployment、Service、Ingressのマニフェスト生成とkubectl applyによるマニフェストの反映を実行します。
3.インターネットからのアクセス経路としてALB Ingress Controllerを利用し、ALBとRouter53のレコードの紐付けをPython boto3を利用して設定します。
4.一連の処理が終わったら、AWS Step Functionsを起動しアプリケーションの簡易動作チェックを行います。
動作確認環境の構成要素
本環境の構成要素を作成手段とともにリストアップします。 EKSクラスタより下層のVPCなどのネットワーク要素はTerraformで作成しました。EKSクラスタの要素についてはeksctlを利用しました。eksctlはAWSがメンテナンスしていることで、Terraformと比較し最新化が早い印象があったのとドキュメントがよく整備されている印象があったためです。ただ、EKSクラスタの構築についてはTerraformも対応しているはずなので、商用環境に本格導入する場合は、きちんとしたTerraformとeksctlの比較評価が必要と考えています。
Terraformで作成
- VPC
- サブネット
- インターネットゲートウェイ
- ルートテーブル
- NATゲートウェイ
- Aurora MySQL
- OpenSearch
- IAM (GithubActionsからのkubectl操作やFluent bit用サービスアカウント用IAMロール)
- S3
- セキュリティグループ
- ECR
- Cloudwatchロググループ
- ACM証明書
- Secrets Manager
eksctlで作成
- EKSマネージドクラスタ
- EKS Fargateノード
EKSのIngress, Serviceにて作成
- ALB
- ターゲットグループ
デプロイツールからPython boto3で更新
- Route53 (featureブランチ毎のエンドポイントURL用DNSレコード)
その他ビルド、デプロイで利用したツール
ビルド、デプロイには以下を利用しました。
- GithubActions
- デプロイスクリプトで動作させるKubernetes関係のツール
- kubectl、Kustomize、Helm
Kustomizeはブランチ毎のマニフェストファイルをテンプレートから生成するために利用しています。 Helmは今の所ALB Ingress Controllerを導入するためだけに利用しています。また、デプロイはKubernetes操作の習熟の意図も込めてkubectlで行っていますが、商用運用を見据えるとSpinnakerやArgoCDといったツールが妥当と考えるため、これらは今後ブラッシュアップしていく考えです。
アプリケーションの簡易動作チェックの仕組み
デプロイ処理が完了後、起動したコンテナのアプリケーションが正しく動くこと、割り当てられたMySQLデータベースに正しく接続されているかを確認したいと考えました。 そこで、StepFunctions、Lambda、Pytestを用いて簡易動作チェックを行うことにしました。 PytestはEKSと同じVPC上で起動するLambdaから実行し、以下のような観点でアプリケーションの挙動を確認します。
- 各コンテナのヘルスチェックエンドポイントにアクセスし、正常な応答が得られること
- ログイン処理のAPIエンドポイントにアクセスし、ログイン完了応答が得られること
- アプリケーションが期待するデータベースに接続して動作すること
- データベース更新を含む機能のAPIエンドポイントにアクセスし、正常な応答が得られるかとPytestから直接データベースに接続し、レコードが更新されていることを確認する
- アプリケーションがSQSやS3といった他のリソースと正しく連携できていること
- SQSやS3といったリソースを利用する機能のAPIエンドポイントにアクセスして確認する
- アプリケーション間の連携 (画面から非同期処理の呼び出しを行う等 ) が正しくできていること
デプロイスクリプトのバグ等が原因で一見動作しているが想定と異なるリソースにアクセスしてしまう状況が生じると良くないので、データベースのレコードを直接参照するなど、環境面に踏み込んで確認しています。
また、あくまでインフラ視点でのテストであることやエンジニアが利用できるようになるまでの待ち時間を最小化するため、試験項目は最小限かつ各AWSリソースとの連携を網羅する形で実装しています。
さらに、動作確認に失敗したときの切り分けを迅速に行うため、Pytestの結果はHTMLでエクスポートし、S3にアップロードしてエンジニアが確認できるようにしています。
Step Functionsを利用している理由は、Lambda Pytestが1度でパスできなかった場合を考慮し、複数回Pytestを実行するようにワークフロー化したかったためです。実際にStep Functionsで実装したワークフローはこのような形です。CheckAppStatusというものでLambdaを複数回実行しています。
最後に一連の処理が完了したら起動環境の画面URL、接続先MySQLデータベース名、Pytestの実行結果ファイルのURLをSlackに通知します。通知のイメージは以下のような形です。
運用してみて
本環境は構築してから半年近く経ちます。構築当初と比較しエンジニア人数も増え、既存のElastic Beanstalk環境だけだと足りない状況が生じるようになってきました。その点本環境により補うことができ、開発工程の効率化に少しは貢献できたかなと思います。 また、簡易動作チェックの仕組みにより環境面で不具合が生じたら気がつくことができ、迅速な調査と動作確認工程への影響を抑えることができました。 よって、一定の効果はあったのではないかと考えています。今後はブランチ戦略をGithub flowからGit-flow等へ変更することも検討されていますが、hotfixの修正等で複数の環境が必要になることも見込まれるため、引き続き本環境を利用する想定でいます。
また、構築から時間が経ったため最近 Kubernetesのバージョンアップをしました。 作業内容としては、ざっくり以下の通りです。
一部、バージョンアップに伴いkubectlの出力が変更されたためデプロイスクリプトを修正する必要があったりしましたが、その他は大きくつまづくところはなく、思い立ってから2営業日で検討から切替まで完了しました。大幅な変更がなく運が良かったのと常にトラヒックの流れている商用環境と異なり作業がしやすかったのも短時間で終わった要因とは思いますが。
EKS Fargateを利用した所感
Kubernetesは今のところ同じバージョンを使えるのが長くて一年で運用負荷が高いというイメージがありました。しかし初期構築時や切替時の手順のメンテナンスが必須になる分、BCP対応の練習になったり構築ノウハウを引き継げる形に残すことが強制されるので属人化が避けられるといったメリットがありそうです。
また、Kubernetesは学習コストが高そうという印象もありましたが、EKS Fargateの場合はコントロールプレーンおよびワーカーノードがマネージドであるため、KuberntesのPodやIngressといった概念やkubectl等の操作方法、マニフェストの書き方を覚えることになります。ただ、AWSのコンテナ実行環境であるECSも各種概念とECSタスクの記述方法を覚える必要があるので、EKS Fargateを使う分には学習コストは大きく変わらない印象でした。オンプレミスでKubernetsを運用する場合はかなりの学習量と運用稼働が必要なのではと推測しますが、Kubernetesの概念を覚えて早めに課題に取り組むためにも EKS Fargateを一度動かしてみるのは良かったと思います。
これらの点を実感できたことも、実験的に導入してみて良かった点かと考えます。
最後に
Emotion Techでは顧客体験、従業員体験の改善をサポートし、世の中の体験を変えるプロダクトを開発しています。現状のアーキテクチャもモノリスなシステムを分割していく最中でして、人手が必要ですが変化を楽しめる状況と考えています。ぜひこの記事や他の記事を見て少しでも弊社に興味をもっていただけましたら、カジュアル面談も行っていますのでご応募お待ちしております。