とあるサービスの基盤構築記録

目次
- [前置き](#前置き)
- [インフラ構成](#インフラ構成)
- [まとめ](#まとめ)
- [おまけ](#おまけ)

## 前置き
[eeNotes](http://eenotes.work/)でインフラ兼バックエンド兼フロントエンドの足枷兼Figmaを眺めるだけの[@tetsuya28](https://twitter.com/_tetsuya28)です
普段はベンチャーや知り合いのお手伝いなどでAWSのインフラ管理などをメインに生計を立てているしがない大学院生です

今回は、去年の[夏インターン](https://voyagegroup.com/internship/)の成果物を優秀なチームメンバーと共に紆余曲折、10ヶ月もの歳月を費やし開発を続け、先週リリースしたeeNotesというサービスのインフラ構成についてざっくりとまとめてみました

https://twitter.com/eeNotes/status/1275730389290479616?s=20

## インフラ構成

なにはともあれ、とりあえずインフラ構成はこんな感じになってます
アイコンがバラバラなのは許して下さい。新しいアイコンが揃ってなかったので…

![eeNotes (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462473/4beac911-b486-4a78-d846-71a9fe84961f.png)


eeNotesではプロダクション環境とステージング環境をAWS上に構築しています
ステージング環境は諸々の事情により若干上記のプロダクション環境とは違うのですが、複雑になるので一旦なかったことに
青色の線が主にサービス内で行われる通信、オレンジがログ等、緑色がデプロイに使われるものを表しています
上記の構成を[Terraform](https://www.terraform.io/)を用いてIaCで構築しています
めちゃくちゃ大雑把な図ですが、主にデプロイ・Backend・Frontendについて解説していこうと思います

### デプロイパイプライン

prod環境は、Frontend, Backend共にGitHub上の `master`ブランチの更新を元にGitHub Actions上でDockerイメージを作りECRにpush、またCodePipelineに使う `imagedef.json` をS3にアップロード
S3へのアップロードをフックしてCodepipelineを起動してECSのタスク定義・タスクを更新。また、デプロイ情報はSNS、Amazon Chatbotを通じて随時Slackに通知しています
デプロイ時に必要な認証情報はSSMを通じて取得
基本的にデプロイに係る作業はGitHub上でPull Requestさえ作ってしまえば後はいい感じにやってくれるようにしてあるので大体MTG中にPRだけ作って後はSuccess通知が来るのを雑談しながら待っています

### Frontend

Frontendはロードバランサーを経由してECS on EC2上でリクエストを処理しています
静的ファイルに関しては前段にCloudfrontを挟みキャッシュしつつS3へリクエストを流しています
(後述のBackendと異なりon EC2で動かしているのはコスト削減の為にステージング環境と同一ホストを使っているためです)

### Backend

Backendはロードバランサーを経由、ECS on Fargate上にGolangのAPIサーバを配置し、RDS・Elasticsearchからデータの取得・検索を行っています。
ログは逐次Cloudwatch Logsに流しています

### その他

ユーザ認証周りは全てFirebaseにお任せしてあります
アラートなどは基本的にCloudwatchからSNS経由でSlackで受信しています
お金に関しては、大体こんな感じの構成をステージング環境用にも作って月3,000円程って感じで運用しています(余裕で赤字。どなたかスポンサーしてくれてもいいんですよ？？いや、まじで…)

### ロードマップ

今後のインフラの課題としては次のようなことに時間が出来たら検証しようと思ってます

- DBのマイグレーション自動化
- 属人化からの脱却
- フロントエンドをS3などで配信
- Auto Scalingの設定

## まとめ
以上、ざっくりとではありますがeeNotesのインフラ構成についてでした
MySQL、Elasticsearchやフロント・デザイン技術、チーム開発体制については他のメンバーが記事を書いてくれることを期待している♪
インフラなどについてご質問等ありましたらお気軽に[@tetsuya28](https://twitter.com/_tetsuya28)までDMでも飛ばして下さい


## おまけ
最後にeeNotesのインフラを作っていく中でのいくつかの失敗をご紹介
**良い子は真似しないでね**

### 環境はきちんと分離しよう
<img width="843" alt="スクリーンショット 95.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462473/873e1cb9-08a8-c6b6-9a1f-469079072a8d.png">
eeNotesでは当初、ステージング環境と言うものが存在しておらずAWS上ではプロダクション環境のみ稼働していました
が、やはり途中からステージング環境が欲しいということで追加したのですが、その中でGitHubのSecretsに設定する値を間違えており、ステージング環境用にビルドされたReactからプロダクション環境にリクエストが飛ぶという事故がありました

### 環境はきちんと分離しよう Part 2
<img width="860" alt="スクリーンショット 96.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462473/6c3b1cf0-eb89-37f6-46fc-0a20ce647ca1.png">
続いての失敗も環境関連の変更を加えた時期に起きた失敗
前述の通り、eeNotesでは特定のブランチの更新を元にGitHub Actionでdockerイメージを作成しているのですが、workflowの設定ファイルをミスってしまい、本来ステージング環境のイメージを更新しなければいけないのにプロダクション環境のイメージを更新してしまっていたというバグでした
**GitHub Actionは大部分がコピペだからって気を抜かずにちゃんとレビューしましょう**
ちなみにスクショに`また`とあるようにこの失敗は何度か起こしてます。笑

### リソース破壊テロ
<img width="359" alt="スクリーンショット 97.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462473/02870389-e46f-22a8-6169-cc42dcf34323.png">
コスト削減の一環でステージング環境のEC2インスタンスを整理していたときのお話
ECS on EC2やら on Fargateを行き来していてとあるタイミングでEC2インスタンスが要らなくなったと勘違いしてコンソール上でボケーッとインスタンスを削除しました
が、なんと運悪くコスト節約のためにElasticsearchとECS on EC2の共有ホストを削除してしまっていました
**ステージング環境くらいからはちゃんとインフラもコード管理 & 気分でリソース削除しないこと**