自己紹介

正徳巧氏(以下、正徳):「Deploy Rails apps in 2021」というタイトルで発表します。ちょっと私も緊張しているので、ビールを飲みながら発表させてください。

自己紹介です。正徳と言います。会社に入社して1年半ぐらいで、CTO室のSREという部署に所属しています。SNSなどは@shinsokuというハンドルネームで活動しています。よろしくお願いします。

SREでなにをやっているかというと、基本的にはAWSのインフラの改善やデプロイの改善、あとはRailsアプリのコードまわりの修正や、セキュリティまわりもちょっと直したりしていました。今日話すのは、この中でもデプロイの改善の話です。

現代に求められているのは開発サイクルの速さ

正徳:デプロイの話の前にソフトウェア全般の話でDevOpsの図を紹介します。ソフトウェアのデリバリは、昨今たぶん1回完成してリリースで終わりではなく、リリースしたあとにユーザの調査をしたり、アクセス数などを見てプランして、また新しいコードを書いてリリースというサイクルがあります。

この開発サイクルを速く回していかないといけないのが現代求められていて、何を指標にするといいかが、“どうやったら早くなるか”というところです。

いい本が1冊あって、『LeanとDevOpsの科学』。この本はすごくいい本で、この中にフィードバックサイクルを速く回すための4つのメトリクスが紹介されています。

4つはデプロイの頻度、変更のリードタイム。これはコミットしてから本番に出るまでの時間かな? MTTRで平均修復時間、障害が起きた時にどれだけ早く戻せるかの内容と、変更の失敗率、デプロイしてバグった時の率です。

どれくらいのデプロイ頻度を目指すべきか?

では一般的にはどのぐらいのデプロイ頻度を目指すべきなのかを調べてみました。この本の中にも2016年と2017年のデータがありますが、せっかくなので最近の『State of DevOps 2019』というレポートがあったので、こちらの値から紹介させてください。

このスライドの中にデプロイ頻度のELITE、HIGH、MEDIUM、LOW PERFORMERSがありますが、ELITEの会社や組織では1日に複数回デプロイしている。変更のリードタイムは1日未満。平均修復時間が1時間未満。

失敗率は意外と0〜15パーセントですが、ここはたぶんHIGH、MEDIUMを見ても変わらないので、数字だけ見ると、変更が減らしづらいのかもしれません。ただ、戻す時間が早いみたいなことが数値から見てとれます。ELITEが目指すところかなというところです。

ちなみにELITEとLOWの比較も出ていて、ELITEはLOWの208倍のデプロイ回数があるようです。そして変更のリードタイムは106倍。ほかにもありますが、だいぶ差があります。LOW PERFORMERSを見ても仕方がないので、ちょっとELITEを目指したいです。

別のページにある各クラスタの変化の割合の情報です。注目すべきは、ELITEがこの1年間ですごく増えているところです。そしてLOW PERFORMERSが減っているところ。これは個人的にけっこう注目だなと思っていて、要はどの会社もデプロイが増えている。ELITEに近づいているんですよね。

たぶん2020年だとELITEはもっと増えていると思っていて、どの会社もデプロイ頻度が増えている傾向にあるのかなと思います。

ではもう1個のレポート。今回の発表資料を作る時に見つけたので紹介します。CircleCIの2017年のレポートに、デベロップメントのメトリクスとして3つ挙げられていました。メインブランチの安定性は「いつでもデプロイできるためにCIをとおしておくべきだよね」というものなのでいいとして、デプロイ時間とデプロイ頻度は他社の時間が載っていたので紹介します。

注目する点はデプロイ時間です。これはCircleCIを使っている企業のデータだと思うのでけっこう上位層になってしまいますが、短い組織は2.7分でデプロイが終わってる驚愕の事実です。3分でデプロイが終わる。30分でも遅いとみなされている。なかなかすごいレポートだなと思いました。

デプロイ頻度については、上位の組織はメインブランチを週に32回。営業日5日で考えると、1日6回ぐらいデプロイしているものが上位組織ということがCircleCIのレポートで見えてきました。

もう1社、私がデプロイ頻度が多い会社を知っているので、そちらを紹介しようと思います。みなさん知っている、GitHub社のデプロイ頻度を紹介します。スライドがあって、この中にデプロイ頻度の回数が出ていました。GitHubはどんなデプロイをしているのか。

GitHub Flowと呼ばれる開発サイクルでデプロイしています。これはブランチを切ってコミットを積み重ね、プルリク(プルリクエスト)を作ってレビュー。議論して、コミットが増えたりして。

