新年明けましておめでとうございます、永井です。
本年も「カルテットコミュニケーションズ技術ブログ」共々頑張っていきたいと思いますので、宜しくお願い致します。

はじめに

カルテット社内におけるデプロイツールのデファクトスタンダードは、Capistranoです。
機能的には特に不満はないのですが、たまに手の込んだことをやろうとすると途端に躓いてしまった経験が何度かあり、出来ればアプリケーションで利用しているプログラミング言語で良いツールがないかなと思っていました。
そこで今回はDeployerを試してみました。

今回のゴール

  • シンプルなPHPのプロジェクト(Silexベース)をDeployerでデプロイする
  • CircleCIを利用して、 特定ブランチが更新された時に自動的にデプロイする

Deployerについて

deployer

DeployerはPHP製のとてもシンプルなデプロイツールです。
公式サイトを見る限り、

  • ロールバック対応
  • 並列処理対応
  • 独自の処理を拡張可能

などなど、デプロイツールに求められるような機能は一通り揃っているように思えます。

デプロイする為のSilexプロジェクトを作成

今回はSilexのプロジェクトをデプロイしてみたいと思います。
deployer-sampleというプロジェクトを作成します。

$ composer create-project fabpot/silex-skeleton deployer-sample "~2.0"

ディレクトリ構成はこんな感じです。

$ tree -L 1
.
├── LICENSE
├── README.rst
├── bin
├── composer.json
├── composer.lock
├── config
├── deploy.php
├── phpunit.xml.dist
├── src
├── templates
├── tests
├── var
├── vendor
└── web

インストール

公式サイトにはいくつかインストール方法が紹介されていますが、今回は直接pharファイルをダウンロードする方法でいきます。
プロジェクト内の bin ディレクトリへインストールします。

# path/to/deployer-sample

$ curl -LO https://deployer.org/deployer.phar
$ mv deployer.phar ./bin/dep
$ chmod +x ./bin/dep

設定ファイルの生成

コマンドで自動生成出来ます。
今回はSilexプロジェクトなので、Commonを選択。
コマンド実行したディレクトリに生成されるので、任意の場所に移動しています。
デプロイ用のファイルはプロジェクト内に置くべきかどうかは、ケースバイケースだと思いますが、今回は後々楽をする為にプロジェクト配下の config ディレクトリ以下に配置します。

# path/to/deployer-sample

$ ./bin/dep init

Please select your project type (defaults to common):
  [0] Common
  [1] Laravel
  [2] Symfony
  [3] Yii
  [4] Zend Framework
  [5] CakePHP
  [6] CodeIgniter
  [7] Drupal
 > 0
Successfully created: /path/to/deployer-sample/deploy.php

$ mv deploy.php ./config/

設定ファイルの設定

見たら分かる感じですね。
主な修正点は

  • 各種パス及びホスト名
  • PHP-FPMを使っていないので削除
  • writable_mode デフォルトでは acl というのが指定されており sudo 必須の為、今回はシンプルに chmod を設定

といったところです。

# config/deploy.php

 // Configuration

-set('repository', 'git@domain.com:username/repository.git');
+set('repository', 'git@github.com:example/deployer-sample.git');
 set('shared_files', []);
-set('shared_dirs', []);
-set('writable_dirs', []);
+set('shared_dirs', ['var/logs']);
+set('writable_dirs', ['var/cache']);
+set('writable_mode', 'chmod');

 // Servers

-server('production', 'domain.com')
-    ->user('username')
+server('production', 'example.com')
+    ->user('user')
     ->identityFile()
-    ->set('deploy_path', '/var/www/domain.com');
+    ->set('deploy_path', '/var/www/example.com');


 // Tasks

-desc('Restart PHP-FPM service');
-task('php-fpm:restart', function () {
-    // The user must have rights for restart service
-    // /etc/sudoers: username ALL=NOPASSWD:/bin/systemctl restart php-fpm.service
-    run('sudo systemctl restart php-fpm.service');
-});
-after('deploy:symlink', 'php-fpm:restart');
-
 desc('Deploy your project');
 task('deploy', [
     'deploy:prepare',
...

ローカルからの実行

ローカルから実行してみます。

前提条件

  • 公開鍵方式でデプロイ先サーバへSSH接続が出来る
  • 秘密鍵はデフォルトの~/.ssh/id_rsaを利用する
# path/to/deployer-sample

$ ./bin/dep -f=./config/deploy.php deploy production

デプロイ先はこんな感じになりました。

$ tree -a -L 2
.
├── .dep
│   └── releases
├── current -> /path/to/deployer-sample/releases/1
├── releases
│   └── 1
└── shared
│   └── var

少し変わっているのは、.dep/releases というファイルでしょうか。
中身は以下のように、リリースバージョン番号とタイムスタンプの一覧が保存されています。

20161206130959,1
20161206135544,2

CircleCIから自動的にデプロイ出来るようにする

SSHの秘密鍵を設定

Project Setting > SSH Permissions にてSSHの秘密鍵をセットします。
今回はホスト名をセットせずに登録しました。

circleci

デプロイ先のサーバにも公開鍵をセットします。

circle.ymlを用意

master ブランチが更新されたらデプロイをするように設定しました。

# path/to/deployer-sample/circle.yml

machine:
  timezone: Asia/Tokyo
  php:
    version: 5.6.22

dependencies:
  pre:
    - echo 'date.timezone = "Asia/Tokyo"' > /opt/circleci/php/$(phpenv global)/etc/conf.d/date_timezone.ini

deployment:
  production:
    branch: master
    commands:
      - |
        curl -LO https://deployer.org/deployer.phar
        mv deployer.phar /home/ubuntu/bin/dep
        chmod +x /home/ubuntu/bin/dep
      - dep -f=./config/deploy.php deploy production

deploy.phpの修正

このままだと、デプロイ時にデプロイ先サーバとの接続に失敗してしまいます。
これは、CircleCIのSSH Permissionsでセットした秘密鍵が~/.ssh/id_[HASH]のようなファイルで保存され~/.ssh/configにて以下のように解決していることが原因です。

Host !github.com *
IdentitiesOnly no
IdentityFile /home/ubuntu/.ssh/id_[HASH]

Deployerのデフォルトで利用されているSSHクライアントは、秘密鍵のパスがデフォルトで ~/.ssh/id_rsa にセットされるようになっているため、うまく認証ができません。
いくつか回避方法はありますが、今回はPHPのSSHクライアントではなく、サーバにインストールされているSSHクライアントを利用するようにDeployerの設定を変更して対応しました。

# path/to/deployer-sample

 set('writable_dirs', ['var/cache']);
 set('writable_mode', 'chmod');
+set('ssh_type', 'native');

これで、自動でデプロイされるようになります!
(実はここが一番ハマりました)

おわりに

PHP製アプリケーションにPHP製デプロイツールを利用することで、学習コストや環境構築コストなど低く抑えることが出来るというのは、ひとつのメリットだと思います。
Capistranoと比較して飛び抜けて優れている点があるかといわれると特にないかもしれませんが、シンプルで拡張しやすく作られており、個人的にはとても好印象でした。