C# + Herokuで heroku_san を使って、環境変数・アドオンの追加とFluentMigratorの実行を行う

前回、HerokuにNancyアプリをデプロイしましたが、各種設定はコマンドラインから1つずつ行いました。

ただ、やり方を忘れそうな気がしたためツールを探してみたところ、Rubyのgemで heroku_san がありました。
fastestforward/heroku_san · GitHub

そこで、RailsSinatraで使っている記事はあったものの、他の環境ではどんなふうに使うのだろうと試してみることにしました。

 

環境

  • Windows7 x64
  • Ruby 2.1.5
  • gem
    • heroku_san 4.3.2
    • albacore 2.3.15
  • NuGet
    • FluentMigrator 1.4.0.0
    • FluentMigrator.Tools 1.4.0.0
    • Npgsql 2.2.3
  • Heroku addon
    • Heroku Postgres
  • Heroku Toolbelt 3.23.1

 

C#アプリの作成

今回はDBのマイグレーションだけができれば良いので、Nancyではなくコンソールアプリケーションを作ります。

作業内容は以下の通りです。

  • Npgsqlパッケージの追加
  • NuGetパッケージの復元を有効化
  • 以下のファイルをリンクとして追加し、プロパティの出力を「常に出力」へと変更
    • FluentMigrator.Runner.dll
    • Migrate.exe
  • FluentMigratorのマイグレーションファイルを作成

 
作成が終わったら、ひとまずGitにコミットしておきます。

 

Gemのインストール

heroku_sanは開発環境で使用するgemであることに注意して、Gemfileを用意します。

source 'https://rubygems.org'
ruby '2.1.5'

group :development do
  gem 'heroku_san'
end

gem 'albacore'

 
あとはbundle install --path vendor/bundleでインストールします。

 

heroku.ymlを用意

heroku:create_configを実行するためのRakefileを用意

READMEに従ってbundle exec rake heroku:create_configを実行してもエラーになります。

$ bundle exec rake heroku:create_config
rake aborted!
No Rakefile found (looking for: rakefile, Rakefile, rakefile.rb, Rakefile.rb)

 
そのため、Sinatraと同じようにRakefileを用意することになります。READMEのRakefileを見ると、

HerokuSan.project = HerokuSan::Project.new(config_file, :deploy => HerokuSan::Deploy::Sinatra)

とあり、Sinatraではないアプリの場合はdeployに何を指定すれば良いのか分かりませんでした。

そこで、コードを読んだところ、heroku_san/sinatra.rb at master · fastestforward/heroku_san · GitHub にある通り、Sinatraを指定してもスーパークラスメソッドを呼んでるだけということが分かりました。

そのため、今回はスーパークラスであるHerokuSan::Deploy::Baseを指定し、以下のようなRakefileを作成しました。

require "bundler/setup"
begin
  require "heroku_san"
  config_file = File.join(File.expand_path(File.dirname(__FILE__)), 'config', 'heroku.yml')
  HerokuSan.project = HerokuSan::Project.new(config_file, deploy: HerokuSan::Deploy::Base)
  load "heroku_san/tasks.rb"
rescue LoadError
  # The gem shouldn't be installed in a production environment
end

 

heroku.ymlを作成・編集

準備ができたので、再度、bundle exec rake heroku:create_configを実行しますが、エラーになります。

$ bundle exec rake heroku:create_config
rake aborted!
Errno::ENOENT: No such file or directory @ rb_sysopen - path/to/project/config/heroku.yml
...
Tasks: TOP => heroku:create_config

 
ディレクトリがないため、ディレクトリを作成後、再度実行します。

$ mkdir config

$ bundle exec rake heroku:create_config
Copied example config to "path/to/project/config/heroku.yml"
Please edit "path/to/project/config/heroku.yml" with your application's settings.

 
無事にできたので、heroku.ymlファイルを編集します。

今回はHerokuにRubyとMonoの環境のための環境変数BUILDPACK_URLと、アドオンのHeroku Postgresの設定を記述します。なお、アプリ名はherokusan-fm-201501としました。

production:
  app: herokusan-fm-201501
  stack: cedar
  config:
    BUILDPACK_URL: "https://github.com/heroku/heroku-buildpack-multi"
  addons:
    - heroku-postgresql:hobby-dev

 

.gitignoreへの追記

heroku.ymlファイルは開発環境でしか使わないため、.gitignoreに記載しておきます。

 

Herokuアプリを作成