リスの絵が記載されている部分はデプロイのマークですが、実はGitHubではデプロイを先にしてからマージしています。このデプロイについても説明があります。

英語で書いてありますが「before marging to main」なので、mainブランチにマージする前にGitHub社ではデプロイをしています。この資料には載っていませんでしたがカナリアデプロイをしているみたいで、最初に全体の5パーセント。次が20パーセントとかで、その次に30パーセント、50パーセント、最後全体みたいなかたちで段階的にユーザーにデプロイされているようです。

もちろん問題が起きたらすぐにロールバックできる体制と、死活監視が徹底的にされているので、こんなことができるのかなと思います。

mainブランチは常に安定板なので、何か問題があったらmainブランチを再デプロイしてロールバックする運用フローになっています。

この運用でGitHub社のデプロイはどうなのかというと、2015年段階で週450回とかです。凄まじいですよね。発表スライドの中にもありますが、GitHub社、実は社員数がすごく増加しているようです。

結果、デプロイのロックやキューが混雑しすぎて次のデプロイまで5時間待ちみたいなことが起き、改善のためリリーストレインという仕組みを導入。1回のデプロイで1プルリク1リリースではなく、複数プルリク1デプロイみたいな仕組みも入れてデプロイの混雑を減らすという施策を打ったそうです。

その結果、2019年のデプロイ回数は350まで減りました。300超えているのもすごいですが。これがGitHub社です。

ここまでで、上位組織とすごい組織のデプロイ回数がだいたいわかったかと思います。上位組織は3分程度でデプロイが終わって、週に30回程度の頻度。GitHubはあくまで参考程度に「こんな回数もある」という紹介になります。

この情報をもとに考えると、現代では少ないデプロイで競合には勝てません。自分たちの競合が実はこれぐらいデプロイしている、という可能性もあるのでデプロイ頻度を上げていかないといけません。

デプロイ頻度を増やすためにやったこと

ここからはデプロイ頻度を増やすために私がやっていたこと、今後やろうと思っていることの紹介をしようと思います。まず1つ目がやったことで、デプロイの改善です。半年前のMedPeerのデプロイは、15分から17分かかっていました。デプロイ頻度が月20回から25回なので、25営業日で考えると1日1デプロイぐらいの頻度でした。

これを改善するためにやったことを紹介します。まずはデプロイの改善に関して、MedPeerのブランチ戦略の運用を図に書いてきました。masterブランチとdevelopブランチがあり、developからfeature用のブランチを切って開発を進めてプルリクを作ってレビューをして。弊社では2人のレビュアーからOKがもらえたらマージなので、ファーストレビュアー、セカンドレビュアーの意見を聞きつつ、OKだったらマージされる。

このサイクルを何回か繰り返して、「developブランチに変更が溜まってきたな」と思ったら誰かがリリースプルリクを作り、デプロイの承認者が「よし! OK!」となって承認をもらえたらマージしてデプロイ、というような運用フローになっています。

GitHubでmasterにマージしたあとにAWSのCodePipelineを使ってCodePipeline上でDockerイメージのビルドをする。そのあとにdb:migrateを実行してマイグレーションを自動的に実行して、終わってからデプロイというかたちにしていました。

このCodeBuildのDockerビルドが12分ぐらいかかっていました。GitHubにマージする前に先にビルドしておこうという施策を考えて実際にやってみました。

GitHub ActionsでDockerイメージを先にビルドして、リリースプルリクの承認待ちの間にビルドを終わらせる。こうすると、CodePipelineではマイグレーションから始まってすぐにデプロイが始まるので、けっこう高速化ができました。

これだとビルドが移っただけなのでGitHubのほうが遅くなりますが、こちらの高速化も一応いろいろやっていて、ちょっとは速くしています。ここの話は時間がなかったのでテックブログに書きました。興味がある方は「メドピア テックブログ」で検索して参照してみてください。たぶんコピペが使えるプロダクション用のDockerファイルがあるので、参考になるかと思います。

もう1つの施策として、リリースプルリクの自動生成の処理を書きました。もともとメドピアでは手元でプルリクを作るシェルスクリプトを使っていました。誰かがシェルスクリプトを叩くとリリースプルリクが作成されます。これをgit-pr-releaseというgemを使うようにして、GitHub Actions上で1日2回、朝と午後に自動的に実行するようにしました。

もちろん手動でこの変更だけデプロイしたいみたいなこともあるので、それもできるようにしてあります。実際のファイルは右側に記載した感じです。

GitHub ActionsでWeb上で実行するものも組めるので、それでやっています。Run workflowを叩くとリリースプルリクができるようになっています。

(次回につづく)