Capistrano による Deploy

信頼性の高いシステムを構築

課題として、以下があります。

  1. デプロイ方法の確立
  2. テスト技法の確立

今回はデプロイに関連して、Capistrano を使ったリモートサーバでのタスク実行について調査してみました。

現状のデプロイ法

テストサーバから本番サーバへ Rsync

Rsync については以下に記述あり。

Rsync は以下のようなスクリプトを書いて実行できる。

#!/bin/sh
rsync -av $1 /path/to/yourapp/ \
      haida@deploy_to_server:/path/to/deploy_to/ \
      --exclude='tmp/cache/*' \
      --exclude='tmp/pids/*' \
      --exclude='tmp/sessions/*' \
      --exclude='tmp/sockets/*' \
      --exclude='log/*' \
      --exclude='*.fuse_hidden*' \
      --exclude='*~' \
      --exclude='.svn'

"--link-dist" オプションを考慮すると尚 Good。

  • 問題点
    • 各プロジェクト毎に専用の deploy スクリプトを書いている
      • 通化した方がオーバーヘッドが減少するはず
    • サーバ台数が増加してくると deploy スクリプトのメンテナンスが大変

Capistrano

デプロイツールとして Capistrano を検討してみる。
Capistrano のバージョンは 1.x 系と 2.x 系があり、バージョン間で結構異なるようだ。
以下では、2.x 系の説明をする。

Capistrano is...

  • Great for automating tasks via SSH on remote servers, like software installation, application deployment, configuration management, ad hoc server monitoring, and more.
  • Ideal for system administrators, whether professional or incidental.
  • Easy to customize. Its configuration files use the Ruby programming language syntax, but you don't need to know Ruby to do most things with Capistrano.
  • Easy to extend. Capistrano is written in the Ruby programming language, and may be extended easily by writing additional Ruby modules.
Capistrano: Home
  • Capistrano とは、、
    • SSH 経由でリモートサーバへのタスクの自動化ツール
    • ソフトウェアのインストール、APP デプロイ、設定管理、アドホックなサーバの監視などに利用できる
    • カスタマイズ簡単
      • 設定ファイルは Ruby 記法を使っているけれど、Ruby についての深い理解は必要はなし
    • 拡張簡単
      • Ruby のモジュールを書いて簡単に拡張できる
    • サーバにログインしては小さなシェルスクリプトを書く手間を省略する

Exit Tedium.

  • Simply put, Capistrano is a tool for automating tasks on one or more remote servers.
  • It executes commands in parallel on all targeted machines, and provides a mechanism for rolling back changes across multiple machines.
  • It is ideal for anyone doing any kind of system administration, either professionally or incidentally.
Capistrano: Home
  • 退屈からの脱出
    • Capistrano は 1 つ以上のリモートサーバにおけるタスクの自動生成ツール
    • ターゲットサーバで、コマンドを並列実行する。
    • 複数サーバにおけるロールバック機能を装備

Capistrano was originally written to ease the pain of deploying Rails applications.
Although it can be (and is) used for a lot more than that now, Rails application deployment is still the primary way that most people use Capistrano, at least initially.

Capistrano: Getting Started
  • Rails APP のデプロイ軽減のために作成されたもの。
  • Rails APP 以外の用途にも利用できる。

インストール

RubyGems で ok。

# gem install capistano

前提条件

Capistrano の利用に際し、以下の前提条件をクリアしているか確認する。

  • リモートマシンへ SSH できること(FTP, telnet は× )
  • POSIX 互換のシェルがインストールされていること
    • シェルは sh でかつ、デフォルトのシステムパスにあること
  • サーバに共通の公開鍵でアクセスできること
    • 鍵には破られにくいパスワードをつけておくこと
    • 公開鍵ではなく全サーバ共通のパスワードでも良いが、公開鍵を利用した方がセキュリティ上より良い
  • コマンドラインでの操作や Ruby には慣れていた方が良い

Capfiles

  • Capfile から Capistrano に指示
  • Capfile には接続先のサーバとそのサーバ上でのタスクを Ruby で記述
    • ヘルパ記法によって簡単に記述できる

簡単な例

Rake の記法については、Rake ことはじめ を参照。

task :search_libs, :hosts => 'www.capfy.org' do
  run 'ls -x1 /usr/lib | grep -i xml'
end

www.capfy.org で指定されるサーバの /usr/lib 以下で xml という文字列を含む ファイル、またはディレクトリ名を表示する。
run はコンソールに出力を表示する。
前述のプログラムを、 Capfile として保存し、cap コマンドの引数にタスク名を与えて実行する。

# cap search_libs

この要領でタスクをどんどん追加できる。

task :search_libs, :hosts => 'www.capfy.org' do
  run 'ls -x1 /usr/lib | grep -i xml'
end

