Heroku上のRails3アプリの延命対策

プライベートユースでHeroku上で運用しているWebアプリ(Rails3.2 + ruby1.9.3)があるのですが

Cedar-14 stack end-of-life window begins 1 May 2019 | Heroku Dev Center

のアナウンスがあり、来年5月からビルドができなくなってしまうとのこと

ならば、アップグレードしておくかと

アップグレードガイド Upgrading to the Latest Stack | Heroku Dev Center に従って

$ heroku stack:set heroku-18
$ git commit --allow-empty -m "Upgrading to heroku-18"
$ git push heroku master

とheroku-18 stackベースでデプロイしてみたところ、buildエラーに...。

remote:  !     An error occurred while installing ruby-1.9.3-p551
remote:  !
remote:  !     Heroku recommends you use the latest supported Ruby version listed here:
remote:  !     https://devcenter.heroku.com/articles/ruby-support#supported-runtimes
remote:  !
remote:  !     For more information on syntax for declaring a Ruby version see:
remote:  !     https://devcenter.heroku.com/articles/ruby-versions

なんと..

こりぁアカン..

どうやらruby-1.9.3は新しいstackでサポートされてないようです..

ということでcontainerでデプロイするように作戦変更しました。

Rails/rubyの段階的アップグレードはとうの昔に放棄)

containerベースへの移行方法

Dockerfileを作ってローカル環境にてdocker上で動くようにできたら、

あとは

$ heroku container:login
$ heroku container:push web   # コンテナイメージのpush
$ heroku container:release web   # pushしたイメージのリリース

です。

既存のCedar-14 stackでのアプリケーションが稼働中であっても問題なく上書き?でデプロイできました。

コードの修正点は

config/database.yml

production:
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>

それ以外としては、

.dockerignore

tmp/pids/server.pid

を追加しておくとよいと思います。

トラブルシューティング

やはりというかいくつか問題が発生したのでその対策です。 もっとスマートな方法はあるはず。。

トラブル1: Boot timeoutエラー

Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch

どうやらアプリケーションがPORTにアクセスできてないようです

Qiitaの記事 DockerでRailsの環境構築してHerokuへデプロイする - Qiita では

CMD ["rails", "server", "-b", "0.0.0.0"]

でサーバー起動していますが同様にしたら上記のエラーになってしまいました

どうやら自分の環境ではWebrickを使っているからのようです。。 (Rails5だとデフォルトサーバーのpumaの設定ファイル内で環境変数PORTにアクセスしているから問題ない)

本来ならばpumaを使うようにするべきだと思いますが、とりあえず次のように修正して解決しました。

CMD bundle exec rails server -b 0.0.0.0 -p $PORT

ただ、

配列形式の

CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0", "-p", "$PORT"]

にすると

2019-07-17T13:43:33.652404+00:00 heroku[web.1]: Starting process with command `bundle exec rails s -p \8224 -b 0.0.0.0

というエラーになりNGでした...

謎。。

トラブル2: assets precompileされていなくアプリケーションエラー

An ActionView::Template::Error occurred in page#index:

  application.css isn't precompiled

が出ます

assets precompileが必要です。(今まではHerokuデプロイ時に自動でやってくれていた)

Dockerfile に以下の行を追加して解決しました

RUN bundle exec rake assets:precompile

Rakefile を ADD/COPY する前だと No Rakefile found (looking for: rakefile, Rakefile, rakefile.rb, Rakefile.rb) が出るので要注意です

トラブル3: コンパイルしたassetsにアクセスできない

ActionController::RoutingError (No route matches [GET] "/assets/application-bf61d1c6485bd814e710bb58a3622bea.css"):

コンパイルされたCSSにアクセスできず、レイアウトが崩れてしまいました

Rails 4+ Asset Pipeline on Heroku | Heroku Dev Center を参考に

Gemfile に

gem 'rails_12factor', group: :production

を追加して解決しました

トラブル4: development環境用にインストールしたgemが悪さをする

development環境用のgemがインストールされていてproduction環境で悪さをしているということがありました

production環境用のgemのみインストールするのは

# RUN bundle install  # を
RUN bundle install --without test development #  に変更

でよいのですがこれだとローカルの開発環境でdockerビルドしたときに開発用のgemがインストールされません

ARGを使って使い分けるようにしました

Dockerfile

ARG bundle_install_opt="--without test development"
RUN bundle install ${bundle_install_opt}

docker-compose.yml

version: '2'

services:
  web:
    build:
      context: .
      args:
        - bundle_install_opt

というようにすると、ローカル環境では docker-compose build とすれば開発用のgemがインストールされたイメージをビルドできます


とりあえず、引き続きメンテナンスできそうで一安心です