2008-12-18

Capistrano は思ったよりシンプルで思ったよりすごい

システム管理者のみなさん、こんにちは。今日は Rails アプリの deploy ツールとして有名な(らしい)Capistrano についてです。紹介? いえいえ。紹介はすでに有名な人たちによってなされています。ワタシがしたいのは検討。こいつはどこにどのように使えそうか。

Capistrano: Home

システム管理の話なのになんで Puppet じゃないの?と思うかもしれません。それは、以前 Puppet の OSX 対応があまりよくなかったことと、また自分の環境が PPC Mac だったため、仮想マシンを使って他の OS を動かすのも現実的でなく、面倒になってしまっていたからです。

で、巡り巡って Capistrano って実は deploy 以外にも結構使えそうじゃない?と思えましたよというお話。想定しているバージョンは Capistrano 2.5.3 です。

なお、例によって嘘書いてる可能性があります。識者のツッコミお待ちしております。

Capistrano の動作に必要なのは Ruby と ssh だけ

  • Puppet は daemon をいくつか用意してやる必要があります。
    • https を使ってくれるので fw friendly ですが、それにしたっていろいろ準備が必要です。
  • Capistrano の準備で大事なのは以下の2点だけ。
    • Capistrano1 をセットアップする1台のマシン
    • 管理される方のマシンには sshd と作業用の ssh アカウント

しかも Puppet と違い C/S 方式ではないため、Capistrano のセットアップが必要なマシンは1台だけです。

なんか、ちょっとお手軽な感じがしませんか。

Capistrano 自体は Windows でも動く

依存している gem パッケージは以下の通り。

$ gem dependency capistrano
Gem capistrano-2.5.3
  net-ssh (>= 2.0.0, runtime)
  net-sftp (>= 2.0.0, runtime)
  net-scp (>= 1.0.0, runtime)
  net-ssh-gateway (>= 1.0.0, runtime)
  highline (>= 0, runtime)
  echoe (>= 0, runtime)

あと echoe がこんな感じ。2

$ gem dependency echoe
Gem echoe-3.0.2
  rake (>= 0, runtime)
  rubyforge (>= 1.0.0, runtime)
  highline (>= 0, runtime)

ext なライブラリはないので Capistrano 自体は Windows でも動かせます。3自分で実際に確認はしてないですけど、動かしている例は探せばすぐ見つかります。

ただ管理対象は ssh でなんでもできる Un*x 系システムじゃないと Capistrano の利用に旨味はないでしょう。

要するにできることは ssh HOST COMMAND

ssh は interactive な login shell を提供するだけではなく、

ssh HOST COMMAND

の形で

HOST に接続して COMMAND に書かれた処理を実行して終了する

という使い方もできます。大雑把に言うと Capistrano はこの機能をより便利に使うために

  • 接続先の管理と接続の自動化
  • 接続先と作業内容のセットをタスクで管理
  • タスクの実行

を提供してくれるものです。そして

そのために Rake によく似た DSL を使う

ようになっています。

deploy ツールとして紹介されることの多い Capistrano ですが、それは deploy 用のタスクがあらかじめ定義されていて、変数をセットするだけで便利に使えるようにしてあるからであって、

タスクを用意すれば ssh でできる仕事はなんでもできますし、remote の仕事だけでなく local の仕事もできます。

たぶん。

ただし、Puppet と違い、接続先のサーバ OS の抽象化などは行ってくれないため、基本的にその部分は生で相手しないといけません。逆に Puppet のように独自文法の習得を要求しません。

ということは従来の方法からの移行コストが小さい

まともな管理者なら、サーバ上のたいていの作業は sh や Perl、Ruby などのスクリプトである程度自動化されていると思います。これが cron ジョブとして管理できるなら手作業はずいぶん減っているはずです。ただ、

完全に定期実行になっていない作業

も中にはあるでしょう。その場合、しぶしぶ個々のサーバにログインしてスクリプトを実行していませんか? 恥ずかしながら自分はそうです。しかし Capistrano を導入すれば

最後の「ログイン -> 実行」の部分を自動化、管理できます。