# /usr/lib 内のファイル数 (サブディレクトリ 1 つも数に加える) を出力
task :count_libs, :hosts => 'www.capify.org' do
  run 'ls -x1 /usr/lib | wc -l'
end

ロール

前述のプログラムに Role を追加して、サーバの宣言を一箇所に固める。

role :libs, 'www.capify.org'

task :search_libs do
  run 'ls -x1 /usr/lib | grep -i xml'
end

# /usr/lib 内のファイル数 (サブディレクトリ 1 つも数に加える) を出力
task :count_libs do
  run 'ls -x1 /usr/lib | wc -l'
end

ゲートウェイ登録

多くのデプロイのケースではゲートウェイの設定が必要である。
Capistrano では role と同じ要領でゲートウェイを登録する。
以下では、crimson.capify.org は NAT 越しにあるとする。以下のスクリプトにより、Capisrtano はゲートウェイへのコネクションを作り、続くコネクションをトンネリングする。

set  :gateway, 'www.capify.org'
role :libs, 'crimson.capify.org'

複数サーバに対応

複数サーバに同様の役割を持たせるには、以下のようにロール名の後ろにサーバ名を "," 区切りで記述する。

role :libs, 'crimson.capify.org', 'magenta.capify.org'

これを使い、サーバごとの役割を記述する Capfile は以下のようになる。

role :libs, 'crimson.capify.org', 'magenta.capify.org'
role :files, 'fuchasia.capify.org'

task :search_libs, :roles => :libs do
  run 'ls -x1 /usr/lib | grep -i xml'
end

task :count_libs,  :roles => :libs do
  run 'ls -x1 /usr/lib | wc -l'
end

task :show_free_space, :roles => :files do
  run 'df -h /'
end

もし複数のロールに同様のタスクを割り当てたい場合は以下のように roles オプションに配列で渡す。

task :do_something, :roles =>[:libs, :files]
.....
end

ドキュメンテーション

Rake と同じように、description を記述すると、タスクコレクションを参照するコマンド "cap -T" により表示される。
先程作成した cap ファイルに以下のように description を加えてみる。

role :libs, 'crimson.capify.org', 'magenta.capify.org'
role :files, 'fuchasia.capify.org'

desc 'Search /usr/lib for files named xml.'
task :search_libs, :roles => :libs do
  run 'ls -x1 /usr/lib | grep -i xml'
end

desc 'Show the number of entries in /usr/lib.'
task :count_libs,  :roles => :libs do
  run 'ls -x1 /usr/lib | wc -l'
end

desc 'Show the amount of free disk space.'
task :show_free_space, :roles => :files do
  run 'df -h /'
end

次に、 "cap -T" コマンドを叩くと以下のようにタスク名とともに description が参照可能になる。

# cap -T
cap count_libs      # Show the number of entries in /usr/lib.
cap invoke          # Invoke a single command on the remote servers.
cap search_libs     # Search /usr/lib for files named xml.
cap shell           # Begin an interactive Capistrano session.
cap show_free_space # Show the amount of free disk space.

Extended help may be available for these tasks.
Type `cap -e taskname` to view it.

上記のように、自分で作成したタスクの他に、"invoke", "shell" というタスクがあることが分かる。
これらのタスクは Capistrano ではいつでも参照可能である。

cap invoke

invoke タスクは、上記のようにタスクを記述した Capfile を用意しなくてもリモートサーバでコマンドを発行できるタスクである。
以下のように、role だけ記述した Capfile を用意しておく。

role :staging, 'example.org'

staging で実行したいコマンドを以下のように COMMAND パラメータを通じて渡す。

# cap invoke COMMAND='df -h'
  * executing `invoke'
  * executing "df -h"
    servers: ["example.org"]
    [tsudoi.jp] executing command
 ** [out :: example.org] Filesystem            Size  Used Avail Use% Mounted on
 ** [out :: example.org] /dev/simfs             20G  1.4G   19G   7% /
    command finished

ロールを明示的に指定して実行する場合には、ROLES パラメータとして渡す。

# cap invoke COMMAND="df -h" ROLES=staging
.....

HOSTS パラメータを使ってホスト名を明示的に指定することも可能。

# cap invoke COMMAND="df -h" HOSTS=example.org
.....

cap shell

invoke タスクではコマンド毎にリモートサーバへの接続が必要だが、shell コマンドは shell セッション中、コネクションをキャッシュして再利用可能にする。利用例を見た方が早い。

# cap shell ROLES=staging
  * executing `shell'
====================================================================
Welcome to the interactive Capistrano shell! This is an experimental
feature, and is liable to change in future releases. Type 'help' for
a summary of how to use the shell.
--------------------------------------------------------------------
cap> touch hello.txt
cap> ls -l hello.txt
 ** [out :: exmple.org] -rw-rw-r--  1 haida haida 0 Dec 10 07:24 hello.txt
