CakePHP2アプリケーションをCapistranoでデプロイする

 2012/11/12

アプリケーションのデプロイを自動化すべきなのは言うまでもないことです。 一応手動でデプロイを行う場合の問題点について整理しておくと以下になります。

  • プロジェクトの期間中そして運用に入ってからも何度も手でデプロイするということはとてつもなく多くの時間を手作業に費やすことになる
  • デプロイ先の環境の数が多くなればなるほど作業の時間も増える
  • 手作業で作業すると間違えやすい。特に手順が複雑だったり環境が多かったりすると確率は飛躍的にあがる
  • もしデプロイしたアプリケーションに問題があってすぐに戻さなければならない場合に多くの時間がかかる。場合によってはビジネス上の機会損失に繋がる

本来は価値を生むフィーチャーを実装することに時間をかけたいはずが、こういうことをやっているとどんどん時間がなくなっていきます。また手作業のリスクや消費される時間を恐れてデプロイの回数を減らしてしまうのは、ビジネス側からみると納得いかないでしょう。

ということで、アプリケーションのデプロイはプロジェクトの早期から実現して、開発や運用の期間中は全てそのデプロイ機構を通じてのみデプロイが行われるべきです。社内の開発環境や確認環境、ステージング環境など全て同一の機構で一環してデプロイを続けることで、デプロイプロセスの信頼性も確保されます。

今回はCakePHP2で作ったアプリケーションをCapistranoを利用して簡単にデプロイする方法を説明します。

Capistranoのインストール

デプロイのコマンドを発行したいサーバにCapistranoをインストールします(デプロイ先サーバではありません)。 この時、Capistranoの出力を色分けしてくれるcapistrano_colors、開発環境や本番環境などのデプロイ先環境の切り替えを行えるcapistrano-ext、Railsではないアプリケーションをデプロイする際に利用するrailsless-deployもあわせてインストールしてください。

sudo gem install capistrano
sudo gem install capistrano_colors
sudo gem install capistrano-ext
sudo gem install railsless-deploy

デプロイ定義ファイルの作成

上記のインストールが終わったらデプロイ定義ファイルを作成します。 デプロイ定義ファイルを作成したいディレクトリに移動して

capify .

を実行してください。以下のようなメッセージが表示され、デプロイ定義ファイルが作成されます。定義の実体はconfig/deploy.rb になります。

[add] making directory './config'
[add] writing './config/deploy.rb'
[add] writing './Capfile'
[done] capified!

ここでひな形が作成されますが、そのままではデプロイできないので、色々な設定を行います。設定する主な項目は

  • アプリケーションの名前
  • デプロイ先のディレクトリ名
  • 利用するバージョン管理システムの種類
  • レポジトリのURL
  • デプロイの方法(デプロイ先で直接バージョン管理システムに接続するか、デプロイ元にチェックアウトしたファイル一式をアップロードするか)
  • デプロイ先サーバの情報(役割やアドレスや接続用アカウント、sudoを使うかなど)

などなどです。かなり色々な設定ができるので詳細はマニュアルを参照してください。https://github.com/capistrano/capistrano/wiki

今回のサンプルでは、

  • デプロイ先の設定を複数のステージに分離する(developとpreviewとproduction)
  • ソースコードはbitbucketに配置
  • デプロイの際は一端ローカル端末にチェックアウトして、まるごとアップロードする
とします。

デプロイ先のステージの準備

config/deploy 以下にステージ用のファイルを作成します。例えばdevelopであればdevelop.rbとしproductionであればproduction.rbとします。 これらのファイルは実際にCapistranoを動作させる際に引数としたステージ名に応じて読み込まれます。 例えば開発環境用のconfig/deploy/develop.rb は以下のようになります。

# develop                                                                                                                                                                                                          #
role :web, *%w[
  dev-web.example.com
]
role :db, *%w[
  dev-db.example.com
]

set :user, "deploy_user"
set(:password) do
  Capistrano::CLI.password_prompt "Set password for develop server: "
end

この例では、develop環境にデプロイする場合の対象サーバの設定(WebサーバとDBサーバ)、それからサーバに接続するユーザー名、そして接続の際にはパスワードを手で入力することにしたので、Capistrano::CLI.password_promptを使って入力されたパスワードを:passwordに設定しています。 サーバへの接続の際にパスワードを聞かれないようにするには、パスワードをベタ書きするか、鍵ペアを使った接続にするかどちらかになります。例えばJenkinsからワンクリックでデプロイしたいような場合は、鍵ペアを利用すると良いでしょう。(今回は割愛します)なお、他のステージも同じ考え方になります。ステージによって切り替わるような定数については、こちら側のファイルに定義すればOKです。

デプロイの手順を定義する