そうです。個々のサーバの管理方法を大幅に変える必要はありません。「ログイン -> 実行」という、最後に残った手作業部分を Capistrano のタスクとして管理できるようになるだけなのです。しかもサーバ側は基本的にいじる必要がありません。

これが複数のサーバ上の作業なら目に見えて楽になりますし、サーバの数がそれほど多くなくても

一定のワークフローを保証しやすくなります。

つまり

管理作業の共有、引き継ぎを楽にしてくれます。

もちろん独自タスクの管理のためには Ruby と Rake への理解を要求するので、楽になる一方ではありません。しかも Rake も Capistrano もそんなにドキュメントが充実しているわけでもありません。しかし、スクリプトを書いて自動化して、手作業によるミスを減らせるようにしてあるはずなのに、なんとなく属人的な作業が残っちゃう部分があって、なんか気持ち悪いなぁと感じているような場合には Capistrano の導入は十分に検討の価値があるんじゃないでしょうか。

超簡単な例

えーと概念の話からインストールの方法をすっ飛ばしていきなり実例に入ります。4

カレントディレクトリに以下のような内容で Capfile という名前のファイルを作ってください。ここでログイン先のサーバのユーザー名、パスワードは一致しているものとします。

role :server, 'server1, 'server2'

set :user, 'user'
set :password, 'password'

desc "reporting disk usage with 'df -h'"
task :check_disk, :roles => :server do
  run 'df -h'
end

cap check_disk