cap> rm hello.txt
cap> ls -l hello.txt
*** [err :: tsudoi.jp] sh: cap: command not found
error: command "cap hello.txt" failed on tsudoi.jp
cap> exit;
exiting
# 

Namespaces

Rakefile と同様。タスクの名前空間を設定しておくとタスクが増えたときに便利。

namespace :libs do
  task :search, :roles => :libs do
    run 'ls -x1 /usr/lib | grep -i xml'
  end

  task :count,  :roles => :libs do
    run 'ls -x1 /usr/lib | wc -l'
  end
end

namespace :disk do
  task :free, :roles => :files do
    run 'df -h /'
  end
end

名前空間を設定したタスクは以下のように実行する。

#cap libs:search

変数

変数を利用することで再利用性や拡張性を高めることができる。

role :staging, 'example.org'
set :term, 'xml'

task :serach, :roles => :staging do
  run "ls -x1 /home/haida | grep -i #{term}"
end

変数の設定は、set メソッドで指定する。

set 変数名(シンボル指定) 値

これを以下のように、コマンドラインから指定できるように変更する。

set(:term) do
  print "Gimme a search term: "
  STDOUT.flush
  STDIN.gets.chomp
end

さらに、Capistrano に用意されているヘルパメソッドを利用すると簡潔になる。

set(:term) do
 Capistrano::CLI.ui.ask 'Gimme a search term: '
end

変数は cap コマンドの "-s" または "-S" オプションを利用して、以下のようにコマンドラインから指定することも可能。

cap -s term=cap libs:search

"-s" と "-S" の違いは、

  • "-s" (小文字) は全ての Capfile ロード後にセットされる
  • "-S" (大文字) は全ての Capfile ロード前にセットされる (後で上書きされるかもしれない。)

トランザクション

デプロイ中にアクシデントが発生した場合、他のサーバに加えた処理を全て元の状態にロールバックする必要がある。
こうした場合は transaction を導入を考える。

task :deploy do
  transaction do
    update_code
    symlink
  end
end

task :update_code do
  on rollback { run "rm -rf #{release_path}"}
  source.checkout(release_path)
end

task :symlink do
  on_rollback { run "rm #{current_path}; ln -s #{previous_release} #{current_path}"}
  run "rm #{current_path}; ln -s #{release_path} #{current_path}"
end

上記のコードでは、 deploy タスクがトランザクションをラップし、update_code と symlink タスクを実行する。
実行中の異常を検知すると、on_rollback が逆順に実行される。

このようにトランザクション処理は Capistrano が自動実行するのではなく、開発者が定義する。

ロードファイルの指定

Capfile を複数ディレクトリに配置した場合は以下のようにロードパスを指定して読み込む。

load "libs"
load "files"

これだとカレントディレクトリを基点に見ることになるので以下のように指定することもできる。

load_path << "config/stages"

勿論コマンドラインからも指定可能で、その場合は、"-f ファイル名" または "-F" オプションを使う。

cap -f libs libs:search

"-f", "-F" オプションの違いは次の通り。

  • "-f" (小文字) : デフォルトの -f で指定された指定されたファイルのみロードする
  • "-F" (大文字) : デフォルトの Capfile (カレントディレクトリの Capfile) のみロードする。

アウトプットを出し続けるために

ベンチャー企業にいると常にアウトプットを出すことことを求められる。エンジニアとして優れたアイディアを出し、プログラムを書けなければならないと感じている。仕事が増加するなかでも良いアウトプット出し続けるために、意識的に自分の中に蓄積すべきことは、以下になる。

  1. フレームワーク
  2. 思考法の確立
    • 悩むべは思考法ではなく、対象の問題
    • アイディアの 2 段階抽象法

アイディアの 2 段階抽象法

ものを作る前にアイディアを企画にまで落とし込む必要がある。企画に落とすまでに通る道を意識しておくこと。

  • 準備段階: Research
    • 目的を達成するのに助けとなる情報を収集する段階
      • 調査のためのフレームワークが活躍
      • 調査項目は事前に準備し、機械的になるべく多くのショーケースを調査
      • 日頃からコピペで済むような、自分なりのデジタルデータを作成
  • 第一段階: Feel
    • 気になる情報を全て吐き出す段階
  • 第二段階: Think
    • 情報同士を結びつけてアイディアを考える段階
      • 第一段階で生まれた発想を抽象化して分類し掛け合わす作業
      • オズボーンのチェックリストや、情報を分類し、図示する技術

企画会議

発想会議をやり、次に決定会議。この両方を意識しながら進めること。

Web 進化論

僕がこの業界に入ってから最初に感銘を受けた本が、昨年の 8 月くらいに読んだ、梅田望夫 による Web 進化論だった。
その本を久々に引っ張り出して見つけたこの一節。

