Rails + Hypernova なアプリを Heroku にデプロイする
個人メモ
- Heroku Container Registry で Rails アプリをデプロイするときにハマったこと - kitak blog
- Hypernova で Vue.js のコンポーネントを Rails でレンダリングする - kitak blog
の続き。
Rails + Hypernova で作った趣味アプリをデプロイすることに。
最近は Firebase を使うことも増えてきたのだけど、Express や Rails で作った API やウェブアプリのデプロイには、Heroku や Now などの Docker に対応している PaaS を使っている。
Docker 対応の PaaS で Rails + Hypernova のアプリをデプロイする際に、 1コンテナ 1サービス のお作法に従うと、Rails と Node でそれぞれ PaaS のアプリケーションを用意して、デプロイしないといけない。 このようにアプリケーションを分割すると、Rails と Node で同じコンポーネントのファイルを使用する事情から、正しく動かすには Rails と Node のデプロイ完了のタイミングを(可能な限り)揃える必要がある。
各ロールでさらに複数のアプリケーションを作っておいて、Blue-Green Deployment のようなことを実現するか、コンポーネントをHypernova に登録する際の名前にバージョンを含めるようにして、過去のバージョンも扱えるようにすればできそうだが、前者はデプロイタスクが煩雑になるし、後者はコードの管理が複雑になるので、趣味アプリでそこまでやる必要性は感じない。 また、Heroku や Now では、アプリケーション同士は内部ネットワークでやりとりできず、外部ネットワークを通す形になるのでレイテンシーも気になる(計測はしていない)。
上記の理由と Wantedly でも Rails のコンテナに Hypernova を同居させてうまくいっているようなので( ref: Rearchitecting Wantedly's Frontend | Wantedly Engineer Blog )、1コンテナで Rails と Hypernova 両方のサービスを動かすことにした。
Rails の対応
Hypernova に限らず Heroku にデプロイするために必要な対応。
Heroku では静的ファイルの配信をアプリケーションサーバーがおこなう必要があるので、config/environments/production.rb に以下を書く。
config.public_file_server.enabled = true
また、Heroku の制約でログを標準出力に書き出す必要があるので、RAILS_LOG_TO_STDOUT 環境変数を設定する。これは設定ファイルにデフォルトで以下のような記述がある。
if ENV["RAILS_LOG_TO_STDOUT"].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) end
昔は、rails_12factor gem を入れて上記と同じ対応していたのだけど、最近は、そういった gem を入れる必要がなくなったぽい。
Docker の対応
複数のサービスを動かすために Run multiple services in a container | Docker Documentation を参考に supervisor を使うことにした。
以下のように ruby:2.5.1 のイメージをベースに apt-get で supervisor を入れ、必要なディレクトリを掘り、設定ファイルをコピーして、supervisord を起動する。
FROM ruby2.5.1 #... RUN apt-get update && apt-get install -y supervisor # ... RUN mkdir -p /var/log/supervisor COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf # ... CMD ["/usr/bin/supervisord"]
supervisord の設定は以下のようなかんじ。Rails や Hypernova のプロセスの標準入出力を supervisord にリダイレクトするために Dockerで子プロセスからのstdoutをsupervisordにリダイレクトする方法 – 踊る犬.netブログ (旧) を参考にした。
[supervisord] nodaemon=true directory=/usr/src/app [program:rails] command=/bin/bash -c "rails server -b 0.0.0.0" autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:hypernova] command=/bin/bash -c "node hypernova.js" autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0