22日目: デプロイ

昨日のキャッシュシステムのコンフィギュレーションによって、Jobeet の Webサイトは運用サーバーにデプロイされる準備ができています。

22日間、開発マシンで Jobeet を開発してきました。ほとんどの方がローカルマシンで作業したでしょう; 運用サーバーで直接開発するのは、もちろん非常にわるいアイデアです。では、Web サイトを運用サーバーに移行しましょう。

今日は、運用環境に移行する前に必要なもの、とることができる~デプロイ戦略~の種類、継続的なデプロイに必要なツールも見ることにします。

運用~サーバー|Webサーバー~を用意する

プロジェクトを運用サーバーに~デプロイ~する前に、運用サーバーを正しく設定する必要があります。1日目を読み返すと、Web サーバーの設定方法が説明されています。

このセクションでは、Web サーバー、データベースサーバーと PHP 5.2.4 以降をインストールしたことを前提とします。

NOTE Web サーバーに SSH でアクセスできない場合、コマンドラインにアクセスする必要のあるセクションは読み飛ばしてください。

サーバーのコンフィギュレーション

最初に、PHP が必要なエクステンションと一緒にインストールされ正しく設定されていることを確認する必要があります。1日目に関して、symfony によって提供される check_configuration.php スクリプトを使います。symfony を運用サーバーにインストールしないので、symfony 公式サイトからファイルを直接ダウンロードします:

http://trac.symfony-project.org/browser/branches/1.4/data/bin/check_configuration.php?format=raw

Web のルートディレクトリにファイルをコピーしてブラウザコマンドラインから実行します:

$ php check_configuration.php

スクリプトが見つける致命的なエラーを修正し両方の環境ですべてがよい状態で動作するまで作業を繰り返します。

PHP ~アクセラレータ~

運用サーバーに関して、可能な限りベストなパフォーマンスを得ることを望んでいらっしゃるでしょう。PHP アクセラレータをインストールすれば最高のお金の節約になります。

NOTE Wikipedia より: PHP アクセラレータはリクエストごとのソースの解析とコンパイルのオーバーヘッドを回避するためにPHPスクリプトのコンパイルされたバイトコードをキャッシュすることで動作します。

~APC~ はもっとも人気のあるアクセラレータで、インストール作業がシンプルです:

$ pecl install APC

OS によっては、OS ネイティブのパッケージマネージャでインストールすることもできます。

NOTE APC の設定方法を学ぶための時間をとってください。

symfony のライブラリ

symfony を埋め込む

symfony の強みの1つはプロジェクトが自己完結していることです。プロジェクトを動作させるために必要なすべてのファイルはメインのルートディレクトリの下にあります。symfony は相対パスのみを使用するのでプロジェクトで何も変更せずにプロジェクトを別のディレクトリに移動できることを意味します。運用サーバーのディレクトリは開発マシンと同じである必要はないことを意味します。

唯一の絶対パスは config/ProjectConfiguration.class.php ファイルで見つかります; しかし1日目を読み返して、symfony コアのオートローダへの相対パスが含まれていることを確認します:

[php]
// config/ProjectConfiguration.class.php
require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';

symfony を~アップグレード~する

すべての内容が単独のディレクトリに収まる場合、symfony を新しいリリースにアップグレードする作業はものすごく簡単です。

バグとセキュリティ問題の修正は定期的に行われるので、ときどき symfony を最新のマイナーリリースにアップグレードすることを望むでしょう。よい知らせはすべての symfony のバージョンは少なくとも1年間は維持されメンテナンス期間の間、新しい機能は小さくても追加されません。ですので、1つのマイナーリリースから別のマイナーリリースへのアップグレードは常に速く、安全でセキュアです。

symfony のアップグレード作業は lib/vendor/symfony/ ディレクトリの内容を変更するだけなのでシンプルです。アーカイブで symfony をインストールする場合、現在のファイルを削除して最新のものに置き換えます。

