HerokuでBambooスタックからCedarスタックへアプリケーションを移行する方法

Heroku DevCenterの[Migrating to the Celadon Cedar Stack](https://devcenter.heroku.com/articles/cedar-migration)の超訳です。（訳の意味が全然違っているものになっていたら教えて下さいー）

## はじめに
CedarスタックはHerokuのデフォルトランタイムスタックであり、Bambooスタックの後継です。Cedarスタックでは多言語、柔軟なプロセスタイプ、HTTP 1.1をサポートし、コードの自動注入が大幅に少なくなっています。BambooスタックからCedarスタックへ自動的に移行する手段はありませんが、この記事では手動で移行する際に必要な手順と考慮事項の概要を説明します。

移行中2つのHerokuアプリケーションがそれぞれのスタックで存在することになります。移行ではDBデータとHerokuの設定をBambooスタックのアプリからCedarスタックのアプリへコピーし、ルーティングをCedarスタックのアプリに切り替えるといったことをします。

### 注意
スタックの移行といったアプリケーションへの大きな変更は、最初は常にステージング環境で実施する必要があります。そこで、移行プロセスと新しい環境でのテストを実施する一時的なHerokuアプリケーションを作成することを強くお勧めします。本番環境に影響を与えることなく、新しいスタックで稼働させるために必要な変更を加えることができるためです。あなたのコードがちゃんと動作するようになったら、本番環境に必要な変更を反映（Push）し、移行を実施することができます。

## Gitのトピックブランチを作成する

Cedarスタックへの移行の際に施した変更は、適切に管理するために `cedar` トピックブランチに分離して保存しましょう。

```
$ git checkout -b cedar
Switched to a new branch 'cedar'
```

## Ruby1.9.2との互換性を確保する

CedarスタックではRuby1.9.2を使用しますが、Bambooスタックでは1.8.7、1.9.1、1.9.2を利用することができました。Cedarスタックへ本番環境をアップグレードする前に、Ruby1.9.2で動作することを確認して下さい。Rubyのバージョン変化に伴う文法の変更や、[1.9.2でのエンコーディング問題](http://www.samanage.com/blog/2011/09/tales-from-upgrading-to-ruby-1-9-2-character-encoding/)を解決して下さい。

アプリケーションが `bamboo-mri-1.9.2` で動作していない場合は、まずこのスタックへ移行することが最初のステップになります。BambooスタックのままRuby1.9.2へ移行しましょう。

```
$ heroku stack:migrate bamboo-mri-1.9.2
-----> Preparing to migrate bamboo-app
       bamboo-ree-1.8.7 -> bamboo-mri-1.9.2
...
-----> Migration prepared.
   Run 'git push heroku master' to execute migration.

$ git push heroku master
...
-----> Heroku receiving push
-----> Migrating from bamboo-ree-1.8.7 to bamboo-mri-1.9.2
...
-----> Migration complete, your app is now running on bamboo-mri-1.9.2
```

Ruby1.9.2で完全に動作するようアプリケーションをテストしましょう。

## Specify dependencies

### アプリケーションサーバを選択する
Bambooスタックでは全てのアプリケーションが[Thin](http://code.macournoyer.com/thin/)で動いていました。依然としてこのアプリケーションサーバの利用を推奨していますが、強制で設定されることはありません。アプリケーションサーバを設定しましょう。Thinを使う場合はGemfileに以下の行を追加します：

```ruby:Gemfile
gem 'thin'
```

#### 訳注
後で出てきますがアプリケーションサーバとしてThinを使用するためにProcfileも設定する必要があります。

### Postgres
Cedarスタックでは自動的に `pg` Gemが設定されないため、Postgresを利用するアプリケーションはGemfileで設定する必要があります。

```ruby:Gemfile
gem 'pg'
```

データベースの設定情報（Credential）はSlugコンパイル時に自動設定されます。config/database.ymlにDATABASE_URLを自動的に設定します。

### New Relic
Bambooスタックでは `config/newrelic.yml` ファイルがNew Relicのプラグインにより自動作成されていましたが、[Cedarスタックでは作成されません](https://devcenter.heroku.com/articles/newrelic#cedar)。

もしBambooスタックでNew Relicを利用しているなら、手動で `newrelic_rpm` Gemを `Gemfile` に追加します。

```ruby:Gemfile
gem 'newrelic_rpm'
```

そして `config/newrelic.yml` をNew Relicのテンプレートから作成します。

```
$ curl https://raw.github.com/gist/2253296/newrelic.yml > config/newrelic.yml
```

### Sendgrid

Cedarスタックでは[Sendgridアドオン](https://devcenter.heroku.com/articles/sendgrid#usage)の設定も自動的に構成されなくなります。RailsアプリケーションがSendgridでメール配信する設定になっているなら、以下のメール初期化設定を `config/initializers/mail.rb` に設定する必要があります。

```
$ curl https://raw.github.com/gist/1690653/mail.rb > config/initializers/mail.rb
```

### HTTP caching plugin
caches_page_via_httpプラグインはVarnishに透過的なキャッシングを提供するためにBambooスタックに自動的にインストールされます。VarnishはCedarスタックのデフォルトではないため、このプラグインは自動注入されなくなります。

ほとんどのCedarアプリケーションではこのプラグインは必要ありませんが、必要な場合は手動でインストールすることができます。

```
$ script/plugin install https://github.com/pedro/caches_page_via_http.git
```

### Commit dependencies

Cedarスタックへのデプロイのために、この時点までに行われた変更をGemの依存関係の変更を含めコミットします。

Bundlerを実行して新しいGemをインストールします。

```
$ bundle install
Fetching source index for http://rubygems.org/
Using rake (0.8.7) 
...
```

Gitに新しいファイルをステージします。

```
$ git add config/newrelic.yml
```

変更をコミットします（カレントのブランチは `ceadr` トピックブランチです）

```
$ git commit -a -m "Modified application dependencies for Heroku/Cedar compatability"
```

## Procfileを作成する

[Procfile](https://devcenter.heroku.com/articles/procfile)はHerokuアプリケーション上でどのようなプロセスを動かすべきか定義している、Cedarスタックで新たに設定するファイルです。

Bambooスタックでバックグラウンドワーカープロセスを使用していないアプリケーションは、シングルWebプロセスタイプで、アプリケーションのルートに新しく `Procfile` を作成します。

```ruby:Procfile
web: bundle exec thin start -p $PORT -e $RACK_ENV
```

バックグラウンドワーカープロセスを使用している場合は `worker` プロセスを `Procfile` に設定します。

```ruby:Procfile
web: bundle exec thin start -p $PORT -e $RACK_ENV
worker: bundle exec rake jobs:work
```

（webプロセス以外のプロセスについてはカスタムラベルをつけることができます。）

ProcfileはHeroku固有のマニフェストではありません。ローカルでの開発中にも[Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) Gemを利用してアプリケーションのプロセス編成を調整するために使用することができます。

```
$ gem install foreman
Fetching: foreman-0.38.0.gem (100%)
Successfully installed foreman-0.38.0
```

プロジェクトディレクトリの`.env`ファイルに環境変数を設定しておくと、Foremanで実行した際に実行時の環境変数に含まれるようになります。`RACK_ENV`をdevelopmentにするよう設定してみましょう。あくまでローカルで使用するため、`.env`はコミットしないようにしましょう。（.gitignoreに含めておきます）

```
$ echo "RACK_ENV=development" >>.env
```

`.env`に設定した環境変数、`Procfile`のプロセス設定、そしてForemanを利用し、ローカルでアプリケーションを実行することができます。

```
$ foreman start
10:01:59 web.1      | started with pid 3484
10:01:59 worker.1   | started with pid 3485
```

Foremanを利用してローカルでアプリケーションが動作したら、`Procfile`をトピックブランチにコミットしましょう。

```
$ git add Procfile
$ git commit -a -m "Added Procfile to define app's process-formation on Heroku/Cedar"
```

## Cedarアプリケーションを作成する
BambooからCedarに自動的に移行する手段はないため、新しいアプリケーションはCedarスタック上に作成される必要があります。リモートのGitリポジトリを`heroku-cedar`といった名前にしておくと、アプリケーションがBambooバージョンなのかCedarバージョンなのか区別がつきやすくなります。

```
$ heroku create --remote heroku-cedar cedar-app
Creating cedar-app... done, stack is cedar
http://cedar-app.herokuapp.com/ | git@heroku.com:cedar-app.git
Git remote heroku-cedar added
```

## デプロイ
変更したコードベースをCedarアプリケーションにデプロイしても、現在Bamboo上で動作しているアプリケーションに影響を与えることはありません。アプリケーションを単にステージングして機能検証を行う機会を得ることができます。

`cedar`トピックブランチから、`heroku-cedar`リモートリポジトリの`master`ブランチに、Cedar互換のソースをデプロイのためPushしましょう。

```
$ git push heroku-cedar cedar:master
Counting objects: 67, done.
...
-----> Heroku receiving push
-----> Rails app detected
...
```

## アドオンを再構成する

アドオンをどこかのアプリケーションから他のアプリケーションへ移動する方法が現在サポートされていません。全てのアドオンはBambooアプリケーションから手動でCedarアプリケーションに構成される必要があります。

現在Bambooアプリケーションに割り当てられている全てのアドオンのリストを`addons.txt`ファイルに保存します。

```
$ heroku addons --app bamboo-app > addons.txt
$ more addons.txt
memcache:5mb
newrelic:standard
pgbackups:auto-month
shared-database:5mb
heroku-postgres:ronin
```

HerokuのPostgresデータベース（heroku-postgresql:XXX）を持つアプリケーションは、この方法でアドオンDBを再作成するべきではないため、`addons.txt`から削除します。

```
$ more addons.txt
memcache:5mb
newrelic:standard
pgbackups:auto-month
shared-database:5mb
```

`xargs`ユーティリティでCedarアプリケーションにアドオンを構成します。

```
$ cat addons.txt | tr '\n' '\0' | xargs heroku addons:add --app cedar-app
-----> Adding memcache:5mb to cedar-app
...
```

Bambooアプリケーションに存在するアドオンのグレードによっては、予期せずして不必要な費用が発生するかも知れないことを留意して下さい。

## 設定変数をコピーする

アプリケーションに設定されている変数も同じく自動的に移行することはできないため、手動でコピーする必要があります。

設定変数をBambooアプリケーションから`config.txt`ファイルに保存します。

```
$ heroku config -s --app bamboo-app > config.txt
$ more config.txt 
DATABASE_URL=postgres://u:p@host/db
MEMCACHE_PASSWORD=pass
MEMCACHE_SERVERS=mcX.ec2.northscale.net
MEMCACHE_USERNAME=pp123%40heroku.com
RACK_ENV=production
PATH=vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:/bin
SESSION_SECRET=secret
SHARED_DATABASE_URL=postgres://u:p@host/db
```

手動で設定されている変数のみ保持する必要があります。アドオンの設定や、`MEMCACHE_`、`DATABASE_URL`といったHerokuの設定を`config.txt`を開いて削除して下さい。

データベースの設定やアドオンの設定を上書きしてしまうと、予期せぬ影響が発生する可能性があるため、このような設定を確認して存在していたら`config.txt`から削除しておきましょう。

```
$ more config.txt
RACK_ENV=production
SESSION_SECRET=secret
```

これらアプリケーション固有の設定をCedarアプリケーションに追加しましょう。

```
$ cat config.txt | tr '\n' ' ' | xargs heroku config:add --app cedar-app 
Adding config vars and restarting app... done, v32
  RACK_ENV            => production
  SESSION_SECRET      => secret
```

もし何かヤバいことが起こったら、`heroku release:rollback`で素早く元に戻すことができます。

## Cedarアプリケーションに息を吹き込む

この段階でBambooアプリケーションと同一の構成である、Cedarで実行中のアプリケーションのコピーがあるはずです。移行への最後のステップでは、CedarアプリケーションにBambooアプリケーションからデータを転送し、ライブトラフィックを受け取れるようにCedarアプリケーションを有効化します。

転送中に何らかのデータ変更が加えられてしまわないよう、データの整合性を確保するため、両方のアプリケーションをメンテナンスモードにします。

```
$ heroku maintenance:on --app bamboo-app
Maintenance mode enabled.
$ heroku maintenance:on --app cedar-app
Maintenance mode enabled.
```

### Postgres

HerokuのPostgresデータベースプランを利用するアプリケーションは、最小限のダウンタイムを達成するために「Fast database changeover strategy」を使用する必要があります。これらの手順はShared Databaseに格納されているデータを使用するアプリケーションのためのものです。

--

[Heroku PG Backupsアドオン](http://addons.heroku.com/pgbackups)はアプリケーション間の素早いデータ移行を実現します（[詳しい情報はこちらを参照して下さい](https://devcenter.heroku.com/articles/pgbackups#transfers)）。それぞれのアプリケーションにこのアドオンを追加します（無料で使用できます）。

```
$ heroku addons:add pgbackups --app bamboo-app
Adding pgbackups to bamboo-app... done
$ heroku addons:add pgbackups --app cedar-app
Adding pgbackups to cedar-app... done
```

Bambooアプリケーションのデータをバックアップします。

```
$ heroku pgbackups:capture --app bamboo-app
SHARED_DATABASE (DATABASE_URL)  ----backup--->  b040
Capturing... done
Storing... done
```

新しいCedarアプリケーションにバックアップをインポートします。

```
$ heroku pgbackups:restore DATABASE `heroku pgbackups:url --app bamboo-app` --app cedar-app
SHARED_DATABASE (DATABASE_URL)  <---restore---  b040.dump
...
Retrieving... done
Restoring... done
```

### MongoDB, Xeround等のDB系アドオンを使用している場合

それぞれのアドオンのドキュメントを見てね！

### カスタムドメイン

カスタムドメインからルーティングされるトラフィックは引き続きBambooアプリケーションを指しています。カスタムドメインが有効になっている場合は、Cedarアプリケーションに追加する前に、Bambooアプリケーションから削除する必要があります。

Bambooアプリケーションからカスタムドメインのリストを取得して`domains.txt`に保存し、カスタムドメインを削除します。

```
$ heroku domains --app bamboo-app | grep -v "Domain names" > domains.txt
$ more domains.txt
secure.mydomain.com
www.mydomain.com
$ heroku domains:clear --app bamboo-app
Removed all domain names for bamboo-app
```

Cedarアプリケーションにカスタムドメインを追加します。

```
$ cat domains.txt | xargs heroku domains:add --app cedar-app
```

### SSL

カスタムドメインと同じように、SSLサポートはBambooアプリケーションからCedarアプリケーションに転送される必要があり、アプリケーションのDNS設定の更新を伴います。[様々なSSL製品がBambooスタックで提供されているため](http://devcenter.heroku.com/articles/ssl)詳細はそれぞれのドキュメントを参照して下さい。

### メンテナンスモードを解除する

アクセスを受け付けるためCedarアプリケーションのメンテナンスモードを解除します。また、適切な数にdyno数をスケールさせます（Bambooアプリケーションのレベルと合わせると良いでしょう）。

```
$ heroku dynos --app bamboo-app
bamboo-app is running 5 dynos and 2 workers
$ heroku ps:scale web=5 worker=2 --app cedar-app
Scaling web processes... done, now running 5
Scaling worker processes... done, now running 2
$ heroku maintenance:off --app cedar-app
Maintenance mode disabled.
```

#### 訳注
スケール数は各々で調整して下さい！　このまま実行すると合計7dyno動いちゃいますよ！

## 最後に
Cedarアプリケーションが動き、稼働状況も特に問題なさそうだと判断したら`master`ブランチに`cedar`ブランチをマージしましょう。

```
$ git checkout master
$ git merge cedar
```

Bambooアプリケーションはコスト削減のために退役させましょう。1dynoにスケールダウンさせ、アドオンも有料のものから無料のものへと切り替えましょう。並行稼動の期間中に問題が発生したら、Bambooアプリケーションにロールバックさせることもできます。

## 免責事項
（一応。。）この訳文を参考にオペレーションを行った場合にもし何らかの損害が発生したとしても責任は負いかねますので、各自の判断でご使用下さい。