開発効率をあげるための半年間の取り組み

所属するチームのプロダクトローンチから半年、ここ半年でチームの開発効率を上げるためにやってきたことを振り返りたいと思います。

ローンチまではとりあえず完成物を世に出すことを目的にやってきたため、過去の別プロダクトの社内資産（インフラの設定ファイルやDockerfileなど）を使い回していたのですが、2,3年も経つと各種のツールはより便利になっているしインフラもかなり進化しています。ローンチ後、ユーザーが増えるにつれ社内外から改善要望も増え、開発チームとしてはいかに素早く機能開発・リリースのサイクルを回せるかは重要な点でした。

インフラの変更といった大きいものから日々の業務の細かい改善まで粒度はバラバラですが、取り入れてきたものを挙げてみます。

## 小さい改善
### Githubのイシューを自動クローズするようにした
弊社の開発チームではGithub上でイシューを管理しています。
今までイシューの対応が完了するたびに手動でクローズしていて無駄だったのですが、コミットに`Github指定のキーワード`+ `イシュー番号`を入れるだけで、プルリクエストがマージされたら自動でクローズできます。

```
git commit -m "fix #i100"
```
* [Linking a pull request to an issue] (https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-)

### commitlintを入れた
メンバーがコミットにイシュー番号を必須で入れてもらうためにcommitlintを入れました。