プロジェクトで ~Subversion~ を使う場合、プロジェクトを最新の symfony 1.4 のタグにリンクすることもできます:

$ svn propedit svn:externals lib/vendor/
  # symfony http://svn.symfony-project.com/tags/RELEASE_1_4_1/

symfony のアップグレード作業はタグを最新バージョンに変更するだけなのでシンプルです。

リアルタイムで修正される1.4系のブランチも利用できます:

$ svn propedit svn:externals lib/vendor/
  # symfony http://svn.symfony-project.com/branches/1.4/

svn up を実行するたびに、最新の symfony 1.4 が得られます。

新しいバージョンにアップグレードするとき、とりわけ運用環境では、常にキャッシュをクリアすることをお勧めします:

$ php symfony cc

TIP 運用サーバーの FTP アクセス権限もある場合、cache/ ディレクトリの下にあるすべてのファイルとディレクトリを削除することで symfony cc をシミュレートできます。

symfony の既存のバージョンを置き換えずに新しいバージョンをテストすることもできます。新しいリリースをテストしたいだけで、簡単にロールバックできるようにしたい場合、別のディレクトリ (たとえば lib/vendor/symfony_test) に symfony をインストールし ProjectConfiguration クラスのパスを変更し、キャッシュをクリアします。ロールバックはディレクトリを削除して ProjectConfiguration のパスを元に戻すだけです。

~コンフィギュレーション~を調整する

データベースのコンフィギュレーション

ほとんどの場合、運用のデータベースはローカルと異なるクレデンシャルをもちます。symfony の環境システムのおかげで、運用データベースの異なるコンフィギュレーションを用意するのはたやすいことです:

$ php symfony configure:database
   ➥ "mysql:host=localhost;dbname=prod_dbname" prod_user prod_pass

databases.yml 設定ファイルを直接編集することもできます。

~アセット~

Jobeet はアセットを埋め込む~プラグイン|プラグインアセット~を使うので symfony は web/ ディレクトリに相対的なシンボリックリンクを作成しました。plugin:install タスクなしでプラグインをインストールする場合 plugin:publish-assets タスクはこれらを再生成もしくは作成します:

$ php symfony plugin:publish-assets

~エラーページ~を~カスタマイズする~

運用に移行する前に、~404エラー~ページ、もしくはデフォルトの例外ページのような symfony の~デフォルトページ~をカスタマイズするのはよいことです。

15日目、config/error/ ディレクトリで error.yaml.phpexception.yaml.php ファイルを作ることで YAML フォーマット用のエラーページを設定しました。prod 環境のときは error.yaml.php ファイルが、dev 環境では exception.yaml.php が使われます。

ですので、HTML ~フォーマット~用にデフォルトの~例外|例外ハンドリング~ページをカスタマイズするには、2つのファイル: config/error/error.html.phpconfig/error/exception.html.php を作ります。

404ページ (ページが見つからないエラーページ) は error_404_moduleerror_404_action 設定を変更することでカスタマイズできます:

[yml]
# apps/frontend/config/settings.yml
all:
  .actions:
    error_404_module: default
    error_404_action: error404

ディレクトリ~構造~をカスタマイズする

コードの構造化と標準化のために、symfony にはあらかじめ定義される名前をもつデフォルトのディレクトリ構造があります。しかしときには、何らかの外部の制約から構造を変更せざるをえないことがあります。

config/ProjectConfiguration.class.php クラスでディレクトリの名前を設定できます。

~Web サイトのルートディレクトリ~

Web ホスティングの状況によって、Web サイトのルートディレクトリの名前を変更できないことがあります。名前が web/ ではなく public_html/ である場合を考えてみましょう:

[php]
// config/ProjectConfiguration.class.php
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    $this->setWebDir($this->getRootDir().'/public_html');
  }
}