と実行すると

 * executing `check_disk'
 * executing "df -h"
   servers: ["server1", "server2"]
   [server1] executing command
   [server2] executing command
** [out :: server1] Filesystem            Size  Used Avail Use% Mounted on
** [out :: server1] /dev/xvda1             32G   24G  7.2G  77% /
** [out :: server1] tmpfs                 201M     0  201M   0% /dev/shm
** [out :: server2] Filesystem            Size  Used Avail Use% Mounted on
** [out :: server2] /dev/mapper/XXX        17G   14G  2.1G  88% /
** [out :: server2] /dev/xvda1             99M   27M   67M  29% /boot
** [out :: server2] tmpfs                 181M     0  181M   0% /dev/shm
   command finished

みたいな結果が得られます。つまり、server1, server2 にログインして実際に df -h した結果をそのまま、Capistrano をインストールしたマシン上で確認できたということです。

どうです、なかなか面白くないですか。

情報収集が楽になるはず

これはちょっといきすぎてるかな?と思わなくもないのですが、cron ジョブの実行を Capistrano マシンに集中させることも可能ですね。こうすると

  • 個々のサーバで crond が不要
  • cron ジョブのレポートメールを Capistrano マシン上に集約可能
  • cron ジョブの様子を一カ所で確認できるので、スケジュールを考えやすくなる

というメリットがあります。もちろんデメリットや不安材料もあって、

  • ssh login のコスト
  • 長い時間掛かる仕事をさせたときの ssh connection はどうなる?

なんかが気になるところです。まだ見落としてることもあるかもしれません。

cron のレポートの受け取りが面倒くさい

ただ、cron はレポートのメールの受け取りが面倒だなと以前から感じていたので、この問題を解決しやすくなるとしたらとても嬉しいです。というのも、cron のレポートは基本的にローカルのアカウントにメールされるのですが、

どうやって読むの?

という問題がつきまといます。今思いつくのは

  1. 個々のサーバにログインして読む
  2. 個々のサーバに POP サーバ立てる
  3. forward する
  4. mail -> html -> feed 変換して feed reader で読む

くらいですかね。数が増えてくれば当然 1, 2 はナシだと思うんですが、

forward する場合、forward 先のサーバには SMTP サーバと SMTP の通る穴が必要

になります。これがまた悩ましい。メールサーバが LAN 内にあるなら LAN 内のレポートは文句なし LAN 内のメールサーバで処理すればいいです。でもインターネット向けに公開しているサーバのメールはどうしましょう? LAN 内のサーバ向けに forward ? fw で閉じてませんか? じゃあインターネット上の SMTP サーバに転送? OBP25 とかに引っかかりませんか? それにインターネット上に置いた SMTP サーバはあっという間に spam やエラーメールの嵐に飲み込まれてしまいます。すると今度は spam filter だ anti virus だ…。ふー。違うんだよ、オレはそんなことしたいんじゃないの。要するに

forward も意外に面倒なのです。

もう一つ、メールったってこんなの返信の必要もないし、みんな feed reader で読みたいなぁと以前から思っていました。実際、mail -> html -> feed 変換をしている人は見かけます。HTML にして URI が付けば内容の共有も楽です。5しかしどうしても転送の部分がネックになります。各サーバで feed 吐いてそれpla で収集してもいいですけど、なんかそれもどうなんだと。

でも Capistrano からタスクを実行すれば、自動的に、少なくとも stdout や stderr の内容は取得できます。結果をファイルに落とすタイプでもファイルの転送が可能6なのでそれを取得してくればオッケーです。

てことは、レポートの収集の部分は自動的にクリアしてしまいます。おう、なんかこれ面白そうじゃん。

できそうなことの一覧

クラスの一覧から一部を抜粋。

Capistrano::Configuration
Capistrano::Configuration::Actions
Capistrano::Configuration::Actions::FileTransfer
Capistrano::Configuration::Actions::Inspect
Capistrano::Configuration::Actions::Invocation
Capistrano::Configuration::Actions::Invocation::ClassMethods
Capistrano::Configuration::Callbacks
Capistrano::Configuration::Connections
Capistrano::Configuration::Execution
Capistrano::Configuration::Loading
Capistrano::Configuration::Loading::ClassMethods
Capistrano::Configuration::Namespaces
Capistrano::Configuration::Namespaces::Namespace
Capistrano::Configuration::Roles
Capistrano::Configuration::Servers
Capistrano::Configuration::Variables
Capistrano::Deploy
Capistrano::Deploy::Dependencies
Capistrano::Deploy::LocalDependency
Capistrano::Deploy::RemoteDependency
Capistrano::Deploy::SCM
Capistrano::Deploy::SCM::Accurev
Capistrano::Deploy::SCM::Accurev::InternalRevision
Capistrano::Deploy::SCM::Base
Capistrano::Deploy::SCM::Base::LocalProxy
Capistrano::Deploy::SCM::Bzr
Capistrano::Deploy::SCM::Cvs
Capistrano::Deploy::SCM::Darcs
Capistrano::Deploy::SCM::Git
Capistrano::Deploy::SCM::Mercurial
Capistrano::Deploy::SCM::None
Capistrano::Deploy::SCM::Perforce
Capistrano::Deploy::SCM::Subversion
Capistrano::Deploy::Strategy
Capistrano::Deploy::Strategy::Base
Capistrano::Deploy::Strategy::Checkout
Capistrano::Deploy::Strategy::Copy
Capistrano::Deploy::Strategy::Export
Capistrano::Deploy::Strategy::Remote
Capistrano::Deploy::Strategy::RemoteCache

いやーこうして見ると Deploy の充実っぷりがやはりすごいですね。Mercurial や Bzr なんて文字も見えるので、これらを使った deploy もできるんでしょう。

使えそうなリソース

Capistrano 自体が github でホスティングされているためか、github で検索するといちばんたくさん引っかかるようです。

あとはシステム管理系のレシピが載ってそうなところとか。まだあんまちゃんと見てないですけど。

最後に。

みんな、実際に試してオラにやり方を教えてくれ!

  1. 当然、Ruby も必要 

  2. これ recursive に取れないのかな? もしかして使ってる gem が古い? 

  3. 公開鍵認証を利用するための鍵作成には Putty などの ssh クライアントがたぶん必要です。 

  4. 実際、rubygems さえ動いていればインストールはそれくらい簡単です。 

  5. 例えば管理用のメールを複数人で受信していて、何か気になるアラートがあったとします。この情報を共有したいわけですが、メールを一意に特定するのは Message-ID です。しかし Message-ID の確認や検索の容易なメーラーは寡聞にして知りません。 

  6. やり方はまだ分かってません! 

About

例によって個人のなんちゃらです