Capistrano

Contents

概要


Capistranoとはオープンソースの複数のサーバ上で同時にスクリプトを動かすツールである。
主にデプロイツールとして使用される。
内部的にRubyのビルドツールRakeを使用しており、デプロイにおける挙動をRakeのTask定義方法で記述する。


環境





サーバの構築


事前準備







Rubyのインストール


パッケージでインストールすると古いバージョンのRubyがインストールされてしまうが、
Capistranoの最新版ではVer1.9以降のRubyが必要なので、手動でインストールを行う。

ソースコードからインストール


  1. Rubyダウンロードサイトから最新版の安定版URLを調べる
  2. Rubyをダウンロードする
    wget http://cache.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p247.tar.gz
  3. 展開する
    tar xzfv ruby-2.0.0-p247.tar.gz
  4. インストールする
    cd ruby-*
    export CFLAGS="-O3 -m64"
    ./configure --prefix=/usr/local/
    
    make | tee make.log
    
    # openssl、zlibにエラーが出ていないか確認
    cat make.log | grep Failed | grep openssl
    cat make.log | grep Failed | grep zlib
    # Failed to configure XXX. It will not be installed. というメッセージが表示されると失敗
    # 失敗した場合は次のコマンドをから再度やり直す
    #
    # ./configure --prefix=/usr/local/ --with-ext="openssl,zlib"
    # make | tee make.log
    
    
    # 既に古いRubyがインストールされている場合は、以下のようなエラーが出る可能性がある。
    #
    # Directory .ext/rdoc already exists, but it looks like it isn't an RDoc directory.
    # 
    # Because RDoc doesn't want to risk destroying any of your existing files,
    # you'll need to specify a different output directory name (using the --op <dir>
    # option)
    #
    # この場合は、./configureに--disable-install-rdocオプションをつけることで、エラー回避が可能。ただし、rdoc (rubyコードからドキュメントを生成するツールが使用できなくなる)
    
    make install
  5. 正しくインストールされたことを確認する
    which ruby
    ruby --version

デプロイユーザの作成


デプロイを実行するユーザを作成する。
更にキーペアを生成する。
CapistranoではSSHを使用してデプロイ先のサーバにログインするが、パスワードよりキーペアを使用した認証が推奨されている。

useradd -U deploy

su - deploy

ssh-keygen
# Enter file in which to save the key (/home/deploy/.ssh/id_rsa):  に何も入力せずにエンター
# Enter passphrase (empty for no passphrase): に何も入力せずにエンター
# Enter same passphrase again: に何も入力せずにエンター

ls .ssh/id_rsa*
# 以下のキーファイルが生成されていることを確認する。
# id_rsa  id_rsa.pub




デプロイ先サーバの準備


各デプロイ先にログインし、それぞれ以下の操作を行う。


デプロイ元サーバからログインできるか確認する場合は以下を実行
ssh -i deploy_key -l deploy <宛先ホスト>

Capistranoの構築


Capistranoのインストール


gem install capistrano
# y/Nを聞かれるのでyを入力

Capistranoの設定ファイル作成


# Capistranoの設定ファイルを配置する
mkdir -p <任意のパス>
cd <任意のパス>
cap install

※以降では
/home/deploy/capistrano
にインストールしたと仮定する。

Capistranoの設定ファイル作成(自作用)


cap installするとテンプレートファイルが生成されるが、あまり役に立たないので自前でインストールを行う。
mkdir -p <任意のパス>
cd <任意のパス>
mkdir -p config/deploy
mkdir -p lib/capistrano/tasks
echo "require 'capistrano/setup'" > Capfile
echo "Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }" >> Capfile
touch config/deploy.rb





Capistranoの使い方


Capistranoは主にsetコマンドやserverコマンドによるパラメータ設定と、Rake形式のタスク定義を記述しておき、
Capistranoの起動時にどの設定・タスクを採用するかを引数として与える、という使用方法をとる。

Readme


Capistranoをインストールした際に作成されるReadmeファイル。
/usr/local/lib/ruby/gems/2.0.0/gems/capistrano-3.0.1/README.md
# Capistrano [![Build Status](https://travis-ci.org/capistrano/capistrano.png?branch=v3)](https://travis-ci.org/capistrano/capistrano) [![Code Climate](https://codeclimate.com/github/capistrano/capistrano.png)](https://codeclimate.com/github/capistrano/capistrano)