setWebDir() メソッドは Web 公開のルートディレクトリの絶対パスを受け取ります。このディレクトリもどこかに移動させる場合、ProjectConfiguration ファイルへのパスがまだ有効であることを確認するためにコントローラスクリプトを編集することをお忘れなく:

[php]
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');

~キャッシュ~と~ログ~ディレクトリ

symfony フレームワークは2つのディレクトリ: cache/log/ のみに書き込みます。~セキュリティ~の理由から、Web ホスティング会社の中にはメインディレクトリに~書き込みパーミッション~を設定しないところがあります。これに該当する場合、これらのディレクトリをほかのファイルシステムに移動させることができます:

[php]
// config/ProjectConfiguration.class.php
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    $this->setCacheDir('/tmp/symfony_cache');
    $this->setLogDir('/tmp/symfony_logs');
  }
}

setWebDir() メソッドに関して、setCacheDir()setLogDir() はそれぞれ cache/log/ ディレクトリへの絶対パスを受け取ります。

symfony のコアオブジェクトをカスタマイズする (別名はファクトリ)

16日目において、symfony のファクトリを少し話しました。ファクトリがカスタマイズできることは symfony コアオブジェクトに対してデフォルトクラスの代わりにカスタムクラスを使うことができることを意味します。これらのクラスに送信するパラメータを変更することでこれらのデフォルトのふるまいを変更することもできます。

おそらくお望みの古典的なカスタマイズ方法を見てみましょう。

~Cookie~ の名前

~ユーザーセッション|セッション~を扱うために、symfony は Cookie を使います。この Cookie はデフォルトの名前として symfony をもちます。これは factories.yml で変更できます。all キーの下で、Cookie の名前を jobeet に変更するために次のコンフィギュレーションを追加します:

[yml]
# apps/frontend/config/factories.yml
storage:
  class: sfSessionStorage
  param:
    session_name: jobeet

~セッション|セッションストレージ~~ストレージ~

デフォルトのセッションストレージクラスは sfSessionStorage です。このクラスはセッション情報を保存するためにファイルシステムを使います。複数の Web サーバーがある場合、データベーステーブルのような中心位置で複数のセッションを保存するとよいでしょう:

[yml]
# apps/frontend/config/factories.yml
storage:
  class: sfPDOSessionStorage
  param:
    session_name: jobeet
    db_table:     session

database: propel database: doctrine dbidcol: id dbdatacol: data dbtimecol: time

セッションのタイムアウト

デフォルトでは、ユーザーセッションの~タイムアウト|セッション (タイムアウト)~は1800秒です。これは user エントリを編集することで変更できます:

[yml]
# apps/frontend/config/factories.yml
user:
  class: myUser
  param:
    timeout: 1800

~ロギング~

デフォルトでは、prod ~環境~ではロギングは行われません。ロガークラスの名前が sfNoLogger だからです:

[yml]
# apps/frontend/config/factories.yml
prod:
  logger:
    class:   sfNoLogger
    param:
      level:   err
      loggers: ~

たとえばロガークラスの名前を sfFileLogger に変更することでファイルシステムでのロギングを有効にできます:

[yml]
# apps/frontend/config/factories.yml
logger:
  class: sfFileLogger
  param:
    level:   err
    loggers: ~
    file:    %SF_LOG_DIR%/%SF_APP%_%SF_ENVIRONMENT%.log

NOTE factories.yml 設定ファイルにおいて、文字列の %XXX%sfConfig オブジェクトからの対応する値に置き換えられます。ですので、設定ファイルの %SF_APP% は PHP コードの sfConfig::get('sf_app') と同等です。この表記は app.yml 設定ファイルでも利用できます。パス (SF_ROOT_DIRSF_WEB_DIR、・・・) を決め打ちせずに設定ファイルでパスを参照する必要があるときにとても便利です。

~デプロイ~する

デプロイとは?

