スタディサプリENGLISHの基盤をECSからEKSに移行しました

大島 雅人
196

こんにちは、スタディサプリ ENGLISH SREグループの大島です。

オンライン英語学習サービスであるスタディサプリ ENGLISHは2015年10月のリリース1)当時は英語サプリという名前でリリースしていましたから5年が経ち、おかげさまでサービスを拡充させることができています。リリース当初からインフラにはコンテナを採用し、長い間AWSのコンテナオーケストレーションサービスのAmazon Elastic Container Service(以下、ECS)で運用してきましたが、この度ECSからAmazon Elastic Kubernetes Service(以下、EKS)に移行しました。
今回の記事では、その歴史の変遷となぜEKSにしたのかというところを書いていきたいと思います。

コンテナと歩んできた5年間

まず、ECSからEKSに移行しようと思ったきっかけの前に、インフラの歴史を少し振り返ってみようと思います。
以下に年表をまとめてみました。

年月 出来事
2015/4 英単語サプリリリース。CoreOS + fleet2)coreos/fleetで運用
2015/4 Kubernetes検証開始
2015/4 ECSがTokyoでGA
2015/7 Kubernetes v1.0がリリース
2015/7 英単語サプリの本番環境をECSに移行
2015/10 英語サプリをリリース。ECSで運用
2016/2 英単語サプリ、英語サプリをスタディサプリブランドに統一
2017/3 GKE上でDeisの検証3)Kubernetes Meetup TokyoでECSからGKEに移行したいというタイトルでLTしました
2017/8 スタディサプリENGLISH TOEICコースリリース
gRPCを使ったマイクロサービス化
ECSで運用、CLBでgRPC接続、http通信はALBへ移行
2017/9 開発環境のECSをSpot Fleetで運用開始
2017/11 スタディサプリENGLISH テキスト物販サイトリリース
2017/12 re:InventでEKSが発表
2018/2 スタディサプリENGLISH パーソナルコーチプランリリース
2018/3 GKEで複数環境の検証
2018/3 EKSの検証
2018/5 開発環境をAWS上でkopsを使ってKubernetesで運用開始
YAMLはHelm Template + kubectl applyで運用
2018/8 ECS Service DiscoveryがTokyoでGA
2018/9 ECS Service Discovery + envoyを導入しgRPCの負荷分散4)EnvoyとAmazon ECS Service Discoveryを利用したgRPCの負荷分散
2018/12 re:InventでApp Meshが発表
2019/3 スタディサプリENGLISH 英語4技能コースリリース
2019/5 Argo CD、Kustomize検証
2019/7 スタディサプリENGLISH ビジネス英語コースがリリース
2019/9 スタディサプリENGLISH 新日常コースがリリース
2019/9 ステージ環境のJenkinsジョブをEKS上のCronJobに移行
2019/10 開発環境をkopsからEKS + Spot Oceanに移行5)EKSクラスタの効率的なリソース管理にSpotinst Oceanを使おう
YAMLはArgo CD、Kustomizeで運用
2020/2 App Mesh検証開始
2020/3 本番環境のJenkinsジョブをEKS上のCronJobに移行
2020/4 開発環境にApp Mesh導入
2020/8 ステージ環境をECSからEKSに移行
2020/9 本番環境をECSからEKSに移行

簡単にまとめると、コンテナーオーケストレーションは、fleetから始まり、kubernetes導入を試みるも断念しECSへ、そして、事業・チームの拡大に伴いKubernetesを再検討しEKSに移行したという流れになっています。
システムのアーキテクチャについては途中からgRPCを利用したマイクロサービス化に舵を切り6)スタディサプリENGLISH 大規模改修の裏側、事業としても初めは一つのサービスのみでしたがTOEICコース、ビジネス英語コースなど提供するサービスを増やしながら運営を行ってきました。

なぜECSからEKSに移行したのか

前置きとして、本記事ではECSよりEKSがよいと言っている訳ではありません。OpsWorksで動いていたサービスを移行する際にECS Fargateを採用したこともありますし7)mpon/tf-ecs-fargate-pipeline-exampleというTerraformを使ってCI/CD含めて一発でECS Fargate環境を作成できるリポジトリを個人的に公開していますそれぞれ適材適所があると思っています。

その上でEKSに移行したのは、以下のようなユースケースが重なっている我々の状況においてはメリットがあると判断したためです。

  • Infrastructure as Codeを実践している
  • サービス全体が数十のマイクロサービスで稼働している
  • 複数のチームが同時並行で複数のアプリケーションの機能開発をする
  • サービス間の内部通信がありgRPCを採用している
  • たくさんの開発環境だけでなくコンテンツの入稿の環境なども必要になってくる

以下に具体的にスタディサプリENGLISHのユースケースにおけるKubernetesにするメリットについて述べていきます。

メリット1: 複数の環境を作る際にKubernetesだけで完結できる

ECSは様々なサービスを組み合わせて構築をする

ECSではサービス間通信や負荷分散を行う場合は、ALB、Target Group、Listener Rule、ECS Service Discovery、Route53などの機能を組み合わせることで実現します。それぞれの機能自体は高いレベルで安定性があり機能には問題はありません

ただ、複数の開発環境や数十の複数のサービス間内部通信を取り扱う際に、TerraformでALBやListener Rule、ECS Cluster、ECS Service、ECS Service Discoveryを作成し、一方でそれぞれの環境ごとのYAML(Task Definition)を用意するところが煩雑になってしまい、インフラのライフサイクルとアプリケーションのライフサイクルの違いをうまく吸収できていませんでした

