Laravel5.1のプロジェクトをDeployerでデプロイする

Deployerについて勉強したので備忘録の意味も込めてまとめてみます。

「Laravelのプロジェクトを〜」というタイトルですが、Laravelに限った内容ではありませんので、Deployerを使って何かしらをデプロイしたい人の参考になればと思います。



#Deployerとは
Deployerとは、PHP製のデプロイツールです。
(デプロイツールといえば他にRuby製のCapistranoやPython製のFabricなどがありますね。)



#デプロイの流れ



##基本方針
- GitHubに置いてあるLaravel5.1のプロジェクトをデプロイする
- Deployer v3.3.0
- デプロイ元: OS X El Capitan
- デプロイ先: Ubuntu 14.04 (デプロイ元で立ち上げた仮想環境)



##Deployerをインストール
[こちら](http://deployer.org/)の公式ページからダウンロードすることができます。
ダウンロードした`deployer.phar`はプロジェクト内に置くなり、`/usr/local/bin/`に置くなりすれば良いです。

私は公式ページを参考にして、以下のようにしました。

```bash
$ mv deployer.phar /usr/local/bin/dep
$ chmod +x /usr/local/bin/dep
```



##デプロイするプロジェクトをGitHubに上げる
今回は`laravel-test-project`というプロジェクトをデプロイします。



##レシピをアレンジする
Deployerには既に`recipe/laravel.php`が組み込まれていますが、これだけだと不十分なところがあるのでアレンジしていきます。

```php:deploy/deploy.php
<?php

require 'recipe/laravel.php';

// デフォルトがUTCなので上書き
env('timezone', 'Asia/Tokyo');

// デプロイ先のサーバ情報を定義
serverList('config/server.yml');

// デプロイしたプロジェクトを直近5件保存しておく (デフォルトは3件)
// -> 保存しておいた分だけrollbackコマンドを使用できる
set('keep_releases', 5);

// デプロイするリポジトリのURL
set('repository', 'https://github.com/purple-jwl/laravel-test-project.git');

// shared_dirsを上書き (deploy:sharedで使用)
// -> 対象ディレクトリがなければ作ってくれる
set('shared_dirs', [
    'storage/app',
    'storage/framework/cache',
    'storage/framework/sessions',
    'storage/framework/views',
    'storage/logs',
]);

// shared_filesを上書き (deploy:sharedで使用)
// -> 対象ファイルがなければ空ファイルを作ってくれる
// -> sqliteを使う場合、ここで設定しておくと良さそう(?)
set('shared_files', [
    '.env',
    // 'database/database.sqlite',
]);

// writable_dirsを上書き (deploy:writableで使用)
// -> デプロイ先の環境によってパーミッションの変更方法が変わる
set('writable_dirs', [
    'bootstrap/cache',
    'storage/app',
    'storage/framework/cache',
    'storage/framework/sessions',
    'storage/framework/views',
    'storage/logs',
]);
```

```yaml:deploy/config/server.yml
Vagrant:
    host: ip_address
    user: vagrant
    password: some_string
    stage: test
    deploy_path: /home/vagrant/laravel-test-project
```

Deployerに組み込まれている`recipe/laravel.php`を利用しつつ、一部上書きしています。また、デプロイ先のサーバ情報を定義しています。

これらの設定をバージョン管理し、GitHubなどで公開する場合、サーバ情報は別ファイルに切り分けしておき、サーバ情報はバージョン管理しないようにするなどしておいたほうが良いでしょう。

例えば、私の場合は以下のようなディレクトリ構成にして`server.yml`はGitの管理対象から外し、そのテンプレートとして`server.yml.example`を置いています。

```bash
$ tree deploy
deploy
├── config
│   ├── .gitignore
│   ├── server.yml
│   └── server.yml.example
└── deploy.php
```




##コマンドを叩いてデプロイ
以下のようなコマンドを打って少し待てばデプロイ完了です。

```bash
# dep [task] [stage]
$ dep deploy test
```

`-vvv`オプションをつけるとコマンド実行時のログを確認することができます。デプロイが失敗する場合などに試してみると良いです。

```bash
$ dep deploy test -vvv
```

また、以下のようなコマンドを利用すればデプロイ前の状態に戻すことが出来ます。

```bash
$ dep rollback test
```

ちなみにデプロイ先のディレクトリはこのようになっています。releasesディレクトリ下にデプロイしたプロジェクトがkeep_releases分だけ保存されます。デプロイした日時がディレクトリ名になるのでtimezoneは上書きしておいたほうが良いです。

```bash
$ tree -L 2 laravel-test-project                                                         
laravel-test-project
|-- current -> /home/vagrant/laravel-test-project/releases/20160919163940
|-- releases
|   |-- 20160918140820
|   `-- 20160919163940
`-- shared
    `-- storage
```



#悩みどころとその解決
Laravelのプロジェクトをデプロイするにあたり、どうしようかなーと考えたり悩んだことを書いておきます。他にも悩む方がいるかもしれないので参考になればと思います。（初回デプロイ時に関することばかりです）



##envファイル
初回デプロイ時のenvファイル設置をどうしようか悩みました。初回のみということで今回はrsyncで設置することにしました。

ちなみに初回デプロイでは、

- `composer install`で`post-root-package-install`によりenvファイルが生成される
- envファイルがshared_filesのenvファイルとリンクされるが、sharedディレクトリ以下にはenvファイルが存在せず、空のファイルが生成され、それがリンクされる
- 空のenvファイルのまま、`artisan:config:cache`タスクが走り、`bootstrap/cache/config.php`が生成される

ので、初回デプロイし、rsync等でenvファイルを設置した後に`bootstrap/cache/config.php`を消さないといけません。



##shared_dirsとwritable_dirs
sharedディレクトリのリンクとディレクトリ生成について悩みました。

`recipe/laravel.php`ではデフォルトで以下のような設定がされていますが、私は`deploy/deployer.php`のように上書きしています。

```php:recipe/laravel.php
...

// Laravel shared dirs
set('shared_dirs', ['storage']);

...

// Laravel writable dirs
set('writable_dirs', ['bootstrap/cache', 'storage']);

...
```

```php:deploy/deployer.php
...

// shared_dirsを上書き (deploy:sharedで使用)
// -> 対象ディレクトリがなければ作ってくれる
set('shared_dirs', [
    'storage/app',
    'storage/framework/cache',
    'storage/framework/sessions',
    'storage/framework/views',
    'storage/logs',
]);

// writable_dirsを上書き (deploy:writableで使用)
// -> デプロイ先の環境によってパーミッションの変更方法が変わる
set('writable_dirs', [
    'bootstrap/cache',
    'storage/app',
    'storage/framework/cache',
    'storage/framework/sessions',
    'storage/framework/views',
    'storage/logs',
]);

...
```

storageディレクトリのみの指定だと、それ以下のディレクトリが生成されません。このように書くことで初回デプロイ時に上記の対象ディレクトリをsharedディレクトリ下に作ってくれるメリットがあります。

今回はこのような上書きする方法にしましたが、sharedディレクトリ下にディレクトリ生成をするのは初回のみなので、デプロイ先サーバに潜って自分で作るなり、タスクを作っても良いと思います。

ちなみに上書きする方法で1点注意すべきことがあります。deployer側でディレクトリ生成に影響があるのはshared_dirsなのでwritable_dirsは上書きする必要がなさそうに見えます。しかしデプロイ先のサーバの環境によってはwritable_dirsを利用する`deploy:writable`タスクで`setfacl`コマンドが使われるため、writable_dirsも上書きしておかないとパーミッション変更がうまく行われません。




##cron設定
初回デプロイ時のcron設定をどうするか悩みました。

Laravelでcron設定をする場合、複数ジョブを設定する場合でもcron設定ファイルに追加するのは以下の1行のみです。

```
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1
```

そして実際のジョブ設定はLaravelプロジェクト内の`app/Console/Kernel.php`で行われます。

他フレームワークの場合は実行するジョブ設定を更新する度にcron設定ファイルをいじる必要がありますが、Laravelの場合はcron設定自体は初回デプロイ時のみ行えばよいことになります。

Deployerでcron設定をするタスクを追加するのもありでしたが、初回のみならタスクにする程でもないと思い、直接デプロイ先サーバに潜ってcron設定を追記しました。



#まとめ
このように少し工夫しなければいけない部分もありますが、Deployerを使えば簡単にデプロイすることができます。それに加え、便利なレシピがデフォルトで備わっていることも強みだと思いますので、皆さんぜひ使ってみてはいかがでしょうか。

レシピのアレンジをしたいと思う方はDeployerのレシピをまず読んでみるのが良いと思います。複雑なことはしていないのでPHPが分かる人なら誰でも読めると思います。

間違っている点やご意見などありましたら、報告していただけるとありがたいです。