読者です 読者をやめる 読者になる 読者になる

肉とビールとパンケーキ by @sotarok

少し大人になった「肉とご飯と甘いもの」

DotCloud で PHP アプリを設置してみたときの色々

PHP nginx DotCloud

beta の invite もらったので DotCloud で遊んでみました。

アプリ1つくらい設置してみないとなんだかよくわからないよねってことで、とりあえずどこで公開するかなーと思っていた、paste アプリ を設置してみた。


DotCloud の PHP の環境は、Ubuntu 上の nginx + php5-fpm (PHP 5.3.2) が標準で、なんというか時代の流れを感じました。いいね!
のは、まあいいとして、まぁ PHP アプリなんてものはたいてい Apache で動くことが前提とされてるもので (そうなのか? いや、そうだと思う。それが PHP のメリットだし) nginx な環境とか全然考慮してなかった + そんな PHP ユーザな弊害として nginx 力が低すぎてアレだったのですこしばかりはまったので、まあそのあたりのメモとして。

ということで、話は Pastit のディレクトリ構成を前提に進めますが、GitHub にあがってるので参考にしてください。

主な話の内容は、

  • DotCloud のアプリ設置操作
  • DotCloud の環境とか
  • DotCloud + PHP + nginx の環境とか

とりあえず設定

まあ Tutorial で言われてるとおりコマンドをインストールして、アプリケーションサーバMySQLサーバをつくってみる。
最初に dotcloud コマンドを使ったときに token をセットしろっていわれるけどこれはログインして setting を見たときに書いてあるやつな。

$ dotcloud list
$ dotcloud create pastit
$ dotcloud deploy --type php pastit.www
$ dotcloud deploy --type mysql pastit.mysql

MySQL の設定とかは以下で確認

$ dotcloud info pastit.mysql

cluster: wolverine
config:
    mysql_password: ****
created_at: 1304535584.4373901
name: pastit.mysql
namespace: pastit
ports:
-   name: mysql
    url: mysql://root:****@mysql.pastit.dotcloud.com:port
-   name: ssh
    url: ssh://dotcloud@mysql.pastit.dotcloud.com:port
state: running
type: mysql

MySQL は、以下でログインできるので、これでログインして DB 作ったりユーザ作ったりする。

$ dotcloud run pastit.mysql -- mysql -uroot -p\'****\'

で、ソースコードのデプロイ。今回は Git リポジトリです。Pastitのリポジトリのルートで実行。Gitのブランチを指定する場合は -b で。しなければ master が push される。

$ dotcloud push -b develop pastit.www .

で、http://www.pastit.dotcloud.com/ で動けばOK。今回は pastit.www という名前でデプロイしてるからこのURLになるけど、pastit.* に当たる部分が URL のサブドメイン *.pastit.dotcloud.com になる。

前提として知っておくべき DotColud の環境

push するとなにがどう設置されるか

DotCloud に push すると、以下のようなディレクトリ構成で設置される。とりあえず type = PHP の場合の話だが、アプリケーションサーバの場合他のタイプでも大差ないだろう。

dotcloud@pastit-www:~$ pwd
/home/dotcloud
dotcloud@pastit-www:~$ ls -la
-rw-r--r--  1 dotcloud www-data 54722 2011-05-06 18:53 build.log
drwxr-xr-x 13 dotcloud www-data  4096 2011-05-06 18:53 c1bda3a
lrwxrwxrwx  1 root     root         7 2011-05-06 18:53 code -> c1bda3a
lrwxrwxrwx  1 dotcloud www-data     8 2011-05-06 18:53 current -> code/www

この c1bda3a ってやつがコードの実態。
今回の場合リポジトリが Git だったので Git でのデプロイした時のコミットオブジェクトの hash 値になっている。
code ってやつは、常に最新のソースのルートへの symlink になっている。
current ってやつも symlink で、ここがアプリケーションの root (ドキュメントルート的な) の場所を指し示す。ここは、特に何も設定しなければ、 code と同じ場所を指すが、次に説明する dotcloud_build.yml で設定することで変更できる。

capistrano とかを使ったことがあれば、ソースコードが配置されて、最新のツリーへの symlink があって、みたいな構成はだいたい同じなのでキャッチアップしやすいと思う。

dotcloud_build.yml

DotCloud にアプリを push をすると、そのディレクトリをドキュメントルート *1 として設置される。多くのフレームワークのアプリの場合これは好ましくないはず。
なので、そのへんを設定してあげるのが docloud_build.yml。ここに、アプリの root がどこなのかという設定を記述できる (その他の設定項目もあるがとりあえずは省略) 。

このファイルは push するディレクトリのルートにおいておく。今回は approot として www ディレクトリを指定。

www:
  approot: www
nginx.conf と fastcgi.conf

approot 以下においておくと、読み込んでくれる nginx の設定。
といっても、Apache.htaccess とはちがって、単に nginx の設定で include されてるだけだから、pushしたときに nginx が reload されてはじめて設定は適用される。
両者の違いは、

  • nginx.conf : nginx のグローバルな設定
  • fastcgi.conf : location ~ /.+\.php$ に適用される設定

