RailsアプリケーションをApp EngineからCloud Runに移行しました

f:id:takamario:20220208155628p:plain

はじめに

CTOの高丸です。Cloud Runの勢いを感じます。

今回は我々のRailsアプリケーションの実行環境の移行に関して、お話ししたいと思います。

経緯

crispyではお買い物支援サービス「HEIM(ハイム)」のサービスを、長らくGoogle Cloud Platform(以下GCP)のApp Engineで稼働させてきましたが、Cloud Runに移行しました。

Railsアプリケーションと言えばHeroku、クラウドならAWSというのがスタートアップ企業ではよくある環境かと思いますが、個人的に使い勝手の良さを感じるところから、GCP でApp Engineを使ってきました。

それまでの経緯は、別記事になりますが、拙著の記事も参考までにどうぞ。

スタートアップ企業であれば、少人数の開発体制でインフラの管理コストを抑えるためにも、サーバーレスの環境にするのが主流かと思います。

時代はさらに、単純なPaaSというよりは、ランタイム環境にある程度の自由度を求めて、コンテナの実行環境へと変わりつつありました。

しかし、Kubernetesのような自由すぎる(設定が多すぎる)環境は、今の我々の開発組織やサービス規模には不相応であることもわかってきました。

そんな中、GCPにCloud Runという絶妙な環境が生まれました。

リリース当初は、「Cloud Functionの単純なコンテナ版かな?」とも思っていましたが、より実践的なアプリケーション使用例やユーザーコミュニティの勢いを感じたため、移行を決めました。

(Cloud Run自体の説明は割愛します)

移行前(2017年〜2021年10月)

移行前のインフラは以下のような感じでした。至ってシンプルなApp Engineの使い方です。

f:id:takamario:20220112123450p:plain
移行前

(図は一部省略してあります)

存在していた問題点

App Engine/Flexibleのデプロイが遅い

GoをApp Engine/Standard環境で動かした場合は爆速で起動しますが、Flexible環境はDockerコンテナをGCP内部で構築するため、ある程度の大きさのRailsアプリケーションになると、20分以上デプロイに時間が掛かるようになってきます。

デプロイ時間が長いと、ロールバックも遅くなるため、サービスの稼働率にも影響してくる重要な項目です。

元々は、このデプロイ時間の高速化のためにCloud Runを検討していました。

オートスケールができない(させてない)

これはあくまでも我々の設定の話なのですが、スタートアップ企業の場合はインフラコストを抑えることも大事なので、オートスケールは行わないようにしていました。

また、オートスケール設定していたとしても、Flexible環境でのRailsサーバーの起動は時間が掛かり、ベストなタイミングでスケールアウトできるとは言えない状態でした。

しかし、今後のサービス成長を考えると、オートスケールは必須であることは明確でした。

カスタムドメインがApp Engineに設定されている

これは移行に関しての問題点ですが、App Engineはカスタムドメインを設定して稼働できる設定があります。

これを使うと、SSL証明書も自動で作成・更新されるため、インフラ管理の手間が減ってとても便利なのですが、逆に言うと、DNSの設定もすべてApp Engineに向いているため、Cloud Runにドメインを移行する際に、DNSを切り替えない限り、Cloud Run側にトラフィックを流すことができず、切り替える際にネットワーク断が発生してしまう可能性がありました。

これに関しては、Cloud Load Balancingを使うことで解決しました。次のセクションで解説します。

移行途中(2021年10月〜2021年12月)

上記のネットワーク断を防ぐため、Cloud Load Balancing(以下LB)を利用することにしました。

LBが、2020年7月にサーバーレスのサービスをバックエンドに設定できるようになった(Serverless NEGs)ため、App Engineの前にLBを置きました。

ただ、今のところ複数のServerless NEGsは設定できないようです。そのため、Cloud Runの前にもLBを置きました。

f:id:takamario:20220112123623p:plain
移行途中

「このままだと、結局DNSをバツっと切り替えないと移行できないんじゃないの?」と思われたかもしれませんが、なんと我々が移行しようとしていたちょうどそのタイミング(2021年10月)で、Cloud DNSの重み付きラウンドロビン(Weghted Roundrobin)がプレビューリリースされていました。

これを使うことにより、DNSを先述の2つのLBに対し割り当てることができ、重み付きでトラフィックを調整することができるようになりました。

この重み付きラウンドロビンは、移行時の負荷を確認するためにも使えました。

いきなり、すべてのトラフィックをCloud Runに流すのではなく、1/3のトラフィックだけをまずCloud Runに流して試しました。数日おきにCloud Run側の割合を増やしていき、最終的に全トラフィックをCloud Runに流していきました。

何か問題があった場合は、すぐにAppEngine側に全てのトラフィックを流し替えることで、ロールバックも可能になりました。

移行後(2021年12月〜)

App Engine側がなくなり、Cloud Runだけになりましたが、LBは、今後移行作業が発生した場合のためにも残してあります。

また、Cloud Armorも同時に試していたので、現状もLBに設定してあります。そのまま攻撃アクセスに対するセキュリティを向上させることができるので、コストに問題なければ導入しておくのが良いかと思います。

f:id:takamario:20220112123710p:plain
移行後

また2021年9月には、Always on CPUという、HTTPアクセスを捌いている時間に限らず常時起動できるオプションも付いたので、バッチ環境としての利用も検討中です。

残っている問題点

移行は無事完了しましたが、いくつか残っている問題点もあります。

まだデプロイが遅い

移行が第一の目標だったので、Dockerコンテナのビルドの仕方がまだキャッシュを活かしきれていない可能性があり、もう少し改善ができそうです。(Asset Pipelineのプリコンパイルなど)

コストが増えてしまった

これは運用上の問題だったのですが、リビジョンタグを付与しているものにはアクセス可能になるため(タグを付与してはじめてアクセス可能になるため必要)、ステージング環境などでは、いろんなfeatureブランチのリビジョンにタグが付いている状態でした。

Cloud Runはアクセスがなくても、リビジョンタグが付いている限りアイドル状態として動いているため、料金が少しずつかかってしまい、これがコスト増加の原因となっていました。デプロイの際に古いリビジョンタグは外すようにお掃除処理をいれることで解決しました。

まとめ

App Engine/FlexibleからCloud Runに移行することで、

  • 自由なランタイム環境(コンテナ)
  • オートスケール
  • コストダウン
  • デプロイ速度向上(志半ば)

加えて、Cloud Load Balancingを使ったおかげで、

  • バックエンド移行作業の簡易化
  • Cloud Armorを使った攻撃対策

が、可能になりました。

はじめにも書きましたが、Cloud Runの勢いをものすごく感じますので、2022年はCloud Runがアツい年になるのではないかと思っています。

エンジニア募集中!

株式会社crispyに興味が出た方は、Wantedlyのページへ!