マルチAWSアカウント/マルチテナントEKSから始める権限移譲
サービスチームが触ることのできる範囲を徐々に広げ、各チームが独立性を持って動けるようにしつつも、まだまだ結合度の高いアプリケーションが多いためネットワーク的な疎通は保ちたい。この課題を解決するために、我々はマルチテナントEKSおよびマルチAWSアカウントを選択しました。(なお、本記事で用いる「マルチテナント」は、同じ組織内の複数のサービスが単一クラスタ上に同居しているソフトマルチテナンシーを指しています。)
シングルテナントではなくマルチテナントを採用したのは、移行時の技術的なギャップを小さく保ちながら、漸進的にサービスチームが触らなければならない範囲を増やすためです。マネーフォワードではインフラを全て中央のインフラチームが見ており、シングルテナントを採用することでクラスタ運用から全部サービスチームが見るのはギャップが大きすぎました。
また、シングルテナントで始めて最初はインフラチームがクラスタを管理し、徐々に運用を移していく方法も考えられます。しかし、この選択肢も当面はサービスチームの増加に伴い、インフラチームの運用負荷が増えていくことが予想され厳しい選択肢でした。
そのため、まずはマルチテナントでクラスタの運用負荷を減らしつつ、Namespace単位でのサービスチームへの権限移譲を行いチームごとの自由度を確保する。これにより、サービスチームが触ることのできる範囲を少しでも広げることを最優先にしました。
一方、シングルテナントの場合のBlast Radiusの小ささやチームごとの自由度の高さは非常に魅力的です。そのため、必要に応じて将来シングルテナントへ分割できるような形で移行を進めていくことにもしました。
また、マルチAWSアカウントというサービスごとにアカウントを分ける形にしたのは、サービスチーム間での独立性を保つためです。アカウントを分けることで、他のサービスへの影響を考えることなくAWSリソースへ変更を加えることを可能に、IAMの管理が比較的シンプルになります。
一方で、複数アカウントにまたがるガバナンスの仕組みや、別々のアカウントにあるサービス間での通信をどのように実現するかなど、単一アカウントに全て含まれているケースと比べて新たに考慮すべきことも増えます。このメリット・デメリットを踏まえた上で、統制やネットワーク周りの課題はインフラチームが解決し、よりサービスチームが自由に動くことができる環境を目指してマルチアカウントを選択しました。
このような意思決定を踏まえた上で、現在マネーフォワードが運用しているアーキテクチャの概要は以下の図の通りになっています。サービスごとに独立したアカウントを用意し、EKSクラスタのアカウントとTransit Gatewayを用いて接続することでアカウント間の独立性を保ちながらネットワーク的な疎通を実現しています。また、オンプレミス環境とはDirect Connectで接続することで、オンプレミス環境で稼働しているサービスの漸進的な移行を可能にしています。
この中でも、マルチAWSアカウント、マルチテナントEKSおよびTransit Gatewayをどのように利用しているのかについて、それぞれ紹介します。
マルチAWSアカウント
サービス間の独立性を保つためにサービスごとのアカウントを分けているのはもちろんのこと、インフラ関連のEKSクラスタやTransit Gatewayなどのアカウントもそれぞれ独立したアカウントに配置しています。各アカウントの責務を最小化して影響範囲を狭めると共に、将来的にクラスタやTransit Gatewayを管理するオーナーの変更にも耐えうるようにするためです。
例えば、将来的にクラスタはクラスタ管理者チームが発足し、Transit Gatewayはネットワーク管理者チームによる管理対象になったりするかもしれません。そのような変更にも耐えうるように、機能単位でアカウントを分割するようにしています。
また、各アカウントへのログインにはAWS SSOを経由するようにし、アカウントが増えてもアクセス権限を一元管理できるようにしています。Azure ADとの連携も行っているため、退職時には自動でAWSへのアクセス権限も失効します。
マルチテナントEKS
単一のEKSクラスタ上に、サービスごとのNamespace内に必要なリソースを配置することでマルチテナントを実現しています。サービスチームに対しては各サービス用のNamespace内の権限のみを付与し、Namespace内の管理はチーム内で行うことができるようにしています。
マネーフォワードでは、実際の変更に際してはArgoCDを用いてGitOpsを行っています。各サービスチームがGitHub上でチーム内にてレビューを実施すれば、インフラチームの関与無しにサービスに対する変更を加えることができるようになっています。 これにより、各Namesapce内であればサービスチームは比較的自由に変更を加えることができるようになっています。
一方で、特定のNamespace内で閉じず、クラスタに影響を与えるものはインフラチームのみが変更可能になっています。そのため、共通コンポーネントはインフラチームが責任を持って管理していく体制を取っています。例えば、AWS Load Balancer ControllerやArgoCD、Datadogといったどのサービスでも利用し、ClusterRoleが必要なものがこれに該当します。
また、共通プラットフォームとして各Namespace内で行ってほしくない操作を禁止するガードレールの整備や、クラスタのアップグレードなどもインフラチームの役割です。このように、インフラチームが共通コンポーネントやクラスタの運用を行うことで、各サービスチームはProduction Readyなクラスタ上にリソースを配置するだけでサービスを稼働させることができるようになり、Namespace内には限られるがある程度の自由度も手に入るというのが現状のマルチテナントEKS環境です。
一方、各サービスチームが自由に新しいコンポーネントを入れたり、Kubernetes APIをたたいたりして自動化するといったことには手を出しにくい環境ではあります。もしKubernetesをフル活用したいサービスチームが出てきた際には、そのサービスのみをシングルテナントに分割するということを行おうと思っています。新クラスタと旧クラスタ双方からTransit Gatewayを通じてRDSなどへの接続性は担保できるため、漸進的なシングルテナントへの移行も可能になっています。
AWS Transit Gateway
マルチテナントなEKSクラスタとサービス別のAWSアカウントのリソース間での通信を可能にするために、AWS Transit Gatewayを採用しています。先述の通り、マネーフォワードのサービスはまだまだ結合度の高いものが多く、AWSアカウントを分けたとしてもアカウント間でのネットワーク疎通が必要なためです。
他にもアカウントをまたいだ通信を可能にするための選択肢として、VPC PeeringやVPC Sharingも存在しますが、今後の組織と事業の拡大と変化に備えてTransit Gatewayを選択しています。 VPC Peeringは数アカウントから数十アカウントをスター状につなぐだけであれば問題ありませんが、数百アカウントをスター状だけでなく一部メッシュも含めてつなごうとするとすぐに複雑化してしまいます。
単一のマルチテナントクラスタで将来もずっと運用するのであれば問題ないですが、シングルテナントへの分割や今後別の運用方式が出てくることを考えると、できるだけネットワーク・トポロジーは簡素化したくTransit Gatewayを採用しています。また、VPC Sharingは単一のEKSクラスタとそこまで多くないAWSアカウントで完結するのであればコストバランス含めて有力な選択肢となります。
しかし、VPC SharingではVPC内に作成できるsubnetの上限が存在するため、アカウントごとに3AZ分のsubnetを発行しようとすると近い将来上限に当たってしまいます。上限緩和は可能ですが、実際の限界値は公開されておらず、組織拡大に合わせてどこまで使い続けることができるかが未知数です。また、将来的なシングルテナント化であったり、EKSクラスタに乗らないアカウントも利用していくことを考えると、少し柔軟性に欠ける選択肢でした。
開発ライフサイクルの変化
これまで述べてきたアーキテクチャの変更を行ったことで、開発ライフサイクル内に直接インフラチームが入る機会を減らすことができました。以前は依頼フォームからチケットを切ってもらい、インフラチームはそれを元に作業する。という形でしたが、現在は各サービスチームがGitHub上でPull Requestを作成し、チーム内でレビューとマージを行う形になっています。そしてマージ後、Terraform CloudやArgoCDを利用して本番環境への反映を自動化しています。インフラチームは共通基盤に関する変更や、サービスに関する変更でもリクエストされたものだけレビューを実施する形になっています。
現状とこれから
このように、マルチテナントEKSおよびマルチAWSアカウントアーキテクチャを採用することで従来の「触ろうと思っても触ることができない」インフラから、「触ろうと思えば触ることができる」インフラに徐々に変わりつつあります。実際に、今までインフラチームへ依頼が必要だった多くのタスクはサービスチーム内で完結するようになってきています。
しかしながら、「触ろうと思えば触ることができる」と「実際に触っている」の間には大きなギャップが存在しました。オンプレミス環境はインフラチームが全て見ていた環境だったのでなおさらです。そのため、アーキテクチャの変更当初はZoomなどでのナレッジシェアやモブプログラミング、レビューへの参加、サービスチームからインフラチームへの社内留学プログラムなどを行い、徐々にサービスチームがAWSやKubernetesを触るハードルを下げていきました。アーキテクチャのみならず、カルチャーをも変える必要があったのです。
このような変更や活動を通じて、各サービスチームは運用フェーズにおいては自由に動けるようになりました。ただ、まだ立ち上げ初期のブートストラップコストが高い点が課題です。ボイラープレートコードの多さであったり、Namespace作成などのインフラチームのレビューを必要とする部分がまだまだ多く、改善できる部分が多数存在します。今後はブートストラップのコストをいかに減らしていくか。そのためのドキュメントやツールの整備が我々の今後の課題です。
今回はインフラにおけるチーム間での結合度合いを最小化し、各チームがインフラを触ることができるようにすることで、組織全体のアジリティの向上を目指す話を紹介しました。次回はアプリケーションにおける密結合を解体し、共有リソースを最小に抑えていくことで、どのように開発組織のアジリティ向上を目指しているかについて紹介します。