--
FuelPHP Advent Calendar 2013 21日目です。@madmamor が担当します。昨日は @Altsencturely さんの「FuelPHPとFluentdの連携」でした。
今日は、PHP製デプロイツール「Rocketeer」を使って、FuelPHPをコマンド一つでデプロイしてみます。デプロイする最中に、PHPUnitやマイグレーションも実行してみます。
Rocketeer公式ドキュメント:
http://rocketeer.autopergamene.eu/
ライセンスファイルへのリンクが切れてしまっていますが、MITライセンスと書かれています。
RocketeerのGitHub:
https://github.com/Anahkiasen/rocketeer
今回の内容は、Mac OSX Mavericks(以下、ローカル)とVagrantで起動しているUbuntu 13.10(以下、リモート)な環境で確認しています。ローカルは普段通りな開発を行う場所で、そこからコマンドを実行して、リモートにデプロイするイメージです。FuelPHPは1.7.1を使いましたが、Composer対応以降のバージョンであれば、あまり関係は無いはずです。
記事内のソースのライセンスについては、Rocketeerが生成するファイルはRocketeerのライセンスに準じます。私が作成したファイルは、ソースにも書きますが、WTFPLライセンスにします。 http://www.wtfpl.net/txt/copying/
1. 下準備(ローカル)
php.iniで以下の設定をします。phar.readonly = Offこれをしないと、後述のrocketeer.pharが自身の内部を更新する関係か、以下の警告が大量に出ました。
failed to open stream: phar error: write operations disabled by the php.ini setting phar.readonly併せて、FuelPHPプロジェクトを作成して、Gitレポジトリへコミットしておいて下さい。このGitレポジトリはリモート側からアクセスできる必要があります。アクセスには、ユーザ名とパスワード、あるいはユーザ名と鍵ファイル(と鍵のパスワード)による認証が使えます。
注意: リモートで鍵の設定時 ~/.ssh/config に以下が無いとエラーになる可能性が有ります。あるいは、一度手動でcloneして、ホストの登録を済ませておきましょう。
StrictHostKeyChecking no尚、この記事を作成するにあたって作成したFuelPHPプロジェクトのサンプルを公開してあります。
https://github.com/mp-php/fuelphp-advent-calendar-2013-rocketeer-sample
2. 下準備(リモート)
git、PHPとmcrypt extension、Composerをインストールしておきます。更に、以下のsymlinkを貼っておきます。このリンク先は、今現在は存在しませんが、それで構いません。$ sudo ln -s /home/vagrant/www/fuel-rocketeer-sample/current/public /var/www/fuel-rocketeer-sample
3. Rocketeerのインストールと設定ファイルの準備
ローカルで、以下をダウンロードして、プロジェクトルートに配置します。ダウンロード方法は何でも構いません。
http://rocketeer.autopergamene.eu/versions/rocketeer.phar
以下のコマンドでコマンド一覧やヘルプが表示できればRocketeerのインストールは完了です。
$ php rocketeer.phar # コマンド一覧 $ php rocketeer.phar -h # ヘルプ次に、設定ファイルを準備します。以下のコマンドを実行して下さい。設問は、とりあえず全て未入力でEnterで良いです。
$ php rocketeer.phar ignite以下のファイルが生成されたはずです。
- rocketeer/config.php ... 主にリモートの接続情報を設定する
- rocketeer/hooks.php ... 主にデプロイ時等のbefore/afterのタスクを設定する(今回は使いません。)
- rocketeer/paths.php ... phpやcomposer等のコマンドのパスを設定する
- rocketeer/remote.php ... リモートのデプロイ先に関する色々な設定をする
- rocketeer/scm.php ... Gitレポジトリの設定をする(SVNも使えるみたいです)
- rocketeer/stages.php ... 同一サーバに複数ステージ(stagingやproduction)がある場合に使う?(今回は使いません。)
注意: rocketeer.pharは自身の内部にキャッシュ的に接続設定を保存するようです。以降の設定が正しく反映されない場合、以下のコマンドを実行してみてください。
$ php rocketeer.phar flushまた、その性質上、rocketeer.pharをパブリックなレポジトリにコミットするのはリスクが有るかもしれません。.gitignoreで除外してしまうのも有りかと思います。
4. リモートの接続情報を設定して確認してみる
rocketeer/config.php を修正します。以下は例なので、適切に書き換えて下さい。(以降、同様です。)'connections' => array( 'production' => array( 'host' => '192.168.33.10', 'username' => 'vagrant', 'password' => '', 'key' => '/Users/mamor/.vagrant.d/insecure_private_key', 'keyphrase' => '', ), ),SSHのポートを22以外にしている場合は"xxx.yyy.com:2222"のように指定してあげればOKです。
早速、正しく設定できたか確認してみましょう。
$ php rocketeer.phar check No repository is set for the repository, please provide one : 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 Your server is ready to deploy Execution time: 0.8238s正しく接続できて、gitコマンド、PHPバージョン、composerコマンド、mcrypt extensionのチェックが行われました。必要なPHPバージョンは、すみません、確認していません。が、Rocketeerのcomposer.jsonには "php": ">=5.3.0" と書かれています。ちなみに手元は5.5です。
5. デプロイの設定をしてデプロイしてみる
rocketeer/remote.php を修正します。
$ git diff rocketeer/remote.php diff --git a/rocketeer/remote.php b/rocketeer/remote.php index a21279b..51424c4 100644 --- a/rocketeer/remote.php +++ b/rocketeer/remote.php @@ -11,12 +11,12 @@ ), // The root directory where your applications will be deployed - 'root_directory' => '/home/www/', + 'root_directory' => '/home/vagrant/www/', // The name of the application to deploy // This will create a folder of the same name in the root directory // configured above, so be careful about the characters used - 'application_name' => '', + 'application_name' => 'fuel-rocketeer-sample', // The number of releases to keep at all times 'keep_releases' => 4, @@ -25,23 +25,24 @@ // 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', + 'fuel/app/cache', + 'fuel/app/logs', + 'fuel/app/tmp', ), 'permissions' => array( // The permissions to CHMOD folders to // Change to null to leave the folders untouched - 'permissions' => 755, + 'permissions' => 777, // 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}', + 'fuel/app/cache', + 'fuel/app/logs', + 'fuel/app/tmp', ), // The web server user and group to CHOWN folders to
"root_directory"の下に"application_name"な名前のディレクトリが作成され、その中にデプロイされます。この例だと "/home/vagrant/www/fuel-rocketeer-sample" になりますね。
"shared"では、デプロイをまたいで共有したいディレクトリやファイルを設定します。大抵の場合、ログディレクトリやキャッシュディレクトリ等、.gitignoreに書かれているものになると思います。裏を返せば、例えばデプロイ毎にキャッシュをクリアしたければ、あえて共有しなければOKです。尚、共有はsymlinkによって実現されます。
注意: ディレクトリを共有する場合、ディレクトリそのものがレポジトリに含まれている必要があります。.gitkeepや、以下のような.gitignoreファイルをそのディレクトリに入れるなどしておいて下さい。
* !.gitignore"permissions"は、指定したディレクトリやファイルを、指定したパーミッションに変更します。今回の例では777を指定していますが、適切な値を設定するようにお願いします。
次に rocketeer/scm.php を修正します。
以上で基本的な設定が済んだので、お待ちかねのデプロイを実行してみましょう。
ブラウザから http://[ドメイン]/fuel-rocketeer-sample/ にアクセスして、おなじみのトップ画面が表示されればデプロイ成功です。
ざっとディレクトリ構造を見てみましょう。
'repository' => 'https://github.com/mp-php/fuelphp-advent-calendar-2013-rocketeer-sample.git',"repository"に、GitのレポジトリURLを設定します。今回の例はGitHub上のレポジトリなので、usernameとpasswordは空のままで構いません。また、ファイル内のコメントにも書かれているように、既に鍵認証の設定がされている場合も、空で構いません。
以上で基本的な設定が済んだので、お待ちかねのデプロイを実行してみましょう。
$ php rocketeer.phar deploy No username is set for the repository, please provide one : No password is set for the repository, please provide one : Cloning repository in "/home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831" Initializing submodules if any Installing Composer dependencies Setting permissions for /home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831/fuel/app/cache Setting permissions for /home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831/fuel/app/logs Setting permissions for /home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831/fuel/app/tmp Sharing file /home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831/fuel/app/cache Sharing file /home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831/fuel/app/logs Sharing file /home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831/fuel/app/tmp Successfully deployed release 20131220204831 No releases to prune from the server Execution time: 61.1617sGitレポジトリのclone(submodulesがあればそれも)が行われ、composer installが行われ、パーミッション変更が行われ、共有が行われました。
ブラウザから http://[ドメイン]/fuel-rocketeer-sample/ にアクセスして、おなじみのトップ画面が表示されればデプロイ成功です。
ざっとディレクトリ構造を見てみましょう。
$ ll /home/vagrant/www/fuel-rocketeer-sample/ total 20 drwxrwxr-x 4 vagrant vagrant 4096 Dec 20 11:49 ./ drwxrwxr-x 3 vagrant vagrant 4096 Dec 20 11:48 ../ lrwxrwxrwx 1 vagrant vagrant 63 Dec 20 11:49 current -> /home/vagrant/www/fuel-rocketeer-sample/releases/20131220204831/ drwxrwxr-x 3 vagrant vagrant 4096 Dec 20 11:48 releases/ drwxrwxr-x 3 vagrant vagrant 4096 Dec 20 11:49 shared/
"current"ディレクトリが、先ほどデプロイしたディレクトリへsymlinkされています。
$ ll /home/vagrant/www/fuel-rocketeer-sample/current/fuel/app/ total 56 drwxrwxr-x 11 vagrant vagrant 4096 Dec 20 11:49 ./ drwxrwxr-x 6 vagrant vagrant 4096 Dec 20 11:49 ../ -rw-rw-r-- 1 vagrant vagrant 718 Dec 20 11:48 bootstrap.php lrwxrwxrwx 1 vagrant vagrant 61 Dec 20 11:49 cache -> /home/vagrant/www/fuel-rocketeer-sample/shared/fuel/app/cache/ drwxrwxr-x 5 vagrant vagrant 4096 Dec 20 11:48 classes/ drwxrwxr-x 6 vagrant vagrant 4096 Dec 20 11:48 config/ drwxrwxr-x 3 vagrant vagrant 4096 Dec 20 11:48 lang/ lrwxrwxrwx 1 vagrant vagrant 60 Dec 20 11:49 logs -> /home/vagrant/www/fuel-rocketeer-sample/shared/fuel/app/logs/ drwxrwxr-x 2 vagrant vagrant 4096 Dec 20 11:48 migrations/ drwxrwxr-x 2 vagrant vagrant 4096 Dec 20 11:48 modules/ drwxrwxr-x 2 vagrant vagrant 4096 Dec 20 11:48 tasks/ drwxrwxr-x 5 vagrant vagrant 4096 Dec 20 11:48 tests/ lrwxrwxrwx 1 vagrant vagrant 59 Dec 20 11:49 tmp -> /home/vagrant/www/fuel-rocketeer-sample/shared/fuel/app/tmp/ drwxrwxr-x 2 vagrant vagrant 4096 Dec 20 11:48 vendor/ drwxrwxr-x 3 vagrant vagrant 4096 Dec 20 11:48 views/
共有設定したディレクトリが、"shared"ディレクトリ下にsymlinkされています。パーミッションも、設定したとおりに変更されています。
以上が、Rocketeerによる基本的なデプロイ方法です。
6. マイグレーションも実行してみる
だいぶ長くなってきましたが、続いてマイグレーションの実行です。簡単なマイグレーションファイルを作成してコミットしておきます。
$ php oil generate migration create_users name:text email:string password:stringリモート側でDBやDBユーザの作成、それに対するFuelPHPのconfigのdb.phpの設定も済ませておいて下さい。
次に、2ファイルを新規作成します。
まず、rocketeer/tasks/Migrate.php を新規作成します。今回はサンプルなので、名前空間はつけていません。尚、"Rocketeer\Traits\Task" を継承しますが、このクラスはabstract classであってトレイトではないようです。
まず、rocketeer/tasks/Migrate.php を新規作成します。今回はサンプルなので、名前空間はつけていません。尚、"Rocketeer\Traits\Task" を継承しますが、このクラスはabstract classであってトレイトではないようです。
<?php /** * Migrate class * * @author Mamoru Otsuka http://madroom-project.blogspot.jp/ * @copyright 2013 Mamoru Otsuka * @license WTFPL License http://www.wtfpl.net/txt/copying/ */ class Migrate extends Rocketeer\Traits\Task { /** * @inheritDoc */ protected $description = 'Migrates the database'; /** * @inheritDoc */ public function execute() { // 実行時にメッセージとして表示されます $this->command->info($this->description); // currentディレクトリ内でコマンドを実行します $output = $this->runForCurrentRelease('php oil r migrate'); // 第一引数は失敗時のメッセージです // 第二引数は失敗時の詳細です // 第三引数は成功時のメッセージです return $this->checkStatus('Migrate failed', $output, 'Migrate successfully'); } }rocketeer/tasks.php を新規作成します。
<?php /** * rocketeer/tasks.php * * @author Mamoru Otsuka http://madroom-project.blogspot.jp/ * @copyright 2013 Mamoru Otsuka * @license WTFPL License http://www.wtfpl.net/txt/copying/ */ // Migrateクラスをカスタムタスクとして登録します // $ php rocketeer.phar migrate で個別に実行できます require_once __DIR__.'/tasks/Migrate.php'; Rocketeer\Facades\Rocketeer::add('Migrate'); // deploy後に自動実行されます // 自動実行したくない場合は書かないで下さい Rocketeer\Facades\Rocketeer::after('deploy', 'Migrate');Gitレポジトリにコミット(Push)したら、デプロイを実行してみます。
$ php rocketeer.phar deploy ... 略 ... Migrates the database Migrate successfully Removing 1 release from the server Execution time: 34.8705s
マイグレーションも実行できました。以下のコマンドでマイグレーションのみを個別に実行することもできます。
$ php rocketeer.phar migrate
注意: deployのafterタスクは、既にsymlinkが貼替えられていることに注意して下さい。尚、マイグレーションを行う場合は、別途、何らかの方法でメンテナンスモードに切り替えるタスクを作成する必要があるかと思います。(もちろん、手作業でも良いですが。)また、後述のPHPUnit失敗時の挙動も気になるところで、マイグレーションを自動化するのはそれなりのリスクが伴いそうです。が、今回はとりあえず自動化して進めます。
after(やbefore)タスクにはクラスの他に、インラインによるコマンド設定や、クロージャの設定もできるみたいです。(まだやったことはありません。)クラスにすると "$this->runForCurrentRelease('コマンド')" のように、便利なメソッドでパス周りの調整が簡単になるので、迷ったらクラスで良いのかなと思います。クラスだと、前述のように個別で実行もできますね。
composer.jsonに以下を追記します。
最後に、必ず失敗するテストを作成して、どうなるかも確認してみます。(ソースは割愛します。)
after(やbefore)タスクにはクラスの他に、インラインによるコマンド設定や、クロージャの設定もできるみたいです。(まだやったことはありません。)クラスにすると "$this->runForCurrentRelease('コマンド')" のように、便利なメソッドでパス周りの調整が簡単になるので、迷ったらクラスで良いのかなと思います。クラスだと、前述のように個別で実行もできますね。
7. PHPUnitも実行してみる
そろそろ最後です。ソースをcloneして、PHPunitを実行して、全てのテストが成功したらデプロイ続行、一つでも失敗したらデプロイ中止(symlinkの貼替えを行わない)できたら良いですね。composer.jsonに以下を追記します。
$ git diff composer.json diff --git a/composer.json b/composer.json index e1b21ea..5ef630e 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,9 @@ "monolog/monolog": "1.5.*", "fuelphp/upload": "2.0.1" }, + "require-dev": { + "phpunit/phpunit": "3.*" + }, "suggest": { "mustache/mustache": "Allow Mustache templating with the Parser package", "smarty/smarty": "Allow Smarty templating with the Parser package",プロジェクト直下にphpunit.xmlを用意します。fuel/core/phpunit.xmlをコピーして、パス周りを整えただけです。
<?xml version="1.0" encoding="UTF-8"?> <phpunit colors="true" stopOnFailure="false" bootstrap="fuel/core/bootstrap_phpunit.php"> <php> <server name="doc_root" value="./"/> <server name="app_path" value="fuel/app"/> <server name="core_path" value="fuel/core"/> <server name="package_path" value="fuel/packages"/> <server name="vendor_path" value="fuel/vendor"/> <server name="FUEL_ENV" value="test"/> </php> <testsuites> <testsuite name="core"> <directory suffix=".php">fuel/core/tests</directory> </testsuite> <testsuite name="packages"> <directory suffix=".php">fuel/packages/*/tests</directory> </testsuite> <testsuite name="app"> <directory suffix=".php">fuel/app/tests</directory> </testsuite> </testsuites> </phpunit>rocketeer/paths.php を修正します。
$ git diff rocketeer/paths.php diff --git a/rocketeer/paths.php b/rocketeer/paths.php index f366b41..2b4d6d4 100644 --- a/rocketeer/paths.php +++ b/rocketeer/paths.php @@ -19,4 +19,6 @@ // Path to the Artisan CLI 'artisan' => '', + // Path to PHPUnit + 'phpunit' => 'fuel/vendor/bin/phpunit', );Rocketeerは /usr/local/bin 等のグローバルな場所のphpunit、あるいはプロジェクト直下の vendor/bin/phpunit は勝手に見つけてくれます。FuelPHPの場合は fuel/vendor/bin/phpunit になるので、この設定が必要です。(この設定がない場合は、対話式でパスの入力が可能ですが。)
-t オプションをつけてデプロイを実行してみます。
$ php rocketeer.phar deploy -t ... 略 ... Running tests... Tests passed successfully ... 略 ... Execution time: 194.1824s
テストが行われました。単体でも実行できます。
$ php rocketeer.phar test ... 略 ... Testing the application Running tests... ... 略 ... [vagrant@192.168.33.11] (production) Time: 9.23 seconds, Memory: 23.25Mb [vagrant@192.168.33.11] (production) OK (361 tests, 413 assertions) Tests passed successfully Execution time: 9.6588s
注意: テストの実行をafterタスクで行うこともできますが、その時には既にsymlinkが貼替わってしまっています。-tオプションを使うようにしましょう。
最後に、必ず失敗するテストを作成して、どうなるかも確認してみます。(ソースは割愛します。)
$ php rocketeer.phar deploy -t No username is set for the repository, please provide one : No password is set for the repository, please provide one : Cloning repository in "/home/vagrant/www/fuel-rocketeer-sample/releases/20131220215555" Initializing submodules if any Installing Composer dependencies Running tests... Tests failed PHPUnit 3.8-g5fb30aa by Sebastian Bergmann. Configuration read from /home/vagrant/www/fuel-rocketeer-sample/releases/20131220215555/phpunit.xml The Xdebug extension is not loaded. No code coverage will be generated. ............................................................... 63 / 362 ( 17%) ............................................................... 126 / 362 ( 34%) ............................................................... 189 / 362 ( 52%) ............................................................... 252 / 362 ( 69%) ............................................................... 315 / 362 ( 87%) ..............................................F Time: 8.6 seconds, Memory: 23.25Mb There was 1 failure: 1) Test_Example::test_fail /home/vagrant/www/fuel-rocketeer-sample/releases/20131220215555/fuel/app/tests/example.php:14 FAILURES! Tests: 362, Assertions: 413, Failures: 1. Tests failed Rolling back to release 20131220215158 Migrates the database Migrate successfully Execution time: 196.3031s
デプロイが中断されました。symlinkは以前のままです。中断されたデプロイのディレクトリはゴミとして残りますが、rocketeer/remote.phpの"keep_releases"により、そのうち掃除されると思いますので、あまり気にしなくても良いかなと思います。マイグレーションが実行されてしまうのは想定外だったので、この点は今後の課題にします。。。
8. まとめ
(全ての機能を把握できているわけではありませんし、公式ドキュメントに記載されているプラグイン機能も気になるところですが)Rocketeerを使って、FuelPHPをコマンド一つで、PHPUnitやマイグレーションの実行を含めてデプロイできました。
デプロイツールはRuby製のCapistranoが有名ですが、RocketeerはPHP製ということもあり、ComposerやPHPUnitの扱いを標準でサポートしてくれていて助かります。今日現在、Rocketeerの使い方に関する日本語の情報はかなり少ない(というか無いかもしれません。あったらすみません。)ので、今後、盛り上がってくれると良いなーと思います。
chefとvagrantのおかげで、こういったサーバが絡む実験もやりやすくなったので、ぜひ試してみてください。
デプロイツールはRuby製のCapistranoが有名ですが、RocketeerはPHP製ということもあり、ComposerやPHPUnitの扱いを標準でサポートしてくれていて助かります。今日現在、Rocketeerの使い方に関する日本語の情報はかなり少ない(というか無いかもしれません。あったらすみません。)ので、今後、盛り上がってくれると良いなーと思います。
chefとvagrantのおかげで、こういったサーバが絡む実験もやりやすくなったので、ぜひ試してみてください。
以上です。お疲れ様でした。
22日目は @egmc さんの「FuelPHPがOpAuth対応になったのでfacebookログインをしてみる」です。
No comments:
Post a Comment