Kubernetesだけで完結することができる

Kubernetesの場合は基本的に複数の環境を作る際にKubernetesだけで完結することができます。例えば、Serviceを使って内部のサービス間通信を行うことができます。また、複数環境を作成する際にも、namespaceを利用して一つのクラスターを論理的に分割することができます。
外部からのルーティングもIngressを利用することでKubernetesのresourceとしてYAMLで統一的に記述することができます。

Kubernetesの周辺エコシステムが充実していたこともあり、YAMLの管理もKustomizeのoverlayを利用した環境差分の吸収、Helmのchartを利用したミドルウェアのインストールの仕組みや、kubectlの高度なapplyの差分チェックアルゴリズムを利用することで簡単に複数環境のデプロイについても対応できたことが大きいです。

メリット2: gitopsによる継続的デリバリー(CD)を適用しやすい

ECSのデプロイまわりで感じていた課題

デプロイについては、recruit-mp/kangolという自社で作成したツール経由で行っていました。ECSやCodeDeployの機能追加に追従する必要がありましたが、初期の頃のECSの仕様で作ったツールのため、新機能をなかなか取り込めず新しいメンバーが独自のデプロイの仕様を把握するのに時間がかかるという問題がありました。

サービスや開発環境が複数あると、現在どこに何がデプロイされてるのかというのを把握するのが難しく、AWS CLIで取ってくるにもしても、イメージのtagを取得するには複数のAPIを呼び出して組み合わせることが必要です。
mpon/ecswalkというツールを作成し、把握しやすいように工夫はしていましたがツールのメンテナンス等を考えると手間がかかっていました。

さらに、gRPCのロードバランシングをするために、envoyのECS Serviceを前段にたてECS Service Discoveryを利用して接続先を切り替えるということを行っていましたが、単純にECS Serviceのローリングアップデートに任せると、STOP済のコンテナのIPが返ってきてしまいリクエストが落ちてしまいます。
この問題に対応するために、Blue/GreenデプロイをJenkinsとシェル、kangolを組み合わせて実現していましたが、設定ミスによりデプロイ時に障害を発生させてしまったこともありました。デプロイ周りの課題に関してはECSの課題というより我々のツールの問題ですが、各社苦労している部分なのではないかと思います。

Kubernetesはgitopsが採用しやすい

どこに何がデプロイされているか把握したいという課題については、gitopsを採用することで解決すると考えていました。
Kubernetesを利用した場合、Reconciliation Loopというアーキテクチャのおかげで常にリポジトリとの差分をチェックしておくということを実現しやすくなっています。
そのため、gitopsを実現するためのエコシステムも発展しており、Argo CDやFlux CDなど高機能なgitopsのツールが揃っています。
また、メリット1でも述べたようにAWSの複数のサービスを組み合わせることなくKubernetesのresourceとして管理できる部分が増えるので、クラスターを動作させるために必要なものをほとんどgitopsでデプロイできるようになるという利点があります。

スタディサプリ ENGLISHではArgo CDとKustomizeを採用し、Argo CDが提供しているdashboardや、公式ツールとして提供される高機能なkubectlの恩恵により、状況が把握しやすくなりました。
Argo CDを採用することで自作ツールのような独自仕様でなくなったため、今後新しいメンバーが入ってきたときも理解しやすくなり、継続的デリバリーで抱えていた課題を解決することができました。

ECSとEKS移行後のシステム概要図

ここまで移行の背景を述べてきましたが、最後に移行前と移行後の構成を簡単に紹介します。
以前は、gRPCのロードバランサーとして単体のECS ServiceとしてEnvoyをおいていましたが、EKS移行後はApp MeshとApp Mesh Controller for k8sを利用してEnvoyをInjectするようにしています。
App Meshの導入により動的にルーティングを切り替えられるようになり、Spot Oceanを利用した、より柔軟なクラスターのオートスケーリングも可能になりました。

また、ALBをALB Ingress ControllerとNginx Ingress Controllerを組み合わせた構成に変更し、Terraformで作成していたリソースをKubernetesのcontrollerに作成してもらうようにすることができ、環境の増減に対応しやすくなりました。

ECSの時の構成図

EKS移行後の構成図

まとめ

ECSからKuberntesに移行するぞと考え始めたのは、2017年の頭で当時はすぐにできそうと思っていましたが、全ての環境をEKSに一本化するまで長い道のりでした。
今後は、App Meshを導入したことでシステムの可視化がしやすくなったこともあり、可視化に力を入れてシステムの品質を高めていきたいと思ってます。App Meshを使ったgRPCのルーティングやArgo CDの運用等の詳細の記事も他のメンバーが書く予定なのでそちらもご覧いただけると幸いです。

脚注

脚注
1 当時は英語サプリという名前でリリースしていました
2 coreos/fleet
3 Kubernetes Meetup TokyoでECSからGKEに移行したいというタイトルでLTしました
4 EnvoyとAmazon ECS Service Discoveryを利用したgRPCの負荷分散
5 EKSクラスタの効率的なリソース管理にSpotinst Oceanを使おう
6 スタディサプリENGLISH 大規模改修の裏側
7 mpon/tf-ecs-fargate-pipeline-exampleというTerraformを使ってCI/CD含めて一発でECS Fargate環境を作成できるリポジトリを個人的に公開しています