というだけ。これは設定が include される場所が違うだけ。PHP に関する設定は fastcgi.conf にしておくのがよさそう。


nginx.conf と fastcgi.conf は、deny 設定されてたのに、次に説明する postinstall だけ deny されてなかったので、それを nginx.conf に書いておいた。あと try_files の設定 (後述)。

try_files $uri $uri/ /index.php?$args;
location = /postinstall {
    deny    all;
}
postinstall

いかにも Debian 好きっぽそうなこの名前は、approot 以下に実行ファイルとしておいておくと、push の最後に実行してくれる。アプリケーションの設定の適用を行うファイルとかを適切においておけば良い。
ちなみに、Pastit は Ethna の config を home においておいて、それを push 時に適切なディレクトリにコピーするようにしている。PHP厨らしくちゃんとPHPで記述しておく。

#!/usr/bin/php
<?php

define('DOTCLOUD_HOME', '/home/dotcloud/');

$files = array(
    'pastit-ini.php'     => 'code/config/pastit-ini.php',
    'pastit-app-ini.php' => 'code/config/pastit-app-ini.php',
);

foreach ($files as $origin_file => $dest_file) {
    if (!file_exists(DOTCLOUD_HOME . $dest_file)
        && file_exists(DOTCLOUD_HOME . $origin_file))
    {
        echo DOTCLOUD_HOME . $origin_file, " -> ", DOTCLOUD_HOME . $dest_file, PHP_EOL;
        copy(DOTCLOUD_HOME . $origin_file, DOTCLOUD_HOME . $dest_file);
    }
}

// task
echo 'end of task', PHP_EOL;
その他

まあ ssh で入って /etc/nginx 以下をのぞけばわかることだけど、

nginx x PHP な設定

PAHT_INFO とか

PATH_INFO使ってる人ってどれだけいるのかわからないけど Ethna の UrlHandler はそれ使って path 解析するから、あるといい。
んだけど、PHP で一般的に知られている nginx 向けの PATH_INFO の設定だと、location が

/.+\.php.+$

にマッチするのが前提だったりしなくもないので、それだと、DotCloud 的にはよろしくない。というのは、DotCloud の PHP 向けの nginx の設定が

    location ~ /.+\.php$ {
        if ( -f /home/dotcloud/current/maintenance) {
            return 503;
        }

        try_files       $uri /static/404.html;

        fastcgi_pass    unix:/var/dotcloud/php5-fpm.sock;
        include         fastcgi_params;
        include         /home/dotcloud/current/*fastcgi.conf;
    }

となっているので、index.php/hoge とかにマッチしてくれない。

ならば /.+\.php.+$ にマッチする設定を approot/nginx.conf に書いておけば良いのかもしれないけど、fastcgi_pass のような DotCloud 環境依存な設定がそっちに記述されるのもどうかなと思うので、ここはゴリ押しで解決させておく。

index.php の先頭でこんなかんじで PATH_INFO のセットをしておいた

<?php
if (!isset($_SERVER['PATH_INFO'])) {
    $request_uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
    if (!empty($request_uri)) {
        $parsed_uri = parse_url($request_uri);
        $request_uri = isset($parsed_uri['path']) ? $parsed_uri['path'] : '';
    }
    $_SERVER['PATH_INFO'] = $request_uri;
}
rewrite とか

このあたりは DotCloud の Tutorial にあるように、try_files で設定しておくのがよさそう。$args も忘れずに。

try_files $uri $uri/ /index.php?$args;

よくある nginx.conf の設定だとここで

/index.php$requrest_uri

などをしておくことで PATH_INFO は設定するんだけど、そもそもこれは前述のとおり location でマッチできなくなるのでだめだった、というわけです。

その他PHPについて

PHP でも rake みたいなツールがほしい&一般的になってほしい
PHP だとどうしても設置後の task みたいなものを記述できる環境がないので、PaaS の恩恵でデプロイが楽になっても、アプリケーションのセットアップと設定管理みたいなものをどうするかって課題が残る。

今のところ、postinstall でなんかしら設定を行うように書いておくのがまあ普通かなーと思う。

まとめと雑感

  • DotCloud いいかんじ
  • サーバ建てるのとかデプロイとか超楽
    • PaaS的なものが増えてきてほんとアプリケーションエンジニアがインフラ触る機会って今後減ってくるんだろうなーと思った
  • Apache で簡単に動く PHP も好きだけど nginx な環境も最近は割と簡単に揃うし FPM とかも徐々に使われるようになるのかなーと思いつつ、色々な環境で動かせるようにしておくのは、たしかによさそう *2
    • まあいずれにしても Apache べったり、じゃなくてもいい時代かもね
  • DotCloud はその他ミドルウェアも充実してるからいろいろ遊びたいなー
  • あ、ってことで Pastit っていう、設置型ペーストアプリを公開しました。これはもとも Internal な環境で (社内とか) snippet の共有が簡単にできるといいなーと思って作ったので、使いたい方は設置してみるといいかもしれません、結構便利ですよ。まだ embed できないけど。

*1:nginx で Apache の DocumentRoot にあたるものってなんていうの?

*2:他の言語で FastCGIWSGI/PSGI などの動きがあるなか PHPFastCGI