一番簡単な例は以下の通りです。最初に必要となるgemを読み込みます。 次にアプリケーション名は各ステージ共通なのでこちらで設定します。またデプロイするソースが配置されているバージョン管理システムの設定をします。ここではbitbucketの僕のレポジトリにあるcake2_sampleというプロジェクトのmasterブランチをデプロイ対象としています。またデプロイ方法は、一端ローカル環境にチェックアウトしてtar.gzで固めてアップロードする:copy形式としており、各種の作業はsudoを使って行うことにします(先ほどのdevelop.rbで定義した接続ユーザーがsudoできるようにデプロイ先サーバを設定しておいてください)

require "capistrano/ext/multistage"
require "capistrano_colors"
require "railsless-deploy"
require "rubygems"

set :application, "cake2_sample"
set :scm, :git
set :repository,  "git@bitbucket.org:ryuzee/cake2_sample.git"
set :branch, "master"
set :deploy_to, "/usr/local/webapp/cake2_sample"
set :deploy_via, :copy
set :use_sudo, true
after "change_permission"
after "git_submodule_update"
after "migrate"

desc "アプリケーションの動作に必要なパーミッションの設定をします"
task :change_permission, roles => :web do
  run <<-CMD
    chmod -R #{deploy_to}/current/app/tmp
  CMD
end

desc "外部モジュールを取得します"
task :git_submodule_update, roles => :web do
  run <<-CMD
    cd #{deploy_to}/current && git submodule init && git submodule update
  CMD
end

desc "データベースのマイグレーションを実行します"
task :migrate, roles => :web do
  run <<-CMD
    cd #{deploy_to}/current/app && Console/cake Migrations.migration run all -p Migrations && Console/cake Migrations.migration run all
  CMD
end

タスクの定義

なお、CakePHPのアプリケーションで特徴的なのは、app/tmp 以下にapache等のhttpdデーモンを起動しているユーザーで書き込みが出来る必要があることです(キャッシュファイル等を作成します)。従って、デプロイの際に、当該ディレクトリに書き込み権限を与えるタスクである:change_permissionを定義し、デプロイ完了後にパーミッションを変更するように設定しています。

また今回は、アプリケーションの中で利用しているライブラリ等をgitのsubmoduleとして定義していますので、同様にデプロイ後にモジュールの取得を行なっています。(:git_submodule_update)

そして最後にデータベースのマイグレーションも自動で実行するようにしましょう。これは:migrateタスクで定義しています。 なおdeploy:migrateという機能もありますが、Webサーバ側からCakePHPの機能を使ってマイグレーションできるので自分で再定義しています。CakePHPのマイグレーションについては既に本サイトで手順を書いていますのでそちらを参照してください。

デプロイの実行

ここまで出来たら試しにデプロイを実行してみます。まずは初回デプロイの場合は ``` cap develop deploy:setup ``` と実行して、ディレクトリの作成等を行います。このコマンドを実行するとデプロイ先ディレクトリにcurrent、releases、sharedの3つのディレクトリが作られます。なお:deploy_toのディレクトリは作成しておいてください。 第二引数のdevelopはステージを表しているので、他のステージの場合はここを変えます。 次にデプロイを実行します。 ``` cap develop deploy ``` これを実行すると以下のように表示されるはずです。 エラーがある場合は赤い文字で表示されるはずです。

その他の話

CakePHPのアプリケーションにおいてはデータベースの接続情報はdatabase.phpに定義しますがこの接続ユーザーやパスワードをバージョン管理システムには入れたくないといったケースもあります。またアプリケーションの中で環境に依存する情報を定義していたりするケースではデプロイ先に応じてファイルを切り替えたいケースもあるでしょう。 そういう場合は個別のタスクを作成して、別の場所からファイルをアップロードしたりすることも出来ます。

以下の例ではデプロイ定義ファイルと同じディレクトリにconfig/[ステージ名]/database.phpというファイルを用意しておいて、個別にアップロードする例です。このタスクをデプロイの際に自動で行うようにすれば、環境毎に異なるファイルを切り替えることが可能になります(CIサーバからデプロイをする場合は、この環境設定用のファイルをCIサーバ側に配置しておくわけにはいかないので他の方法を考えます)

desc "データベース接続設定をアップロードします"
task :upload_databaseconfig, roles => :web do
  upload(File.dirname(__FILE__) + "/config/#{stage}/database.php", "#{deploy_to}/current/app/Config/", :via => :scp) do |event, options, *others|
  end
end

おまけ

cap -Tを実行すると色々なタスクが実行可能なのが分かります。ただうかつに実行されてしまうと問題になる項目もあるでしょう。 そういう場合はデプロイスクリプトの中でデフォルトの挙動を無効化します。

namespace(:deploy) do
[
  :restart, :start, :stop, :cold, :migrate, :migrations,
].each {|t| task(t){ puts "この機能は無効になっています"} }
end                                                           

さらにおまけ

デプロイが完了したらTwitterにつぶやきを流すことも出来ます。 この場合はgemでtwitterライブラリを使えば簡単です。

 2012/11/12

サイト内検索


著作

寄稿

Latest post: