Rails エンジンによる脱 Microservices 化のススメ

はじめに

こんにちは。ゲーム開発基盤部の池田です。

アドベントカレンダー4日目の今日は、複数の Rails アプリケーションを「ほどよく」マイクロサービス化する手法として、 Rails エンジンを用いた構成を紹介します。

Rails エンジン自体はそれほど目新しい技術ではありませんが、Ruby, Rails での開発経験のある方や、サーバサイドの開発者にとって、何かの参考になればよいな、と思います。

Rails エンジンとは何か

Rails エンジン は、Rails プラグインの一種ですが、単なるプラグインよりも強力で、 Rails アプリケーションとほぼ同等の機能を提供してくれます。

Rails エンジンは、Rails アプリケーションから次のコマンドで生成することができます。

$ bin/rails plugin new my_engine --full

実行すると、 my_engine/ ディレクトリ以下に、 app/config/routes.rb を含む Rails アプリケーションそっくりのディレクトリツリーが生成されます。

エンジンを生成した Rails アプリケーション側からは、まるで自身のアプリケーションコードの一部であるかのように扱うことができます。

そもそも、 Rails::Application クラス自体が Rails::Engine クラスを継承しており、その振る舞いを多く引き継いでいます。

なぜ Rails エンジンを採用したか

今回、担当した開発案件では、 API や管理画面機能を含む複数の Web アプリケーションが必要になることが、初めからわかっていました。

API と管理画面では、リクエスト・レスポンスのフォーマットも含め、フロントエンドに近いレイヤのニーズが大きく異なります。
従って、 View, Controller のレイヤは完全に切り離した方がよいだろうと考えられました。

一方で、データストアは共有するため、Model 層は共通化することができました。

そこで、Model 層を含む共通部分を Rails エンジンとして実装し、View, Controller を実装するそれぞれの Rails アプリケーションから利用する形を取ることにしました。

これにより、アプリケーションとしては分離しつつ、共通部分を再利用することで、開発を効率よく進めることができるようになりました。

アプリケーション構成

リポジトリとしては、Rails エンジンを共有する全ての Rails アプリケーションを、単一のリポジトリで管理しています。

ディレクトリ構成としては、以下のようになっています。

  • (root)
    • api/ ... API
      • Gemfile
      • app/
      • bin/
      • config/
      • config.ru
      • lib/
      • shared -> ../shared/
      • spec/
    • admin/ ... 管理画面
      • Gemfile
      • app/
      • bin/
      • config/
      • config.ru
      • lib/
      • shared -> ../shared/
      • spec/
    • shared/ ... 共通エンジン
         - app/
         - config/
         - lib/
         - spec/

個々の Rails アプリケーションと Rails エンジンをそれぞれ別々のリポジトリにするやり方も考えられ、実際に試行錯誤もしましたが、結局は今の形になりました。
個々の Rails アプリケーション同士は独立していますが、アプリケーションとエンジンは互いに密結合であるため、特に開発効率の点から、今の形がベストのように思います。

config/lib/ 以下は、全アプリケーションで共有可能なものはエンジン側に置き、アプリケーションごとに実装の異なるものは、アプリケーション側のディレクトリに置くようにしています。

複数アプリケーション同居のつらいところ

上記のようなディレクトリ構成は、開発上便利ではありますが、Rails アプリケーションの標準的なディレクトリ構成でないため、ときどきレールに乗れずにつらい思いをすることがあります。

特につらいのがデプロイです。
Capistrano を使っていますが、基本的に release_path 等の各種パスが「リポジトリルート = アプリケーションのルートディレクトリ」を前提としているケースが多いです。

そのため、利用している Capistrano のプラグインに対して、いくつかモンキー・パッチを当てて問題を回避しています。

しかし、その辺りは一度仕組みを作ってしまえば、普段のアプリケーション開発で意識する必要はないので、エンジンを共有するメリットの方が勝っていると感じています。

終わりに

以上、Rails エンジンを利用した複数のアプリケーション構成について、紹介しました。

エンジンを共有し、単一のリポジトリで完結させるという点では「モノリシック」に近い構成とも言えそうです。
サービスでより多くのアプリケーションが必要になったときは、必ずしも全てをこれに乗せるべきということはないでしょうが、アーキテクチャとして選択肢の一つにはなると思います。

何かの参考になれば幸いです。

明日、5日目は @haminiku さんです。お楽しみに!

参考

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る