Jobeet の Web サイトを運用サーバーにデプロイするとき、 不要なファイルをアップロードしないもしくは企業のロゴのように、ユーザーによってアップロードされたファイルを上書きしないように注意する必要があります。

symfony プロジェクトにおいて、転送から除外されるディレクトリは3つ: cache/log/web/uploads/ あります。 そのほかはすべてそのまま転送できます。

セキュリティ上の理由から、frontend_dev.phpbackend_dev.phpfrontend_cache.php スクリプトのような"運用環境ではない"フロントコントローラも転送したくないでしょう。

デプロイ戦略

このセクションでは、運用サーバーを完全にコントロールできることを前提とします。サーバーへのアクセス権限が FTP アカウントの場合は、唯一可能なデプロイの解決策はデプロイするたびにすべてのファイルを転送することです。

Web サイトをデプロイするもっともシンプルな方法は組み込みの project:deploy ~タスク~を使うことです。これは接続して1つのコンピュータから別のコンピュータにファイルを転送するために ~SSH~ と ~rsync~ を使います。

project:deploy タスクのサーバーは config/properties.ini 設定ファイルで設定できます:

[ini]
# config/properties.ini
[production]
  host=www.jobeet.org
  port=22
  user=jobeet
  dir=/var/www/jobeet/

新しく設定した production サーバーにデプロイするには、project:deploy タスクを使います:

$ php symfony project:deploy production

NOTE 初めて project:deploy タスクを実行する前に、キーを既知のホストファイルに追加するために手動でサーバーに接続する必要があります。

-

TIP このコマンドが期待どおりに動かなければ、rsync コマンドのリアルタイムの出力を見るために -t オプションを渡すことができます。

このコマンドを実行すると、symfony は転送のシミュレーションのみを行います。実際に Web サイトをデプロイするには、--go オプションを追加します:

$ php symfony project:deploy production --go

NOTE properties.ini ファイルで SSH パスワードを提供できる場合でも、パスワードなしの接続ができるように SSH キーでサーバーを設定するほうがベターです。

デフォルトでは、symfony は以前のセクションで話したディレクトリを転送しませんし、dev のフロントコントローラスクリプトも転送しません。これは project:deploy タスクが config/rsync_exclude.txt ファイルで設定されたファイルとディレクトリを除外するからです:

# config/rsync_exclude.txt
.svn
/web/uploads/*
/cache/*
/log/*
/web/*_dev.php

Jobeet に対して、frontend_cache.php ファイルを追加する必要があります:

# config/rsync_exclude.txt
.svn
/web/uploads/*
/cache/*
/log/*
/web/*_dev.php
/web/frontend_cache.php

TIP ファイルとディレクトリの転送を強制するために config/rsync_include.txt ファイルを作ることもできます。

project:deploy タスクがとても柔軟であるとしても、さらにカスタマイズできます。デプロイはサーバーとコンフィギュレーションとネットワークトポロジーによって大きく異なる可能性があるので、デフォルトのタスクを拡張することをためらわないでください。

Web サイトを運用サーバーにデプロイするたびに、少なくとも運用サーバーの設定キャッシュをクリアすることをお忘れなく:

$ php symfony cc --type=config

ルートを変更したら、ルーティングのキャッシュもクリアする必要があります:

$ php symfony cc --type=routing

NOTE キャッシュを選別してクリアすることで、テンプレートキャッシュのようなキャッシュの一部を維持できます。

また明日

プロジェクトのデプロイは symfony 開発のライフサイクルの一番最後のステップです。これはすべてが終わったことを意味しません。全くの逆です。Web サイトの人生の始まりです。おそらくバグを修正しなければならず時間が経過したら新しい機能も追加したくなります。しかし symfony の構造と自由に使えるツールのおかげで、Web サイトのアップグレード作業はシンプルで、速く、安全です。

明日は Jobeet チュートリアルの最後の日です。Jobeet の23日間に学んだことを振り返ります。

ORM