はじめに
Symfony2 で作ったアプリを初めて Heroku にデプロイしたんですが、意外と Web に情報が少なくてちょいちょい困ったので、実際に行った手順をまとめておきます。
Symfony2 のアプリはローカルで動いてて、あとは適切にデプロイしたいだけ、という前提のお話です。(Symfony のバージョンは 2.6 です)
BEAR.Sunday アプリのお話も こちら にありますので、よろしければご覧ください。
Heroku の環境準備
まずは Heroku 自体を使える状態になりましょう。
1. アカウントを作成
何はともあれ Heroku の アカウントを作成 します。
2. heroku-toolbelt をインストール
heroku
コマンドを使えるようにするために、heroku-toolbelt
というツールをインストールします。
Web からダウンロード してインストールしてもよいですし、brew-cask
を使っている場合は以下のようにコマンドでもインストールできます。
$ brew cask install heroku-toolbelt
Heroku 上にアプリを作成
次に、Heroku 上にアプリを作成します。
Web UI から作成 してもよいですし、コマンドでも作成できます。
$ cd {Symfony2 プロジェクトのルートディレクトリ} # heroku コマンドは基本的にここで使用します
$ heroku login
Enter your Heroku credentials.
Email: {メールアドレス}
Password (typing will be hidden): {パスワード}
Authentication successful.
$ heroku create {付けたいアプリ名} # アプリの公開 URL が https://{付けたいアプリ名}.herokuapp.com になります
heroku create
でアプリを作成した場合は、ローカルの Git リポジトリに heroku
というリモートリポジトリが自動で追加されます。
これが追加されている状態だと、heroku
コマンド実行時に --app {アプリ名}
の指定を省略できます。
Web UI からアプリを作成した場合は、
$ heroku git:remote -a {アプリ名}
を実行してリモートリポジトリを追加しておきましょう。
Heroku 上でビルド・実行できるように小細工
あとはソースコード一式をリモートリポジトリ heroku
に push すればデプロイできるのですが、Symfony2 プロジェクトを Heroku 上で正常に動作させるためにはいくつか小細工が必要です。
順番に片付けていきましょう。
1. SYMFONY_ENV 環境変数を prod にする
Heroku に PHP アプリをデプロイすると、自動的に composer install --no-dev
が実行されるため、require-dev
で依存しているライブラリはインストールされません。(参考)
そのため、SYMFONY_ENV
が設定されていない状態(つまりデフォルトで dev
となる状態)でビルドしようとすると、以下のようなエラーで失敗します。
PHP Fatal error: Class 'Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle' not found in /tmp/build_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/app/AppKernel.php on line 33
Script Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache handling the post-install-cmd event terminated with an exception
[RuntimeException]
An error occurred when executing the "'cache:clear --no-warmup'" command.
これを回避するには、Heroku の環境で SYMFONY_ENV
環境変数の値を prod
に設定しておけばよいです。
Web UI (https://dashboard.heroku.com/apps/{アプリ名}/settings) から設定してもよいですし、コマンドでも設定できます。
$ heroku config:set SYMFONY_ENV=prod
2. プロジェクトローカルな node_modules を使うようにする
LESS を使っている場合は、Heroku 上にも less
コマンドがインストールされている必要があります。
もしローカル環境で global な node_modules
を使って動かしている場合は、Heroku 上でも使えるようにプロジェクトローカルな node_modules
を使う設定にしておく必要があります。
config.yml の修正
assetic:
filters:
less:
node_paths:
+ - "%kernel.root_dir%/../node_modules"
- "/usr/lib/node_modules"
packages.json の作成
プロジェクトローカルな node_modules
に less
コマンドをインストールできるように、packages.json
を作成します。
(packages.json
は、composer.json
の npm 版みたいなものです)
プロジェクトのルートディレクトリに packages.json
を作成して、以下のような内容にします。
{
"repository": {
"private": true
},
"dependencies": {
"less": "~1.7"
}
}
.gitignore の修正
この状態で
$ npm install
を実行すると、node_mondules
配下にパッケージがインストールされます。
この node_modules
は Git で管理したくないので、.gitignore
に追加しておきましょう。
3. PHP 用と Node.js 用の両方の Heroku 環境を使えるようにする
Heroku では基本的に、プロジェクト内に特定のファイルがあるかどうかによって自動で環境が決定されます。(PHP の場合は index.php
があるかどうかで判別されるようです)
この環境のことを Buildpack と呼びます。
Symfony2 のプロジェクトを普通にデプロイすると、index.php
を見つけて PHP 用の Buildpack が自動で適用されます。
しかし、この Buildpack には node の環境が入っていないため、npm install
が実行できません。
これでは LESS のコンパイルができないので、PHP 用の Buildpack と Node.js 用の Buildpack(npm install
が実行される)を両方適用させる必要があります。
具体的には、以下の 2 つを実施すればよいです。
- heroku-buildpack-multi を使うよう設定
- プロジェクトルートに
.buildpacks
というファイルを作成し、使いたい Buildpack を記載
heroku-buildpack-multi を使う
以下のコマンドで heroku-buildpack-multi を使うように設定することができます。
$ heroku buildpack:set https://github.com/heroku/heroku-buildpack-multi
このコマンドが実際に行うのは、
BUILDPACK_URL
環境変数の値に Buildpack のリポジトリの URL を設定するというだけなので、Web UI から行っても問題ありません。
.buildpacks を作成
プロジェクトルートに、以下の内容で .buildpacks
ファイルを作成します。
https://github.com/heroku/heroku-buildpack-nodejs
https://github.com/heroku/heroku-buildpack-php
順番を逆にすると、
composer install
→npm install
の順で実行されるようになってしまい、LESS のコンパイル時に/usr/bin/node: not found
というエラーになってしまうので注意が必要です。
4. デプロイ後に assetic:dump させる
多くの場合、prod
環境ではデプロイ後に assetic:dump
コマンドを実行する必要があると思います。
Heroku ではこのようなデプロイ時に実行させたいスクリプトを composer.json で指定します。
{
"scripts": {
"compile": [
"php app/console assetic:dump"
]
}
}
普通に
post-install-cmd
に追加してもいいのですが、それだとdev
環境でインストールしたときにも走ってしまってローカルでの開発の邪魔になります。compile
に書いておけば Heroku でしか実行されないので安心です。
起動スクリプトを用意
さて、小細工も済んだので、あとはプロジェクトルートに Heroku 用の起動スクリプトを設置すれば準備完了です。
プロジェクトルートに Procfile というファイルを設置して、以下のような内容にします。
web: bin/heroku-php-apache2 web/
もし
composer.json
のbin-dir
の設定がbin
でない場合は、適宜読み替えてください。例えば
bin-dir
を特に設定していない場合は、デフォルトでvendor/bin
になるのでweb: vendor/bin/heroku-php-apache2 web/
とすればよいです。
デプロイしてみる
いよいよデプロイしてみましょう。
$ git push heroku master
特にエラーなく終了したら、
$ heroku open
とすればブラウザでアプリのページが開きます。ちゃんと動いていたらバンザイしましょう。
おまけ:データベースを設定
データベースを使う方法についても最後に説明しておきます。今回は MySQL を使うケースを例に取ります。
アドオンを追加
Heroku では、アドオン を追加することで機能を拡張することができます。
MySQL のアドオンは
- https://addons.heroku.com/cleardb
- https://addons.heroku.com/jawsdb
の 2 つがあるようですが、今回は JawsDB の方を使ってみようと思います。
アドオンの追加方法は簡単で、このページ に記載があるとおり
$ heroku addons:add jawsdb
とするだけです。
完了すると
Please allow 10-15 minutes for your new database to be provisioned. Your config var will be updated automatically when it is finished.
というメッセージが出るので、言われたとおりしばらく待ちましょう。
無料のアドオンであっても クレジットカード情報を登録 しておかないと追加できないみたいなので要注意です。
parameters.yml にデータベース情報を反映させる
データベースが出来上がるのを待つ間に、Symfony2 からデータベースに接続するための準備を進めましょう。
デプロイ時に、parameters.yml
の内容が環境変数から設定されるようにします。
詳しくは [Symfony2] 環境毎に app/config/parameters.yml を自動的生成 を参照してください。
まずは composer.json
に以下を追記します。
{
"extra": {
"incenteev-parameters": {
"file": "app/config/parameters.yml",
"env-map": {
"database_host": "APP_DATABASE_HOST",
"database_port": "APP_DATABASE_PORT",
"database_name": "APP_DATABASE_NAME",
"database_user": "APP_DATABASE_USER",
"database_password": "APP_DATABASE_PASSWORD"
}
}
}
}
あとは
APP_DATABASE_HOST
APP_DATABASE_PORT
APP_DATABASE_NAME
APP_DATABASE_USER
APP_DATABASE_PASSWORD
これらの環境変数に実際の値をセットすれば準備は完了です。
以下のコマンドでデータベース情報を確認してください。
$ heroku config | grep JAWSDB
JAWSDB_URL: mysql://uuuuuuuuuuuuuuuu:pppppppppppppppp@hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh.amazonaws.com:3306/heroku_app_db
もし出力結果が
JAWSDB_URL: mysql://This:Text@WillAutomatically.UpdateOnce.DatabaseIsReady:1234/heroku_app_db
こんな感じだったら、まだデータベースのプロビジョニング中なので、もう少し待ちましょう。
この URL は、
mysql://{ユーザ名}:{パスワード}@{ホスト名}:{ポート番号}/{データベース名}
という構造になっています。それぞれの値を抜き出して、以下のように環境変数を設定しましょう。
$ heroku config:set APP_DATABASE_HOST=hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh.amazonaws.com
$ heroku config:set APP_DATABASE_PORT=3306
$ heroku config:set APP_DATABASE_NAME=heroku_app_db
$ heroku config:set APP_DATABASE_USER=uuuuuuuuuuuuuuuu
$ heroku config:set APP_DATABASE_PASSWORD=pppppppppppppppp
デプロイ後にデータベースのスキーマを更新させる
このままだとデータベースはあるけどテーブルは全くない状態なので、デプロイ後に一度だけ
$ heroku run bash
> php app/console doctrine:schema:create
ってやってもいいんですが、スキーマの変更が自動で反映されるようにしたければ、composer.json
に以下を追記してからデプロイしてもよいです。
{
"scripts": {
"compile": [
"php app/console assetic:dump"
+ "php app/console doctrine:schema:update --force"
]
}
}
ちゃんとマイグレーションしたいとかプロジェクトによって色々あると思うので、今回はたまたまこうしました、というお話です。
おわりに
思ったより長文になってしまいましたが、Symfony2 のアプリを Heroku にデプロイするための手順が一通りご紹介できたかなと思います。
ちなみに今回実際に作ったアプリは これ です。社内でちょっとした多数決とかをとりたいときに使える超簡易なアンケートツールみたいなのが欲しかったので作りました。(まだ未完成ですが、とりあえず動くだけ動きます)
ローカルで動いている状態から Heroku に対応させるために行った変更は このコミット にまとまっているので、よろしければ参考にしてみてください。