## Requirements

* Ruby >= 1.9 (JRuby and C-Ruby/YARV are supported)

## Installation

Add this line to your application's Gemfile:

``` ruby
gem 'capistrano', '~> 3.0.0'
```

And then execute:

``` sh
$ bundle install
```

Capify:
*make sure there's no "Capfile" or "capfile" present*
``` sh
$ bundle exec cap install
```

This creates the following files:

```
├─ Capfile
├─ config
│   ├─ deploy
│   │   ├─ production.rb
│   │   └─ staging.rb
│   └─ deploy.rb
└─ lib
     └─ capistrano
            └─ tasks
```

To create different stages:

``` sh
$ bundle exec cap install STAGES=local,sandbox,qa,production
```

## Usage

``` sh
$ bundle exec cap -vT

$ bundle exec cap staging deploy
$ bundle exec cap production deploy

$ bundle exec cap production deploy --dry-run
$ bundle exec cap production deploy --prereqs
$ bundle exec cap production deploy --trace
```

## Tasks

``` ruby
server 'example.com', roles: [:web, :app]
server 'example.org', roles: [:db, :workers]
desc "Report Uptimes"
task :uptime do
  on roles(:all) do |host|
    info "Host #{host} (#{host.roles.join(', ')}):\t#{capture(:uptime)}"
  end
end
```

## Before / After

Where calling on the same task name, executed in order of inclusion

``` ruby
# call an existing task
before :starting, :ensure_user

after :finishing, :notify


# or define in block
before :starting, :ensure_user do
  #
end

after :finishing, :notify do
  #
end
```

If it makes sense for your use-case (often, that means *generating a file*)
the Rake prerequisite mechanism can be used:

``` ruby
desc "Create Important File"
file 'important.txt' do |t|
  sh "touch #{t.name}"
end
desc "Upload Important File"
task :upload => 'important.txt' do |t|
  on roles(:all) do
    upload!(t.prerequisites.first, '/tmp')
  end
end
```

The final way to call out to other tasks is to simply `invoke()` them:

``` ruby
task :one do
  on roles(:all) { info "One" }
end
task :two do
  invoke :one
  on roles(:all) { info "Two" }
end
```

This method is widely used.

## Getting User Input

``` ruby
desc "Ask about breakfast"
task :breakfast do
  breakfast = ask(:breakfast, "What would you like your colleagues to get you for breakfast?")
  on roles(:all) do |h|
    execute "echo \"$(whoami) wants #{breakfast} for breakfast!\" | wall"
  end
end
```

Perfect, who needs telephones.


## Running local tasks

Local tasks can be run by replacing `on` with `run_locally`

``` ruby
desc "Notify service of deployment"
task :notify do
  run_locally do
    with rails_env: :development do
      rake 'service:notify'
    end
  end
end
```

## Console

**Note:** Here be dragons. The console is very immature, but it's much more
cleanly architected than previous incarnations and it'll only get better from
here on in.

Execute arbitrary remote commands, to use this simply add
`require 'capistrano/console'` which will add the necessary tasks to your
environment:

``` sh
$ bundle exec cap staging console
```

Then, after setting up the server connections, this is how that might look:

``` sh
$ bundle exec cap production console
capistrano console - enter command to execute on production
production> uptime
 INFO [94db8027] Running /usr/bin/env uptime on leehambley@example.com:22
DEBUG [94db8027] Command: /usr/bin/env uptime
DEBUG [94db8027]   17:11:17 up 50 days, 22:31,  1 user,  load average: 0.02, 0.02, 0.05
 INFO [94db8027] Finished in 0.435 seconds command successful.
production> who
 INFO [9ce34809] Running /usr/bin/env who on leehambley@example.com:22
DEBUG [9ce34809] Command: /usr/bin/env who
DEBUG [9ce34809]  leehambley pts/0        2013-06-13 17:11 (port-11262.pppoe.wtnet.de)
 INFO [9ce34809] Finished in 0.420 seconds command successful.
```

