PHPのためのCapistrano風デプロイツール「Rocketeer」でLaravelをデプロイする
そろそろrsyncでデプロイするのは卒業したいな、ということでRocketeerというデプロイツールを導入してみました。
RocketeerはPHP製のCapistrano風デプロイツールです。PHP製なだけあってはじめからComposerやPHPUnitをサポートしてるし、当然だけど設定ファイルや新しいタスクもPHPで記述できるしでとても使いやすいです。
Rocketeer自体はフレームワークに依存しないデプロイツールではありますが、Laravelのパッケージとしてインストールすると、artisanからデプロイできたり、データベースのマイグレーションやシーディングなんかもできるようになるので、Laravelアプリケーションのデプロイには特に便利に使えます。
ただ、新興のツールであるからか、日本語での具体的な導入手順について解説している情報があまりありません。素晴らしいツールでありながら導入に障壁があるのももったいないので、このエントリではRocketeerでLaravelで作ったアプリケーションをデプロイする方法を紹介したいと思います。
Rocketeerの概要
RocketeerはSSHでデプロイ先のリモートホストに接続し、タスクとして定義されたコマンド群を実行することでデプロイを行います。ソースコードはリモートホスト上でgitもしくはsvnを使って取得し、ライブラリはcomposerでインストールします。今のところローカルからファイルをコピーしてデプロイする機能はサポートされていないようです。
つまりRcoketeerを導入するには
の3つの前提をクリアしている必要があります。
次にデプロイしたアプリケーションのリモートホスト上でのディレクトリ構造について説明します。
Rocketeerの特徴の一つは、単にアプリケーションをデプロイするだけでなく、過去のリリースにロールバックする機能を持っていることでしょう。そのため、リモートホストでのディレクトリ構造は少々独特です。
リモートホストでの典型的なディレクトリ構造は次のようになります。
/var/www/rocketeer-example/ ├── current -> /var/www/rocketeer-example/releases/20140116170238 ├── releases │ ├── 20140115152810 │ ├── 20140115173018 │ ├── 20140115174248 │ └── 20140116170238 │ ├── app │ │ └── storage │ │ ├── logs -> /var/www/rocketeer-example/shared/app/storage/logs │ │ └── sessions -> /var/www/rocketeer-example/shared/app/storage/sessions │ └── public └── shared └── app └── storage ├── logs └── sessions
Rcoketeerはデプロイ先として指定されたパスにアプリケーション名のディレクトリを作成します。この場合は/var/www
がデプロイ先のパスで、アプリケーション名はrocketeer-example
です。
さらに/var/www/rocketeer-example/
には3つのディレクトリが作成されます。
1つ目はcurrent
です。ここにはアプリケーションの最新のリリースが設置されます。Webサーバはcurrent/public
を公開するように設定します。
2つ目はreleases
で、新しいものから4件(デフォルト値)のリリースが保存されます。current
は実際にはreleases
に保存さているリリースへのシンボリックリンクとなっており、current
のリンク先を変更することでデプロイをロールバックすることができるようになっています。
3つ目はshared
です。このディレクトリにはリリース間で共有する必要のあるファイルが置かれるディレクトリです。各リリースのディレクトリにあるログファイルなどはshared
にあるものにリンクされます。
Capistranoを使ったことがある人にはお馴染みでしょうが、シンボリックリンクを使ってリリースを切り替えるというのは目から鱗で面白いですね。
インストール
composerでanahkiasen/rocketeer
パッケージをインストールします。
$ composer require anahkiasen/rocketeer:dev-master ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) - Installing anahkiasen/rocketeer (dev-master 3591b74) Cloning 3591b74208e632ce5ffe090ffcd19330785feb77 anahkiasen/rocketeer suggests installing anahkiasen/rocketeer-campfire (Campfire plugin to create deployments notifications) Writing lock file Generating autoload files Generating optimized class loader
app/config/app.php
のproviders
配列に次の行を追加。
'Rocketeer\RocketeerServiceProvider',
app/config/app.php
のaliases
配列に次の行を追加。
'Rocketeer' => 'Rocketeer\Facades\Rocketeer',
deploy:
で始まるコマンド群が追加されます。
$ ./artisan deploy deploy:check Check if the server is ready to receive the application deploy:cleanup Clean up old releases from the server. deploy:current Display what the current release is deploy:deploy Deploy the website. deploy:flush Flushes Rocketeer's cache of credentials deploy:ignite Creates Rocketeer's configuration deploy:rollback Rollback to the previous release, or to a specific one deploy:setup Set up the remote server for deployment deploy:teardown Remove the remote applications and existing caches deploy:test Run the tests on the server and displays the output deploy:update Update the remote server without doing a new release.
Laravel4.0の場合はremote
パッケージを別途導入する必要があります。4.0へのインストール方法は公式サイトで解説されていますので参照ください。
設定
具体的な設定を行っていく前に設定に必要な情報を確認しておきましょう。
デプロイ先のリモートホストついては次のように想定しています。
- デプロイ先のパスは
/var/www
/var/www
のユーザとグループはwww-data
/var/www
はセットグループIDされている- デプロイタスクは作業用ユーザ(
hogehoge
)で実行する - 作業用ユーザの補助グループを
www-data
にして/var/www
にアクセスできるようにしてある git
とcomposer
は予めインストール済み(デプロイタスクで使われる)
/var/www
はセットグループIDされているので、作業用ユーザによってデプロイ時に作成されたファイルのグループはwww-data
になります。www-data:www-data
で動作しているWebサーバは、グループの権限を通じてファイルにアクセスできるという仕組みです。
アプリの名前はrocketeer-example
で、Githubのパブリックなリポジトリ(https://github.com/hogehoge/rocketeer-example.git
)で公開されているとします。
それでは具体的な設定を行っていきます。
まずはapp/config/remote.php
にリモートホストの接続情報を設定します。
artisan tail
が使えるようにroot
には/var/www/rocketeer-example/current
を指定しておきましょう。
'connections' => array( 'production' => array( 'host' => '203.0.113.1', 'username' => 'hogehoge', 'password' => '', 'key' => '/Users/hogehoge/.ssh/id_rsa', 'keyphrase' => '', 'root' => '/var/www/rocketeer-example/current', ), ),
次にRocketeerの設定ファイルをpublishします。 アプリケーションのリポジトリと名前について聞かれるので入力します。
./artisan deploy:ignite No repository is set for the repository, please provide one :https://github.com/hogehoge/rocketeer-example.git Configuration published for package: anahkiasen/rocketeer What is your application's name ?rocketeer-example The Rocketeer configuration was created at anahkiasen/rocketeer Execution time: 9.3387s
app/config/packages/anahkiasen/rocketeer/
以下に設定ファイルが生成されます。
各設定ファイルには詳細なコメントがあるので、参考にしながら設定していきましょう。
app/config/packages/anahkiasen/rocketeer/ ├── config.php ├── hooks.php ├── paths.php ├── remote.php ├── scm.php └── stages.php
デプロイ先のディレクトリパスを指定します。
app/config/packages/anahkiasen/rocketeer/remote.php
// The root directory where your applications will be deployed 'root_directory' => '/var/www/',
リリース間で共有されるべきディレクトリとファイルを指定します。SQLiteをプロダクションで使っているのでなければデフォルトで大丈夫だと思います。
app/config/packages/anahkiasen/rocketeer/remote.php
// A list of folders/file to be shared between releases // Use this to list folders that need to keep their state, like // user uploaded data, file-based databases, etc. 'shared' => array( '{path.storage}/logs', '{path.storage}/sessions', ),
Webサーバが書き込みするファイルやディレクトのパーミッションを変更するようにします(chmod -R755 %s
だけでもいいですが、特に実害もないのでなんとなくデフォルトのまま他の2つのコマンドも残してあります)。アプリによってはapp/storage
だけ書き込めるようになっていれば十分で、app/database/production.sqlite
とpublic
は外してしまってもいいかもしれません。アプリの実装によって調整しましょう。
app/config/packages/anahkiasen/rocketeer/remote.php
'permissions' => array( // The folders and files to set as web writable // You can pass paths in brackets, so {path.public} will return // the correct path to the public folder 'files' => array( 'app/database/production.sqlite', '{path.storage}', '{path.public}', ), // Here you can configure what actions will be executed to set // permissions on the folder above. The Closure can return // a single command as a string or an array of commands 'callback' => function ($task, $file) { return array( sprintf('chmod -R 775 %s', $file), sprintf('chmod -R g+s %s', $file), sprintf('chown -R www-data:www-data %s', $file), ); },
パブリックなリポジトリを使うのでリポジトリのユーザ名とパスワードは空にしておきます。プライベートなリポジトリで認証が必要な場合はここでユーザ名とパスワードを指定します。
app/config/packages/anahkiasen/rocketeer/scm.php
// The repository credentials : you can leave those empty // if you're using SSH or if your repository is public // In other cases you can leave this empty too, and you will // be prompted for the credentials on deploy 'username' => '', 'password' => '',
設定は以上です。
設定が完了したら./artisan deploy:check
を実行して、リモートホストがデプロイ可能な状態かチェックしておきます。
$ ./artisan deploy:check No username is set for the repository, please provide one : No password is set for the repository, please provide one : Checking presence of git Checking PHP version Checking presence of Composer Checking presence of mcrypt extension Checking presence of mysql extension The mysql extension does not seem to be loaded on the server Execution time: 2.2685s
レポジトリにアクセスするためのユーザ名とパスを聞かれますが、パブリックなリポジトリを使っているので無視してEnterでOKです。
PHPのconfigureオプションの関係で、mysql extension
がないと怒られてますが実害はないので無視しています(app/config/database.php
で設定されているdatabase.default
の値と同名のextensionが存在するかチェックするように実装されているのですが、これは本来はdriverを見て対応するextension名を決めるように実装したほうがいいと思う)。
デプロイ
deploy:deploy
コマンドでデプロイします。省略してdeploy
だけでもデプロイできます。
$ ./artisan deploy:deploy No username is set for the repository, please provide one : No password is set for the repository, please provide one : Server is not ready, running Setup task Checking presence of git Checking PHP version Checking presence of Composer Checking presence of mcrypt extension Checking presence of mysql extension The mysql extension does not seem to be loaded on the server Cloning repository in "/var/www/rocketeer-example/releases/20140114191141" Initializing submodules if any Installing Composer dependencies Setting permissions for /var/www/rocketeer-example/releases/20140114191141/app/database/production.sqlite Setting permissions for /var/www/rocketeer-example/releases/20140114191141/app/storage Setting permissions for /var/www/rocketeer-example/releases/20140114191141/public Sharing file /var/www/rocketeer-example/releases/20140114191141/app/storage/logs Sharing file /var/www/rocketeer-example/releases/20140114191141/app/storage/sessions Successfully deployed release 20140114191141 No releases to prune from the server Execution time: 111.9915s
/var/www/rocketeer-example
ディレクトリが作成され、最新のリリースへのリンクが/var/www/rocketeer-example/current
に作成されます。Webサーバは/var/www/rocketeer-example/current/public
を公開するように設定すればOKです。
デプロイタスクの流れとしては
- 初回デプロイ時など必要なディレクトリが作成されてない場合はセットアップタスクを実行
- リポジトリをclone
composer install
--tests (-t)
オプションが指定されていればphpunitを実行しテストが失敗したらデプロイを中止config.php
の設定に従いパーミッションを変更--migrate (-m)
オプションが指定されていればartisan migrate
を実行(--seed
と併用された場合はartisan migrate --seed
)--seed (-s)
オプションが指定されていればartisan db:seed
を実行- リリース間で共有されるフォルダにリンクを張る
current
のリンク先を更新
となっています。
一般的なLaravelを使ったアプリケーションのデプロイとして必要なことはひと通りよしなにやってくれます。便利ですね。
ロールバック
deploy:rollback
コマンドでcurrent
のリンク先を変更してデプロイをロールバックできます。
一つ前のリリースに戻す。
$ ./artisan deploy:rollback Rolling back to release 20140114195555 Execution time: 2.4191s
ロールバック可能なリリースのリストを表示し、番号でロールバック先を選択。
$ ./artisan deploy:rollback --list Here are the available releases : [0] 2014-01-14 19:57:28 [1] 2014-01-14 19:55:55 [2] 2014-01-14 19:53:59 [3] 2014-01-14 19:11:41 Which one do you want to go back to ? (0) Rolling back to release 20140114195728 Execution time: 95.3531s
バグが見つかったときも、すぐに以前のリリースに戻すことができるので安心です。
そのほかのコマンド
deploy:current
current
からリンクされているリリースを表示します。
./artisan deploy:current The current release is 20140114191141 (b3f46005e0ec4b1e202a113c5fa31875ef772826 deployed at 2014-01-14 19:11:41) Execution time: 1.6177s
deploy:update
current
からリンクされているリリースでgit pull
とcomposer install
を実行します。
$ ./artisan deploy:update Pulling changes Sharing file /var/www/rocketeer-example/releases/20140115174248/app/storage/logs Sharing file /var/www/rocketeer-example/releases/20140115174248/app/storage/sessions Installing Composer dependencies Setting permissions for /var/www/rocketeer-example/releases/20140115174248/app/database/production.sqlite Setting permissions for /var/www/rocketeer-example/releases/20140115174248/app/storage Setting permissions for /var/www/rocketeer-example/releases/20140115174248/public Successfully updated application Execution time: 8.2524s
deploy:cleanup
保存件数(デフォルトは4件)を超えた古いリリースをリモートホストから削除します。
$ ./artisan deploy:clean Removing 1 release from the server Execution time: 1.8961s
--clean-all
オプションを使えば、current
からリンクされている以外のリリースをすべて削除することもできます。
$ ./artisan deploy:clean --clean-all Removing 3 releases from the server Execution time: 2.7766s
古いリリースはdeploy:deploy
が削除してくれるので、明示的にdeploy:clean
を実行する機会はあまりないとは思います。使いどころとしては、保存件数を減らした時とか、deploy:deploy
を中断してゴミが残ったときなどでしょうか。
deploy:teardown
リモートホストからアプリを削除します。/var/www/rocketeer-example
が削除されます。
$ ./artisan deploy:teardown This will remove all folders on the server, not just releases. Do you want to proceed ? The application was successfully removed from the remote servers Execution time: 3.9923s
deploy:flush
認証情報のキャッシュ(app/storage/meta
あたりに保存されている)を削除します。設定の変更が反映されないときは取り敢えずこのコマンドを叩いてみる感じです。
$ ./artisan deploy:flush Rocketeer's cache has been properly flushed
deploy:setup
デプロイ前にリモートホストにディレクトリを作成するのに使用します。明示的にこのコマンドを実行しなくても、deploy:deploy
コマンドが初回デプロイ時によしなにやってくれるので、直接使うことはあまりなさそうです。
deploy:test
リポジトリにSSHで接続する場合
HTTPSじゃなくてSSHでリポジトリにアクセスすることもできます。その場合は.ssh/config
を駆使して予めリモートホストの作業用ユーザでgit clone
出来るように設定しておきましょう。.ssh/known_hosts
にリポジトリをホストしているサーバの公開鍵がないと、デプロイ時にエラーになるので、予めコマンドラインでgit clone
を実行するなりしておくのも忘れずに。自分はこれでハマりました。
リモートホストの接続情報を変更するときの注意点
app/config/remote.php
の設定を変更するだけではダメです。
artisan deploy:ignite
を実行したときに、app/config/remote.php
を元にしてapp/config/packages/anahkiasen/rocketeer/config.php
に接続情報が設定されるのですが、Rocketeerはconfig.php
に接続情報があればremote.php
より優先して使うので、接続情報を変更する場合は、remote.php
だけではなくconfig.php
も変更する必要があります。接続情報はキャッシュされているので、設定を変更したあとはartisan deploy:flush
で接続情報のキャッシュをフラッシュしましょう。
もしくは、同じ内容の設定が2つのファイルにあるのが気持ち悪いのであれば、config.php
から接続情報を削除し、常にremote.php
を使うようにしてし
まってもいいかもしれません。
実行されるコマンドを確認する
各コマンドに-p
オプションを指定すると、リモートホストで実行されるコマンドを確認できます。これらのコマンドは実際に実行されるわけではありません。どのようなコマンドが実行されるのか不安なときはこれで確認を。-v|vv|vvv
オプションでも色々見れます。
以上、RocketterでLaravelアプリケーションをデプロイする方法について簡単に紹介しました。ステージング環境用に設定を切り替えたり、複数台のサーバへの一括デプロイしたりといった本格的に運用する上で必要なことについて補足エントリを書きましたので、よろしければそちらも参照ください。