ここ数年考え続けてきたことをまとめればいいと分かっていても、さまざまな指向の断片を一冊の本へと構造化させるには膨大な集中の時間を要する。そのことは、書き始める前から想像がついていた。私の場合、日々の仕事の制約から、ほとんど人に会わずに一つのことに集中できるのは長くても五週間である。そこで、五週間精一杯ベストを尽くし、それでもまとまらなければ仕方ないと腹をくくり、毎朝午前 3 時に起床し、原則として午前中一杯を集中の時間に充てた。全部書き終えたときはふらふらだったし、今振り返ると、その五週間についての記憶が曖昧である。そんな風にしてこの本はできあがった。

この創作への姿勢が素晴らしいと思った。

僕が思うに、この本の素晴らしさは、Google という、良くも悪くも現代では無視できない巨大なパワーについて、そして Google を中心としたネットの世界について、一般の人が関心を持ち、さらには行動を起こさせてしまうほど見事に、構造化し、切ってみせたところだと思う。

梅田さんがプログラムを書いたとか、書いていないとか、そんなことでこの本を評価すべきではないと思うし、その創作に対する姿勢は、適当な気持ちで日々を過ごすプログラマには足元にも及ばないだろう。

そして僕が没頭し、新しいメディアを生み出していくための、モチベーションとなっている。

人力検索 (Human Powered Search)

人力検索のサイトって意外に沢山ある。

実際,New York Times紙は,2007年1月時点でシリコンバレーには新しい検索サービスに挑戦する企業が少なくとも79社は存在し,そこにベンチャー・キャピタルから 3 億 5000 万ドル(約 390 億円)が注ぎ込まれていると報じている。これらの中には,自然言語検索の Powerset やhakia,あるいは人力検索のMahalo.comやChaCha Searchなど,従来とは全く異なるアプローチで検索エンジンに取り組む企業もいくつかある。
意外な角度から斬り込んでくるだけに,当たればGoogleに相当の痛手を負わすポテンシャルを秘めている。

Google対抗馬の一番手,人力検索エンジン「WikiaSearch」がまもなく登場

人力検索サイトを調査

How to create a great website

偉大なサイトの作り方。今後のために訳しておこう。

Here are principles I think you can’t avoid:

How to create a great website

1. Fire the committe.
No great website in history has been concieved of by more than three people.
Not one.
This is a deal breaker.

委員会を解散しろ。歴史上偉大ないかなるウェブサイトも 3人以上で作成されたことはない。 1 つもない。これは厄介な問題だ。

2. Change the interaction.
What makes great websites greate is that they are simultaneously effortless and new at the same time.
That means that the site teaches you a new thing or new interaction or new connection, but you know how to use it right away.
(Hey, if doing this were easy, everyone would do it.)

相互作用(インタラクション)を変更せよ。偉大なサイトを偉大なものとしているのは、それらが、簡単そうな感じであると同時に新しいからだ。つまり、それら偉大なサイトは新しいこと、新しいインタラクション、新しいコネクションを提示しながら、使い方もすぐ分かるものなのだ。

3. Less.
Fewer words, fewer pages, less fine print.

より少なく。より少ない言葉、ページ、但し書き。

4. What works, works. Theory is irrelevant.

秘訣は働くこと。理論は無関係だ。

5. Patience.
Some sites test great and work great from the start. (Great if you can find one).
Others need people to use them and adjust to them.
At some point, your gut tells you to launch.
Then stik with it, despite the critics, as you gain traction.

忍耐。いくらかのサイトは、始めからテストも上手くいき、上手く動く。その他のサイトは利用する人を必要とし、彼らに合わせていく。どこかのポイントで、もう手放したくなるかもしれない。批判されても手放さず、徐々に力をつけていけ。

6. Measure. If you're not improving, if the yield is negative... kill it.

計測せよ。もし改善せず、成果がネガティブなものなら、やめてしまえ。

7. Insight is good, clever is bad.
Many websites say, "Look at me."
Your goal ought to be say, "here's what you were looking for."

洞察や良いが、巧妙であってはだめだ。多くのウェブサイトは「こっちを見て」と言う。あなたの目標は、「ここにあなたの探しているものがありますよ。」というようなものであるはずだ。

8. If you hire a professional: hire a great one. The best one.
Let her do her job.
10 mediocre website consultants working in perfect harmony can't do the work of one rock star.

プロフェッショナルを雇用するなら最高の一人を雇用せよ。その人にその人の仕事をさせよ。10 人の 2 流のコンサルタントの完璧な調和も一人のロックスターの仕事はできない。

9. One voice, one vision.

ひとつの言葉、ひとつのビジョン。

10. Don’t settle.

立ち止まらない。