## A word about PTYs

There is a configuration option which asks the backend driver to as the remote host
to assign the connection a *pty*. A *pty* is a pseudo-terminal, which in effect means
*tell the backend that this is an **interactive** session*. This is normally a bad idea.

Most of the differences are best explained by [this page](https://github.com/sstephenson/rbenv/wiki/Unix-shell-initialization) from the author of *rbenv*.

**When Capistrano makes a connection it is a *non-login*, *non-interactive* shell.
This was not an accident!**

It's often used as a band aid to cure issues related to RVM and rbenv not loading login
and shell initialisation scripts. In these scenarios RVM and rbenv are the tools at fault,
or at least they are being used incorrectly.

Whilst, especially in the case of language runtimes (Ruby, Node, Python and friends in
particular) there is a temptation to run multiple versions in parallel on a single server
and to switch between them using environmental variables, this is an anti-pattern, and
symptomatic of bad design (i.e. you're testing a second version of Ruby in production because
your company lacks the infrastructure to test this in a staging environment).

## Configuration

The following variables are settable:

| Variable Name         | Description                                                          | Notes                                                           |
|:---------------------:|----------------------------------------------------------------------|-----------------------------------------------------------------|
| `:repo_url`           | The URL of your Git repository                                       | file://, https://, or ssh:// are all supported                  |
| `:git_https_username` | The (optional) username for accessing your Git repository over HTTPS | if this is an SSH connection, this setting will have no effect. |
| `:git_https_password` | The (optional) password for accessing your Git repository over HTTPS | if this is an SSH connection, this setting will have no effect. |
| `:tmp_dir` | The (optional) temp directory that will be used (default: /tmp) | if you have a shared web host, this setting may need to be set (i.e. /home/user/tmp/capistrano). |

__Support removed__ for following variables:

| Variable Name         | Description                                                         | Notes                                                           |
|:---------------------:|---------------------------------------------------------------------|-----------------------------------------------------------------|
| `:copy_exclude`       | The (optional) array of files and/or folders excluded from deploy | Replaced by Git's native `.gitattributes`, see [#515](https://github.com/capistrano/capistrano/issues/515) for more info. |

## SSHKit

[SSHKit](https://github.com/leehambley/sshkit) is the driver for SSH
connections behind the scenes in Capistrano, depending how deep you dig, you
might run into interfaces that come directly from SSHKit (the configuration is
a good example).

## Licence

The MIT License (MIT)

Copyright (c) 2012-2013 Tom Clements, Lee Hambley

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

ファイル構成


cap install直後にはカレントディレクトリに以下のファイルが生成される。
+-Capfile
+-config
|   |
|   +-deploy
|   |   |
|   |   +-production.rb
|   |   +-staging.rb
|   |
|   +-deploy.rb
|  
+-lib
    |
    +-capistrano
        |
        +-tasks

Capfile


起動時に読み込むファイルなどを定義する。
このファイルの初期内容は以下のとおりである。
# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
#   https://github.com/capistrano/rvm
#   https://github.com/capistrano/rbenv
#   https://github.com/capistrano/chruby
#   https://github.com/capistrano/bundler
#   https://github.com/capistrano/rails/tree/master/assets
#   https://github.com/capistrano/rails/tree/master/migrations
#
# require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
# require 'capistrano/bundler'
# require 'capistrano/rails/assets'
# require 'capistrano/rails/migrations'

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

ここでrequire構文によってインポートされているファイルは以下に存在する。
/usr/local/lib/ruby/gems/2.0.0/gems/capistrano-3.0.1/lib/
require ‘capistrano/deploy’に関してはサンプルファイルであるので、このrequire文はコメントアウトしてしまってよい。

config/deploy.rb


全デプロイ先に共通のパラメータ設定を行う。
デフォルトファイルを編集しても良いが、破棄して新規に作成したほうが早い。
このファイルは中身は空でもよいが、必須である。

config/production.rb


本番環境にデプロイする際のパラメータ設定を行う。
デフォルトファイルを編集しても良いが、破棄して新規に作成したほうが早い。

config/staging.rb


ステージング環境にデプロイする際のパラメータ設定を行う。
デフォルトファイルを編集しても良いが、破棄して新規に作成したほうが早い。

lib/capistrano/tasks/


この階層に拡張子.capでタスクを定義したファイルを作成する。

設定系記法


/usr/local/lib/ruby/gems/2.0.0/gems/capistrano-3.0.1/lib/capistrano/dsl/env.rb
/usr/local/lib/ruby/gems/2.0.0/gems/capistrano-3.0.1/lib/capistrano/configuration.rb
にて多くが定義されている。

set


Capistranoは内部に連想配列を保持しており、そこに特定のキーで値を指定することで、挙動を制御できる。
このメソッドによって値を登録する。


























fetch


キーを指定して、setメソッドで保存した値を取り出す。


role


アプリケーション、データベースなど特定のデプロイグループ(ロール)に対応するデプロイサーバのリストを登録する。
認証方法や認証鍵が異なる場合は、serverメソッドで個別に登録することもできる。


デプロイ先サーバは ユーザ名@ホスト名 の書式で書く。

server


デプロイ先のサーバ情報を登録する。


サーバ情報として渡せるのは以下である。

タスク系記法


namespace


指定した文字列で名前空間を作成し、その内部での定義のスコープを名前空間内にのみ限定する。
Capistranoでは、この空間内で、タスクを定義することで、複数の同名のタスクを定義できる。
それらのタスクは
名前空間:タスク名
として識別される。
名前空間をネストして使用することも可能。


※rakeで実装されているメソッド
/usr/local/lib/ruby/gems/2.0.0/gems/rake-10.1.0/lib/rake/dsl_definition.rb


desc


定義するタスクに説明をつける。
taskメソッドの直前に呼び出す。
ここで記述した内容は cap -T コマンドで使用できるタスクの一覧表示を行った際に表示される。
descで説明を記述していないtaskでも呼び出し可能。



task


タスクを定義するメソッド。


on [SSHKit]


指定したホストに対してSSHを開始する。
通常このメソッドを使用してタスクを定義する。


within [SSHKit]


onメソッドブロック内で使用し、SSH接続先で作業を行うパスを指定する。


invoke


タスク定義内で使用し、他のタスクを呼び出す


execute


ネイティブコマンドを実行する。
コマンドの引数を可変長引数としてこのメソッドに与えることができる。


capture


ネイティブコマンドを実行しつつ、出力結果を返す。
コマンドの引数を可変長引数としてこのメソッドに与えることができる。


any?


setメソッドでパラメータが既に設定されているかどうか

after


特定のタスクの実行後に行うタスクを登録する


capコマンド


Capistranoを使用する際のコマンド。

タスク一覧表示


cap -T

タスク起動


cap <stage> <task>


サンプル


HelloWorld


STAGING_RB=/home/deploy/capistrano/config/deploy/staging.rb
echo "set :stage, :staging" > $STAGING_RB
echo "role :app, %w{deploy@<デプロイ先サーバ1、デプロイ先サーバ2、、、>}" >> $STAGING_RB
# 例:echo "role :app, %w{deploy@127.0.0.1}" >> $STAGING_RB

TEST_CAP=/home/deploy/capistrano/lib/capistrano/tasks/test.cap
echo "namespace :test do" > $TEST_CAP
echo "  desc 'echo Hello'" >> $TEST_CAP
echo "  task :hello do" >> $TEST_CAP
echo "    on roles :app do" >> $TEST_CAP
echo "      execute :echo, 'Hello'" >> $TEST_CAP
echo "      execute 'pwd'" >> $TEST_CAP
echo "    end" >> $TEST_CAP
echo "  end" >> $TEST_CAP
echo "end" >> $TEST_CAP

cap -T
# test:helloが追加されていることを確認 ※cap installしたディレクトリで実行

cap staging test:hello


SVNアップデート


チェックアウトを事前に行っておく。




特定の環境のみ実行


task :XXX do
	if fetch(:stage).to_s == "staging"
	~~~
	end
end

Notice: Trying to get property 'queue' of non-object in /usr/local/wordpress/wp-includes/script-loader.php on line 2876

Warning: Invalid argument supplied for foreach() in /usr/local/wordpress/wp-includes/script-loader.php on line 2876