AWSで開発環境自動構築とslackからのデプロイを実現した話

本記事は[サムザップ #1 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/sumzap1)の初日の記事です。
ゲーム開発においてどんな環境で開発を行っているのかを少し紹介できたらなと思います。

# 本題に入る前に
初日の投稿ということで少し会社のことを紹介させていただきます。
私の所属している[サムザップ](https://www.sumzap.co.jp/)は2009年に設立した会社で、[サイバーエージェント](https://www.cyberagent.co.jp/)の子会社になります。

スマートフォンゲームの企画・運営・配信事業を行っている会社で、先日[このファン](https://konosubafd.jp/)
の事前登録を開始しました。興味がありましたらぜひ登録お願いします。

私自身は現在SREチームに所属しており、システムの構築・改善・効率化などを主に行っております。

ということで前置きはこのくらいにして
早速....:point_up::point_up:
タイトルで上げている内容に移っていきます。

# 前提
・ インフラ歴2半年
・ GCP歴2年
・ 新規プロジェクト始動時にアサイン
・ AWSは今回初挑戦!!
・ 基本的にterraformで構築
・ 実装期間(作業時間ベース)2週間くらい

# 目指したこと
・ とりあえずコンテナ使いたいよね
・ [2017年のアドベントカレンダー](https://qiita.com/hiroki_shimada/items/ba433b18478d98e589ad)でAWSちょっとさわった時のノウハウを使う
・ なるべくコストは抑えたい(みんなそうだよね :eyes:)
・ 今どきっぽいデプロイしたいよね

# 構築したデプロイの流れ
今回作成したデプロイシステムは主に2種類あります。
1. gitへのpushを契機に開発環境を自動生成
2. slackから固定環境へのデプロイ

---

### 1.のシステム
まず1. のシステムから説明してきます。
今回はデプロイ周りをメインに紹介したいので、各リソースの作成は予め行っている前提で話を進めます。
開発環境の構成は下記の図のようになっています。

![スクリーンショット 2019-11-29 17.45.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210637/9b386d16-69c2-a0a5-24bc-e33ba749aa70.png)
構成だけ見るとめっちゃシンプルですね:rolling_eyes:

上記環境に対してデプロイを行う処理の流れは以下です。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210637/d92aa8b8-10ab-9764-b93b-928d39653d47.png)
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210637/4fc4b7ca-ccfc-3428-2219-8857ce3641fa.png)

1-1. githubへの特定リポジトリの特定ブランチ(feature/dev-〇〇)を[CodeBuild](https://aws.amazon.com/jp/codebuild/)でhook。
1-2. 特定ブランチ内のbuildspec.ymlを読み込んでユニットテスト実行
1-3. ユニットテストが成功したらイメージを作成
1-4. 作成されたイメージを[ECR](https://aws.amazon.com/jp/ecr/)にPUSH
1-5. DBの作成とマイグレーション
1-6. TerraformでLBのターゲットグループと[Fargate](https://aws.amazon.com/jp/fargate/)のサービスを作成

※ DBは予め[Aurora](https://aws.amazon.com/jp/rds/aurora/)を1クラスター立てておき、その中でブランチ名をサフィックスにしてDBを作成しています。
※ Cacheは予め[ElastiCache](https://aws.amazon.com/jp/elasticache/)を1クラスター立てておき、キャッシュキーにブランチ名をサフィックスとして保存しています。

---

### 2.の構成
次に2. のシステムを説明します。
デプロイを行う環境自体は1.の構成と変わりありませんが、別環境を用意します。

デプロイを行う処理の流れは以下です。
![スクリーンショット 2019-11-29 17.37.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210637/d10ee326-13e4-0605-aa31-963e8336e38c.png)
図がカオス:sweat_smile:

2-1. slackからスラッシュコマンドを発行
2-2. [API Gateway](https://aws.amazon.com/jp/api-gateway/)①を通して[Lambda](https://aws.amazon.com/jp/lambda/)①を起動
2-3. Lambda①が対象の[CodePipeline](https://aws.amazon.com/jp/codepipeline/)を起動
2-4. CodePipelineがgithubからソースを取得
2-5. ソースの取得が終わったらCodeBuildを起動し、イメージ作成+ECRへPUSH
(ここでDBのマイグレーションも行っている)
2-6. イメージの作成が終わったら[CodeDeploy](https://aws.amazon.com/jp/codedeploy/)が起動しBlue Greenデプロイ開始
2-7. 再ルーティング待ち状態を[Cloud Watch Events](https://aws.amazon.com/jp/cloudwatch)で拾ってLambda(2)を起動
2-8. Lambda②からslackに通知
2-9. デプロイが正しいかテストを行い「再ルーティング」か「ロールバック」かを選択
2-10. 選択結果をAPI Gateway②が拾いLambda③を起動
2-11. lambda③がCodedeployのステータスを変更する

パイプラインは現在ステージが3つ
![スクリーンショット 2019-11-29 17.07.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210637/2d1cb1f3-3f49-ecab-472f-6dcc01059f24.png)

slackでの実行結果はこのようになります。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210637/ff59b767-a732-55a1-1f0e-6de3d33b8eee.png)

# まとめ
今回は使用状況に合わせて2つのデプロイシステムを構築しました。

1.のシステムは<font color="Red">**開発の初期段階**</font>から導入をしています。
デプロイ周りの実装は今まで優先順位が低くなりがちで開発後期に回されることが多かったですが、はじめにしっかり設計することでかなり効率的に開発を進めることができています。もしこのあたりの実装を後回しにしていたり、そもそも自動化されていないシステムで運用しているところがあるならば、かなりの工数をロスしていることになります。ぜひ参考にしていただき取り入れていただきたいです。

2.のシステムは<font color="Red">**固定環境構築時**</font>に合わせて実装したデプロイシステムです。
どのような環境かというと例えばアプリをストアに申請する際に使用する環境とか、プロモーションなどで使用する環境です。このような環境はアクセス先を固定化する必要があるので動的に環境を構築するのではなく、必要な時に必要なアップデートを対象の環境に行う必要があります。またステージング環境や本番環境もこちらに属しますね。こういった環境のデプロイもアプリ開発においてはとても多く、またミスも許されない状況が多いです。なのでシステム化をしっかりして<font color="Red">ミスを無くす</font>と共に、<font color="Red">slackから手軽にデプロイできる</font>仕組みはとても有効だと思います。


# 今後の改善
上記で上げているようなデプロイの仕組みが既に開発フローとして定着しつつあります。
ただ、これで完成！！！ということではなく、やはりまだまだ改善しなくてはいけない点は多々あります。
本番までには対応しないとなとざっくり思っていることを下記に上げて今回はしめたいと思います。

・ **CodeBuildの処理高速化**
　　-> 毎回デプロイするのに5分以上かかっている
こちらの原因はいろいろ合って、対応手段もあるのですが、1つ大きな原因だけ上げておきます。
現在のプロジェクトがPHPを使用しているためCodeBuild上でイメージを作成する際にcomposer installを行っているのですが、イメージを作成後にmigrationをするためにCodeBuildが入っているサーバでもcomposer installを走らせています。つまり時間のかかる処理が2重に走っていることになります。ここだけ解消するだけでもかなり時間を短縮できると思います。なので作成したイメージを使ってdocker runからのexecでmigrationする方法に変更対応を入れるつもりです。


・ **slackのスラッシュコマンドをボットに変更**
　　-> slackのスラッシュコマンドでは3つほど問題があります。
      　　1. デプロイ可能ユーザを制限できない(頑張れば可能だが) - ボット化してデプロイできるチャンネルを制限
      　　2. レスポンスタイムアウトが3秒である - そのためエラーメッセージが出る
      　　3. インタラクティブメッセージが使えない - ボタンが使えない、選択ボタンが消えない
この辺は最初から分かっていたことですが、ボットを作っている工数が無かったのでスラッシュコマンドで済ませてしまった感じです。機能は揃っているので開発には問題ないですが、ステージング環境以降はユーザ制限やミス防止は必須ですので、取り入れて行こうと思います。

# 参考

[ECSでCodeDeployを使用したBlue/Green Deploymentがサポートされたので早速試してみた](https://dev.classmethod.jp/cloud/aws/ecs-codedeploy-blue-green-deployment/)
[AWS CodePipeline で ECS(Fargate) へ Blue/Green デプロイする](https://qiita.com/grohiro/items/7bdab666c55fb31d7550)
[CodePipelineのステータスをSlackへ通知](https://qiita.com/ot-nemoto/items/91886f4a18c1b4e80a45/)
[slack スラッシュコマンドでaws cliを実行させる方法](https://tgctkkz.com/377)

---

明日は @ozaki_shinya の記事です。