HerokuのCedar-14からHeroku-18へのupgrade

# Ceder-14は2020年5月1日でEOL Window for Cedar-14が終了します。

HerokuからメールでCedar-14終了までのプランについて通知が来ました。
Ceder-14上のアプリは2020年5月1日以降も運用はできますが、更新やセキュリティパッチを受けられなくなります。
結構Ceder-14で使っているものがあって重い腰を上げてCeder-18へのUpgradeを試してみました。

> May 3, 2018: Heroku announces deprecation of Cedar-14 for April 2019.
May 1, 2019: EOL window for Cedar-14 begins. Apps on Cedar-14 will continue to run, build, and receive security updates. Apps and builds running on later stacks will not be affected.
May 1, 2020: EOL window for Cedar-14 ends. Apps on Cedar-14 will continue to run, but will no longer build or receive security updates. Apps running on later stacks will not be affected.

実は以前heroku-18を試したことがあったのですが、躓いてしまいすぐに戻した経緯があります。

# 変換前アプリの環境

Herokuで立ち上げているのはRailsアプリで、次のバージョンを使用しています。

| |バージョン|
|:--|:--|
|Rails|4.0.x, 4.1.x, etc...|
|Ruby|2.2x, 2.3.x, etc...|


# 手順

## RubyとRailsのバージョンアップ

heroku-18にする場合Rubyのバージョンを上げる必要があります。
Herokuの現時点のデフォルトが2.5.3ということで、GemfileにRubyバージョンとして2.5.3を指定します。
またRailsは本来5.xに上げるのがベストと思いますが、時間的にあまり変更する余裕がないので4.2.8にします。
(4.2.8に上げないとstack level too deep (SystemStackError)が出ます)

Gemfile

```
gem 'rails', '4.2.8'

ruby "2.5.3"
```

rbenvを使っている場合は```rbenv local 2.5.3```でバージョンを切り替えておきましょう。

## bundle updateで関連するバージョンにアップデート

bundle updateで使用しているgemを関連するバージョンにアップデートします。

```
$ bundle update
```

## sqliteとpgのバージョンを指定

```rails s```で起動するとsqlite3が見つからないと言われます。

```
$ rails s

Specified 'sqlite3' for database adapter, but the gem is not loaded. Add `gem 'sqlite3'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord).
```

Heroku上ではpostgresを使用しますが、ローカルではsqliteを使用していました。
どうもこのsqliteが古いバージョンを指定しないといけない様で```~> 1.3.6```指定します。

また、herokuに展開した時もpgで同様にエラーが出るので、ここで古いバージョンの```~> 0.19.0```を指定します。

Gemfile

```
group :development, :test do
  gem 'sqlite3', '~> 1.3.6'
end
group :production do
  gem 'pg', '~> 0.19.0'
end
```

ここまでで、手元で正常に起動することが確認できました。

## Herokuへの展開

いきなり本番環境で試してうまくいかなかった時は面倒なことになります。
pipelineを使ってStaging環境で試してからにします。

### 既存のアプリのコピー作成

ここでは itosoft アプリということで進めていきます。
```heroku fork```コマンドでコピーを作成します。
staging用のアプリを itosoft-stg としてコピーします。

```
$ heroku fork --from itosoft --to itosoft-stg
```

ただし、forkはdeprecate扱いで```HEROKU FORK IS UNMAINTAINED AND MAY NO LONGER FUNCTION.```という警告が出ます。
[Review Apps](https://devcenter.heroku.com/articles/github-integration-review-apps)を推奨していますが、コードはGithub上にないとだめなようなので警告はでますがforkで作成しました。


### パイプラインの作成

HerokuのDashboardから対象のアプリ itosoft を選択します。
右上のMoreメニューからAdd to pipeline...を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8941/776206c1-f389-634c-0bfb-8d42399749bd.png)

開いた画面で次の様にします。

- プルダウンメニューから + Create new pipeline を選択します。
- Name the pipelineにpipelineの名称を入力します。  
  アプリ名と同じで問題ないと思います。
- Choose a stage to add this app to でproductionを選択します。
- Create pipelineボタンを押して作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8941/77714127-2997-dd45-1a69-8b7eb91609f0.png)

表示された画面で、STAGINGのAdd app...ボタンを押して、forkで作成したitosoft-stg横のAddボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8941/0fae0c70-ab09-3980-8265-3e0aece5a677.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8941/371a7e44-3d3c-5d58-c13e-a95d208e2aaf.png)

### stagingのStackをheroku-18にUpgradeします。

stagingアプリを選択し、Settingsタブをクリックします。

Upgrade Stackボタンを押してUpgradeします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8941/f8f6426f-eb74-4907-42a1-eca472d47a2b.png)

### stagingのremote repository登録

git の remote repository設定にstagingアプリのURLを登録します。
先ほどのSettingsにgitのURLが表示されていますので、それを使い以下のコマンドを実行します。

```
 git remote add staging https://git.heroku.com/itosoft-stg.git
```

### stagingにdeploy

stagingにpushしdeployします。

```
$ git push staging master:master
```

stagingアプリで正常に動作しているか確認します。
問題なければproductionにdeployします。

### productionにdeploy

productionへのdeployはpipelineの画面でPromote to production...ボタンを押してdeployします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8941/935e37b4-36c2-d8e7-1314-730e34672aac.png)

この手順では実際にheroku-18になるのは次のpush時になります。
次に何か手を入れた時に自動的に変わるので問題ないのですが、すぐに切り替えたい場合はstating同様にUpgrade Stackボタンで先にheroku-18にUpgradeしておいた方が良いと思います。


# 謝辞

Upgradeするにあたって以下のサイトを参考にしました。
ありがとうございます。

[Ruby 2.4 and Rails 4 stack level too deep (SystemStackError) - Stack Overflow](https://stackoverflow.com/questions/41504106/ruby-2-4-and-rails-4-stack-level-too-deep-systemstackerror)
[rails　Herokuでrails db:migrate時に突然エラー発生！！　postgresqlバージョン問題　 - Qiita](https://qiita.com/Hijiri-K/items/51d53c0512a2ef455da6)

# 追記 (2020/2/23)

その後、別のプロジェクトでconfig.eager_loadがセットされていなというエラーが出てconfig/application.rbに設定を追加しました。

```
class Application < Rails::Application
  .
  .
  config.eager_load = true
end
```

もう一つsprocketsがセキュリティアラートで2.12.5にしないといけないとありGemfileのバージョンを変更しました。

```
gem 'sprockets', '2.12.5'
```