* [commitlint](https://github.com/conventional-changelog/commitlint)
* [commitlint の紹介](https://qiita.com/ybiquitous/items/74225bc4bf0a9ddcd7dd)

## 大きい改善
### デプロイをシェルスクリプトからGithub Actionsに変更した
以前は踏み台サーバーにリリース用のシェルスクリプトを置いておき、Githubから踏み台にプルしてリリースしていました。リリースのために踏み台にsshしたり手作業でデプロイする手間がかかっていました。

後述するインフラのECSへの変更により、CIの導入が容易になったため、リリース方法はGithubActionsに変更しました。

stageブランチにマージしたらステージ環境に自動リリース、本番リリースについてはマージベースだと事故が起きる可能性があるのでGithub上でバージョン番号をタグ付けしたらリリースするようにしています。
Github主体で開発している場合、Githubでのイベントを細かくトリガーにできるところはActionsを使う大きいメリットだと思います。

Githubでプルリクエストをマージ→GithubActionsでビルド→CodeDeployでECSにブルーグリーンデプロイという流れは本当にスムーズで見ていて気持ちいいです。

Githubでタグ付けしたバージョン番号をそのままDockerのタグ名に使うと、ECR上でのバージョン管理が容易になります。

### インフラをECSに変えた
以前は社内で運用経験のあったAWA Elastic BeanstalkでDockerコンテナを稼働させていました。
Beanstalkはソースコードをデプロイするだけでアプリケーションを稼働させられるのでこれはこれでメリットはあったのですが、デプロイ後に旧環境と新環境のスワップ作業が発生するなど、CIを含めた全体の開発プロセスを効率化するにはサービスとして物足りない部分がありました。

元々Dockerを導入できていたこともあり、コンテナ運用に特化したECSへの変更を行いました。サーバー管理もやめたかったのでEC2ではなくサーバレスのFargateを採用しています。

まだ試行錯誤で運用している段階ではありますが、すでに変更によるメリットが色々ありました。具体的には以下のようなことです。

* CIツールを入れた開発プロセスの全体構築が劇的にスムーズになった
* CIの導入によりリリース作業が自動化できたことで、今まで週一回しかできていなかったリリースを毎日行えるようになった
* 一回のリリースの変更範囲が小さくなったことで、影響範囲を把握しやすくなり、万一リリース後に不具合が見つかってもすぐに原因特定できるようになった
* サーバーの管理をしなくて良くなった
* 負荷に応じたDockerコンテナの増減が容易になった
* 検索した時の情報量がBeanstalkに比べて圧倒的に豊富なため、課題が発生した時の対処や心理的負担がかなり軽減した
* 開発プロセスがモダンになったことで自分含めメンバーのモチベーションが上がった（これはチームの様子を見ての個人的感想）

ECSの導入に当たっては、AWSのセミナー映像や資料をかなり参考にさせていただきました。神様！！

* [【初級】AWS コンテナサービス入門 | AWS Summit Tokyo 2019](https://www.youtube.com/watch?v=L4bLDNRSYC8&ab_channel=AmazonWebServicesJapan%E5%85%AC%E5%BC%8F)

### CodeDeployのブルーグリーンデプロイを入れた
ブルーグリーンデプロイ自体はBeanstalkを使っていた時から行なっていました。
しかしながらBeanstalkでは、Lambdaで切り替え処理を別途用意するなどしない限り、新環境と旧環境の切り替えや一定時間後の旧環境の終了などが自動で行えませんでした。

ECSはCodeDeployと連携しているため、これらの作業を痒いところに手が届くようにやってくれます。

* 事故がおきた時のロールバックがボタン一つで簡単にできる
* 旧環境は指定時間経過後自動で終了できる
* トラフィックが切り替わるタイミングも非常にわかりやすいです↓

![スクリーンショット 2021-03-21 13.45.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260824/12f4813b-6d75-d07f-3684-a8c793b7d93b.png)

なお、CodeDeployとECSを組み合わせたデプロイプロセスの構築に当たってはクラスメソッドさんの資料を大いに参考にさせていただきました。

* [あなたの組織に最適なECSデプロイ手法の考察](https://dev.classmethod.jp/articles/ecs-deploy-all/)

### Cloudformationでインフラをテンプレート化した
ECSの環境を今後簡単に再現できるようにするために、ECS環境を作るに当たってはCloudformationで構築しました。

ロードバランサー、S3バケット、Cloudwatchのロググループ、VPCのセキュリティグループなどなど、プロダクトを構成するインフラを関連付けグループ化できるので、後から一つ一つのリソースを見たときに「これは何に使われているものだ？？」「間違って削除」みたいなことが起きづらくなりました。

ただし、インフラ稼動後にテンプレートと実際のインフラの状態を完璧に一致させ続けることは難しく、ここは最初のプロビジョニングのみに利用するにとどまっています。

こちらもクラスメソッドさんのブログに本当に助けられました！！

* [CloudformationでFargateを構築する](https://dev.classmethod.jp/articles/cloudformation-fargate/)

## 今後試したいことリスト
世の中の会社のブログなど見聞きしているとまだやれることはありそうです。やってみてダメだったら捨てる感じで色々手を加えたい。

#### CodeDeployのテストリスナーを使う
CodeDeployではテストリスナーを設定できます。例えばリリース時、新環境に切り替える前に、トラフィックは旧環境に向けたまま同じデータ8080ポートで新環境を試すといったことができるみたいです。

#### CodeDeployでリリース状況をチャットに流す
CodeDeployのトリガーを使うとデプロイステータス随時SNSに通知できるので、それをLambda経由で開発者向けにSlack、ビジネスサイドにもChatworkへ通知する。

#### GithubActionsをもっと活用する
先日この記事を拝見し、もっと日々の業務改善に使えそうな感じがしました。
[GitHub Actionsで日々の小さな作業を自動化する](https://tech.pepabo.com/2021/03/03/ec_efficiency_with_github_actions/)

#### ステージ環境を使っていない夜間・休日は自動でコンテナの数を0にする
こちらもクラスメソッドさんのブログで拝見しました。
[検証環境のFargateのタスクを定期停止・定期起動してみた](https://dev.classmethod.jp/articles/fargate-service-task-schedule-stop-start/)
あまり大きいコストメリットはないかもしれませんが、少ない予算で回しているチームのため、できることはやろうという感じです。

## 終わり

改善していく作業、自動化していく作業は楽しい！