Herokuにログイン
$ heroku login
Enter your Heroku credentials.
...
Authentication successful.

これ以降は、herokuコマンドとheroku_san、どちらでも作成できます。

 

herokuコマンドの場合

アプリの作成と、リモートの設定をしてくれます。

$ heroku create herokusan-fm-201501

$ git remote
heroku

 

heroku_sanを使う場合

アプリの作成とリモートの追加を行います。リモートの追加を忘れるとエラーになるので注意します。

$ bundle exec rake all heroku:create
production: Created herokusan-fm-201501

$ git remote

$ bundle exec rake all heroku:remotes
git remote add production git@heroku.com:herokusan-fm-201501.git

$ git remote
production

 
なお、この段階では環境変数やアドオンなどは追加されていません。

$ heroku config --app herokusan-fm-201501
herokusan-fm-201501 has no config vars.

$ heroku addons --app herokusan-fm-201501
herokusan-fm-201501 has no add-ons.

 

デプロイ前に環境変数やアドオンを追加

以下のコマンドで環境変数やアドオンを追加できますが、コマンドの実行し忘れが発生しそうです。

$ bundle exec rake all heroku:config    
$ bundle exec rake all heroku:addons

参考: Easily deploy to multiple environments on Heroku with heroku_san | Adventures In Coding

 
そのため、なにかよい方法を探してみたところ、Wikiafter_deployの例が載っていました。
Updating a REVISION environment variable · fastestforward/heroku_san Wiki · GitHub

 
同じようにしてbefore_deployで追加作業ができるのではないかと考え、ソースコードを見たところ、HerokuSan::Stageにいくつか便利そうなメソッドがありました。
heroku_san/stage.rb at a36789b7f66fd3d234097714c534a762b4a2aa89 · fastestforward/heroku_san · GitHub

 
それを使って、before_deployのtaskをRakefileへ追記しました。

task :before_deploy do
  each_heroku_app do |stage|
    # push_configでは、以下の値を環境変数に設定
    # ・引数なしは`heroku.yml`の内容、
    # ・引数ありは引数で指定した値
    stage.push_config
    stage.push_config(CONFIG_BY_RAKEFILE: :heroku_san_rakefile) # 例なので、無くても良い

    # `heroku.yml`のアドオンを追加
    stage.install_addons
  end
end

 

デプロイ後にFluentMigratorを実行する

Rakefileの追記

デプロイ後にFluentMigratorを忘れずに実行したいため、同様にして、after_deployのtaskをRakefileに追記します。

task :after_deploy do
  each_heroku_app do |stage|
    # albacoreによるFluentMigratorの実行
    stage.run "rake", "db:migrate"
  end
end

 

FluentMigratorを実行するRakefileの用意

以前の記事で使用したRakefileを流用し、exeファイル名などを変更します。

FluentMigrator.rakeという名前にて、path/to/project/rakelib ディレクトリの中に保存します。

Rakeでは、rakelibディレクトリにRakefileを置いておけば、自動的にインポートするようです。
library rake - Ruby 2.1.0 リファレンスマニュアル

 

.buildpacksファイルの追加

RubyとMono用のbuildpackのURLを書いた.buildpacksを用意します。

https://github.com/friism/heroku-buildpack-mono.git
https://github.com/heroku/heroku-buildpack-ruby.git

 
ここまででデプロイする準備ができたので、Gitにコミットします。

 

デプロイ

bundle exec rake production deploy を実行してデプロイし、FluentMigratorの実行を確認します。

$ bundle exec rake production deploy

...
git update-ref refs/heroku_san/deploy HEAD^{commit}
...
=====> Detected Framework: .NET
...
=====> Detected Framework: Ruby
...
Running `rake db:migrate` attached to terminal... up, run.365
...
[+] Task completed.

 
アドオンなども追加されています。

$ heroku addons
=== herokusan-fm-201501 Configured Add-ons
heroku-postgresql:hobby-dev  HEROKU_POSTGRESQL_ORANGE
scheduler:standard

$ heroku config
=== herokusan-fm-201501 Config Vars
BUILDPACK_URL:                https://github.com/heroku/heroku-buildpack-multi
CONFIG_BY_HEROKU_YML:         heroku_yml
CONFIG_BY_RAKEFILE:           heroku_san_rakefile
...

 

ソースコード

GitHubに上げてあります。heroku.ymlは、heroku.example.ymlになっているため、名前を変更して使います。
thinkAmi-sandbox/heroku_san-FluentMigrator-sample · GitHub

 

参考