はじめに
こんにちは。ゲーム事業本部開発基盤部の池田です。
アドベントカレンダー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日目は @sairoutine さんです。お楽しみに!
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。