ストレスのない分散チーム開発 AWS編

Global Mobility Service株式会社(以下GMS)というスタートアップでソフトウェアエンジニアをしているkooogeです。
[Global Mobility Serviceのアドベントカレンダー](https://qiita.com/advent-calendar/2019/global-mobility-service)の3日目です。
昨日は、インターンの[Shiruba](https://qiita.com/Shiruba)さんの[エンジニアの教養、フレームワーク解剖学【Express編】](https://qiita.com/Shiruba/items/0543415d9a410390e0b8)でした。
弊社もついにアドベントカレンダーデビュー、組織の成長を感じています。

サービスの成長とともにチームの規模が拡大していくにつれ、本来のシステム開発とは異なる部分に時間がかかるようになりました。この記事では、分散したチームにおいて、ストレスの（すく）ないシステム開発手法の実現に向け、弊社の事例を紹介します。

## 地理的に分散したチームと1つのAWSアカウントの限界
スタートアップでは、リーンにシステム開発を進め、必要になったときにスケールさせていく、ということはよくあると思います。AWSの利用方法に関しても同様に、多くのスタートアップは、1つのAWSアカウント、1つのEC2インスタンスから始まったのではないでしょうか。

弊社は、日本、フィリピン、カンボジア、インドネシア、韓国に拠点があり、各1人～10人ほどの小規模な開発チームが存在し、それぞれ連携はするもののチームごとに別々のシステム開発を行っています。当初これらのシステムは、日本のインフラ担当が管理運用する1つのAWSアカウントで開発を行っていました。サービスがスタートしたばかりの頃は、この構成でも大きな問題はありませんでしたが、チームが拡大してすぐに限界を迎えました。

#### XXXXを作ってください。が辛くなった
> EC2作ってもらえますか？

まず、（当たり前ですが）インフラ担当が、リソース作成や管理に時間を取られるようになります。サービスの立ち上げ時にリソースを作成を依頼されていましたが、プロダクション環境用のリソースだけでなく、ステージングや開発用の環境も作成が必要な場合があり、倍々に作業が増えていきました。これに関しては、Cloud FormationやTerraformである程度の構成管理と設定の再利用が可能です。しかし、インフラ担当不在の組織においては、サービスの直接の価値ではない部分に学習コストをかける必要があるため、厳しいと思います。
また、リソースは作成するだけでなく、設定変更のたびに作業が必要となります。チームの拡大に伴ってインフラ担当の仕事量が純粋に多くなり、いずれ作業が追いつかなくなります。

#### XXXXは今どういう状況ですか？が辛くなった
> サービスの待ち受けポートを増やしたいのですが、AWSの設定を確認してもらえますか？

など、インフラの固定の管理者がいる場合、各チームはリソースの設定の変更だけでなく、単なる確認もインフラ担当に行うようになります。これは、チームがAWSの学習の機会を与えられていないためです。これに関しては、自由にAWSリソースの状況を見れるIAM Userを配布することで解決は可能ですが、実際にリソースを触ってみないと身に付かないことは多いと思います。

#### XXXXを使いたいけど、インフラ担当が多忙ですぐに使えなかった
インフラの担当が多忙となり、リソース作成や設定変更に時間がかかるようになり、サービス開発のボトルネックとなってしまいます。

また弊社では、国をまたぐチーム間の作業依頼がオーバーヘッドとなりました。アジアに展開する各チームの母語は日本語、タガログ語、クメール語、インドネシア語、韓国語とバラバラです。英語が意思疎通を図る言語となりますが、それぞれの第２言語であり、完璧ではありません。作業依頼は通常以上のオーバーヘッドとなります。

#### 管理者を増やしつつ、権限分離をしたいけどIAM辛かった
インフラ担当が忙殺されたある時を境に、インフラの管理者を各拠点に設ける作戦に変更しました。ただし、全員が全権限を持つ管理者になるというわけではありません。 `うっかり他拠点のリソースに干渉できることのないようにしよう` という権限分離を実現すべく、このためにIAM Policyを細かく設定しなければなりませんでした。IAMは地味ながらAWSで一番重要なサービスなんじゃないかと思っていますが、きちんと使おうとするととにかく複雑です。やっていくうちに、いくつか矛盾が発生してしまう部分がでてしまいました。IAMで完璧な権限分離をやりきるプラクティスは存在するとは思いますが、IAMに時間を避けるIAMマスターがいないと厳しいと感じました。

また、会計管理の関係で各国の拠点毎にAWSの利用料を算出する必要がありました。リソースに特定のTagを含めるようにお願いし、そのTagを元に集計していましたが、Tagに対応していないリソースがあったり、Tagをつけ忘れたりなど、正確ではなく大雑把なものとなってしまいました。

#### XXXXを試しに使ってみたいけど、インフラ担当に依頼するのが面倒だった
各チームが成長してくると、AWS LambdaなりAmazon CloudFrontなり自由にAWSのサービスを駆使して自分たちのサービス開発したい、という要望がでてくるようになります。しかし、これは前述の複雑なIAMによる権限分離のおかげで、インフラ管理者の設定の見直しが必要となってしまってしまいました。このような状況が続いてしまうと、高いコミュニケーションコストを払ってまでインフラを洗練したくない、という心理的障壁が少なからず生じています。実際に各チームは多少効率が悪くても、自分たちができる範囲内でやろうとしてしまっていました。素早いサービス開発によって顧客に価値を提供するために、使いときすぐ使えるインフラを提供できることが本来あるべき姿であり、インフラ担当としても本位ではないではずです。

## AWSアカウントの分離
1つのAWSアカウント内で共存するのが辛くなると、複数アカウントを使い分ける方法がプラクティスとして存在します。これにより、複雑なIAMの設定は不要となり、アカウントの全ての権限を持つユーザーを配布するのみとなります。加えて、利用料の算出も、そのアカウント全体の利用料となるため、設定も不要で明快です。

#### アカウントの分け方
アカウントを分割する際に、まず検討するのが、どの粒度でアカウントを分割するのか？です。これには権限分離と運用工数のトレードオフがあります。次の記事が参考になります。

https://dev.classmethod.jp/cloud/aws/account-and-vpc-dividing-pattern/

弊社では、"2. システムの種類でAWSアカウントを分割する" のパターンを採用しました。利用者側も複数AWSアカウントを持つ意味、管理者としての運用方法を学習する必要があるため、無用に複雑にすることを避ける必要もあります。特にスタートアップにおいては、必要になったときに更なるアカウント分割を実施する、という方針でよいと思います。

#### AWS Organizations
単に複数アカウントに分割すると、アカウント毎にユーザーを作成する必要があります。つまり、利用者が複数のアカウントを利用したい場合はIAM Userをアカウント毎に持ち、管理しなくてはなりません。そこで、[AWS Organizations](https://aws.amazon.com/jp/organizations/)を使って、すべてのアカウントを、つながりをもつ1つのアカウント群として扱うようにします。利用者は、他のアカウントのIAM RoleにスイッチできるIAM Userをただ1つ管理だするだけで済みます。

[支払いの一括化](https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/consolidated-billing.html)や、[リザーブドインスタンスの共有](https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/ri-behavior.html)の他、アカウント間でのリソースの参照やスナップショットのコピーなども出来るため、複数AWSアカウント運用において、AWS Organizationsを利用しない手は無いでしょう。

#### ユーザー作成は1つのアカウントにまとめる
プラクティスとして、ユーザーはどこか1つのユーザー管理用のアカウントでまとめて管理するのが良いでしょう。このアカウントは、親アカウントでも子アカウントでも可能です。
インフラ管理者は、AWSアカウントの管理と、このユーザー管理がメインの業務となるでしょう。ユーザーを作成し、どのアカウントにAssumeRoleできるかを設定する必要があります。これにはIAM Groupを用いてある程度ユーザーをグループで分けると良いでしょう。

#### アカウント間でリソースを移動するのは大変
アカウント間でAWSのリソースを移動することは、同じOrganizationであっても出来ません。最初に1つのAWSアカウントで開発進め、後に分割した場合、いずれかの手段によってあるべきアカウントに移動させる必要があります。

###### リソースを消す
説明不要と思いますが、まずそのリソースが不要な場合、リソースの削除を試みましょう。1つのAWSアカウントで長いこと運用を続けていると、どのリソースが使われているのか、何のためにあるのかを精査するのが地味に大変です。インフラをコード管理すればある程度把握できると思いますが、コード管理されていない場合は、泥臭くてもスプレッドシートなどでリソース管理台帳があることが望ましいです。(とはいえ台帳は実態と乖離していくものです。ないよりマシ程度に考えてください）

###### 別のリソースとして作り直す
状態を持たない単なるリソースの場合、別のアカウントにリソースを作り直せば良いです。ただし、これに関してもProvisioning方法がわからなくなったなど、サーバーのミドルウェア情報や設定方法が不明となり、動かせないということがよくあると思います。規模な大きな物だけでもコード化(最悪は台帳管理)しておきましょう。

###### リソースを作り直した上で、データを移動する
DBやデータストアなどの移行は時間がかかります。リアルタイムに必要のないデータはバッチを作成し、順次コピーしていきましょう。RDSなどSecurity Group内のリソースは、[VPC Peering](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-peering.html)などを用いて、アカウント間のデータ移行を行いましょう。完全オンラインでデータ移行をすることは難易度が高くなるため、計画的にダウンタイムを設定し、リソースの移動を行いましょう。

#### アカウント間で共有したいリソースをどうするか
アカウントを分割しても、いくつかアカウント間で共有したいリソースがあると思います。この場合、基本的には共有用のアカウントを作り、そのアカウントへのアクセスは、そのアカウントの利用者が等しく行えるようにしておくプラクティスが良いと思います。

##### 開発用のサブドメインを配ると便利
AWS Route 53で作成したドメインに関して、開発用や社内ツール用に共有したいという要望がありました。このとき、レコード管理はインフラ管理者が管理するようにしまっては、アカウントを分けて権限分離した恩恵を得られません。このような場合に、AAA.XXXX.YYY、BBB.XXXX.YYYのように[サブドメインを作成し、各アカウントに配る](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/CreatingNewSubdomain.html)と便利です。AWSアカウント毎にホストゾーンを作成し、AAA.XXXX.YYY、BBB.XXXX.YYYのよNSレコードを作成することで自由に使えるサブドメインが配布可能です。

##### CloudTrailで監査ログを集約する
AWSアカウントの管理で欠かせない機能として、[AWS CloudTrail](https://aws.amazon.com/jp/cloudtrail/)があります。AWSのリソース変更などをロギングする監査用の機能です。このような機能は、[Organizationsの全てのAWSアカウントに対して有効にしておきましょう](https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/services-that-can-integrate-ct.html)。1つのS3バケットに監査ログを集約しておき、管理者がいつでも閲覧できるようにしておきましょう。

## まとめ
AWSを用いて分散チーム開発をする場合のインフラ管理について、事例を交えて説明しました。
組織の成長の合わせ、インフラの利用方法も適切にスケールさせる必要があります。これはAWSのアカウント利用に関しても、同じことが言えます。AWS Organizationsを利用し、各チームにAWSアカウントを配布することで、AWSの運用が楽になり、チームも自由にストレスなくAWSを使い倒せるようになります。

GMSで、[よりよいチーム開発についてお話ししませんか](https://www.wantedly.com/projects/381879) ٩( ᐛ )و