明日はじめるCapistrano

投稿者 akira 2010-03-03 10:13:00 GMT

Railsのdeployに使われることで知られるようになったCapistrano。でもその実態はRailsにとらわれているわけではありません。Capistranoは何かというと、こう言えます。SSHを使って多数のホストに同時並列に接続して、実行させたいコマンドを一斉に送信、実行結果を受け取って問題なければ次のコマンドを、というのを行うためのフレームワークです。

Capistranoを使い始めるのは簡単です。受け側に必要なものがあまりなく、一般的なUNIX系環境であればすでに準備が整っている状態です。Capistranoを実行するホストにはRuby環境が必要ですが、それ以上のものは基本的には必要ありません。コンパイラも不要ですし、ちょっと試してみるだけならインストールしてなくても大丈夫。

iptablesのstringモジュールでバイト列にマッチさせる

投稿者 akira 2009-12-22 01:59:00 GMT

特定の内容の通信だけを遮断したくなり、きっとiptablesに何かあるだろうと調べたらstringモジュールがあった。iptables 1.4.6のmanpageから引用する。

   string
       This  modules  matches  a  given  string by using some pattern matching
       strategy. It requires a linux kernel >= 2.6.14.

       --algo {bm|kmp}
              Select the pattern matching strategy. (bm = Boyer-Moore,  kmp  =
              Knuth-Pratt-Morris)

       --from offset
              Set the offset from which it starts looking for any matching. If
              not passed, default is 0.

       --to offset
              Set the offset from which it starts looking for any matching. If
              not passed, default is the packet size.

       [!] --string pattern
              Matches the given pattern.

       [!] --hex-string pattern
              Matches the given pattern in hex notation.

遮断の条件に指定したい内容が非ASCIIのバイト列だったので--hex-stringを指定した。--hex-string 'e7a781e381aee5908de5898de381af...'のように。ところがうまくいかず、ありそうな書式をいくつか試しても変わりがない。ふと、試しに、文字列をそのまま(16進数表記にせずに)指定したところ、当初の意図の通りにマッチした。

どうやら何かの書式があるらしいと、iptablesのコードにあたったところ、以下のルールに従ってバイト列に変換されることがわかった。

  • |」にはさまれた部分はバイト列の16進数表記として処理される
  • それ以外の部分にある文字はその文字自身を表す
  • ただし「\」により続く文字の特別な意味をキャンセルできる(「\|」や「\\」)

先の例については--hex-string '|e7a781e381aee5908de5898de381af...|'とするのが正しいやり方となる。また、--hex-string 'a|62|c'は「abc」にマッチし、--string abc--hex-string abcを指定したのと同じ結果となる。指定できるバイト列の長さ(変換後の長さ)は128バイトまでのようだ。

--from--toの指定を加えると、マッチ対象とする範囲を指定できる。--from 20ならTCPヘッダ(など)以降(〜65535バイト目まで)が対象となり、特に指定しなければIPパケットの先頭から65535バイト目までが対象範囲となる。

Passengerで本当にあった○○な話

投稿者 akira 2009-11-08 03:36:00 GMT

Passengerを使っていて実際にやってしまったダメーな思い出話。(けっこう前のことなので今の状況とは少し違うかも。)

間違ったキャッシュが返る

この日記にはtDiaryからTypoに移行したという経緯がある。移行のためのあれやこれの手間はかかったものの、一通りの作業を終えるとおとなしく動作していた。

ところが、ある時、ブラウザからのアクセスにatomデータを返していることに気付いた。動作を追ってみると、どうも何かの加減で間違ったキャッシュファイルがレスポンスに使われているように見える。そこで、とりあえずの回避策として、生成されていたatomキャッシュを削除した。するときちんとhtmlデータが返されるようになり、新たにhtmlのキャッシュファイルが生成されていることを確認できた。

気になって調べてみると、atomキャッシュだけが生成されているページが他にもいくつかある。先にatomへのアクセスがあれば当然このようになるわけなので、それ自体は問題ないはず。だが、これがあるとhtmlで返すべきところが返らなくなってしまうようだ。

ある期間この現象は困った謎のままであった。まったく見られなくなるわけでもなく、ともかくは動いているということもあって、場当たり的な対処を繰り返して過ごしてきた。

ここでTypoが作るキャッシュを考えてみる。Typoは生成するレスポンスによってhtml、atom、rssなどのキャッシュをファイルとしてpublic以下に作る。これらのファイルは、Passengerの通常通りの動作としてTypoが関与することなくレスポンスに使われる。したがって、問題のhtmlリクエストに対してatomデータを返している容疑者はTypoではなくPassengerかApache HTTPサーバである。ということに、かなり時間をかけた上で気付いた。

もう少し正確に言うと、ようやくそこに目を向けることができた、という感じかもしれない。となれば、まっ先に疑うべきであった点が一つ。MultiViewsだ。

ところで、前述の通り、この日記はtDiaryからTypoに移行した。tDiaryのときの設定は以下のようなものだった。

Alias /diary /path/to/diary
<directory /path/to/diary> # tDiary
  Options -MultiViews
</directory>

これをTypo+Passengerにかえた際に、/path/to/document_rootから/path/to/diary/publicへのシンボリックリンクを作成した上で、次のように変更した。(実際にはtDiary→Typo+FCGI→Typo+Passengerと設定を変えてきているため、その跡が少し残っている。)

#Alias /diary /path/to/diary/public
<directory /path/to/diary/public> # Typo
  Options -MultiViews
</directory>

気持ちの上ではMultiViewsはオフのままにしたつもり。だが、もちろん、そんなことはなく、/path/to/document_rootで有効になっているMultiViewsは/path/to/document_root/diaryでも有効になる。そしてTypoが作り出すURLには拡張子がついていない。ブラウザからのアクセスは/diary/fooに対するものとなる。この時htmlキャッシュがなくて、atomキャッシュやrssキャッシュがあれば。そう、MultiViewsの機能により(もちろん設定にもよるが)htmlではなくそれらのデータがレスポンスとして送信されてしまうのであった。

Passengerじゃない!

FastCGIで動作させていたあるRailsアプリケーションをPassengerで動かすことにした。ところが、なかなか作業がはかどらない。移行をしているせいもあって、いろいろやってみたあげく、変わらずFastCGIで動いてしまうというのを何度か繰り返していた。

と、ここで、FastCGIを動かなくしてしまえばよいではないかと思い付いた。そもそもPassengerに移行した後はFastCGIを使わないのであるから、これはどちらにしても良いことである。

さっそくそのようにしてみたところFastCGIで動作することはなくなった。

よかった、よかった。別の作業に取りかかろう。……あれ? なんだか重い? アプリケーションは動いてはいる。エラーも出ていないし、返ってくるデータにも問題はない。だけど、あれ? レスポンスがものすごく悪い?

FastCGIのプロセスがなくなったことで安心してしまったが、そういえばPassengerのプロセスは動いていただろうか。

あわてて見直してみると、Passenger配下にあるはずのインスタンスがない。では、どうやって動いているのだと追ってみれば、なんとも困ったことにアプリケーションはCGIで動いていたのだった。

Snow Leopardが遅くなる 1

投稿者 akira 2009-11-05 09:45:00 GMT

Snow Leopardにしてから、なのではないか思うのだけど、よくわからない現象が起きるようになった。(実際にはそれ以前から起きていて気付いていなかっただけ、ということも無いとは言い切れないが。)

ある時、突然動作が遅くなる。重くなるのではなくて、遅くなる。CPUは使っていない(idleが70%以上など)。I/Oもたいしたことはない(ほぼアクセスしていない)。メモリにも空きがある(20%くらいはfree)。こういう状況でちょっとしたコマンドが終了するのに1秒以上かかるようになる。

たとえば「ruby -e0」を実行すると、通常ならキャッシュに乗っていない状態でも0.285秒。キャッシュに乗っていれば0.018秒で終了する(今やってみた)。これが現象発生時には1秒かかる。特に「ruby」に限定されるわけではなく、iPhotoとかXMindとか、GUIのツールでもものすごく反応がにぶくなる。

何がきっかけになってこの状態になるのか分からない。が、リブートすると元に戻ることは分かった。最初は熱か何かが原因なのかもしれないとも思ったけども、そういうものでもないようだ。ついでに言うと、上の「ruby -e0」の例はmacportsでいれた「ruby」(/opt/local/bin/ruby)を使った場合のことで、とっても不思議なのだけどもOSについてくる/usr/bin/rubyについてはこの現象を確認できない。まあ、少なくとも「/usr/bin/ruby -e0」については遅くなったところを見ていない。いったいなんなんだろう。

試しにOSの再インストールをしてみたのだけども…… たまたまなのかなんなのか、現象発生時(やっぱり発生してしまった)に「ruby -e0」を実行してみると終了までに1.5秒かかるようになってしまっていたという……。その後、まだ起きていないので本当にたまたまだったのかどうかは確認できていない。

ハードウェアトラブルでPC新調

投稿者 akira 2009-10-01 01:00:00 GMT

昨日の朝方、気が付いたらPCが止まっていた。

自宅のサーバ用として使っているPCで、それが止まると何もできないというほどのことはないが、長引くとわりと困る。原因ははっきりしないのだけども、電源かマザーボードなのかなと思える(まともに電源が入らなくなった)。予備の電源などはなく、切り分けるにも道具が足りない。手さぐりでのトライ&エラーを繰り返すのもためらわれるので思いきって中身を入れ換えることにした。

前回、このPCの構成を変えたのは2006年のことだったようなので、三年ばかりたったことになる。今回も、まわりの人々にアドバイスをもらいながら構成をおおまかに決め、あとは店頭でと、ショップに走った。

  • ASUS P5Q-E
  • Intel Q9550
  • バルク メモリ8GB
  • Owltech SS-600HM
  • 適当なビデオカード

小雨の中、けっこうな重さと大きさになった紙袋をひぃはぁいいながら持ち、この時節に似合わない汗を大量にかきながら帰った。

時間をおいてもいられないのですぐに換装作業に入り、毎度のことながらドキドキしながらCPUファンの取り付けをしたり、HDDのデバイス名が変わっているのに対応したり、fsckが延々続くのを待ったり、といったお決まりの作業をした。

以前よりはずいぶんと良い環境になったので、本格的に何か動かそうかな。

QuickSynergyとxmodmap

投稿者 akira 2009-09-06 00:21:00 GMT

OmniFocusを使い始めたこともあり、もう少しMacをちゃんと使おうと思って久しぶりにSynergyを使おうと思った。

そういえばGUIの何かがリリースされたとあったなと探して出てきたのがQuickSynergy。debパッケージもある。Mac版は何やら作り込んであるようだけど、debというかLinux向けにはsynergyコマンドのためのwrapperのようなものであるようだった。

使ってみたのはバージョン0.9。上下左右のホストをGUIで設定できる。細いオプション指定はできないうようだ。最初、ホスト名の指定を間違っていたのだが、それが分かるまでにはsynergyコマンドを直接起動して動きを見ていたという。オプションのことも考えるとLinux側(サーバ側)はsynergyコマンドをそのまま使ったほうがよいかもしれない。

Macとの共有でちょっと困ったのがキーの違い。Cmd-Altはいいとして、Optionをどうしようか、とか。それと、手元のキーボードでは右AltにあたるキーでISO_Level3_Shiftが送られるようで、右Altとして使えないというのもある。以前からxmodmapで適当に設定してAlt_Rになるようにはしていたのだが、この際だからちょっと整理(?)しておいた。

というわけで以下はメモ。

まずキーボードのリマップ機能を使って、左AltキとAlt Grキー(右Altキー相当)により左右Windowsキーのキーコード(Super_LとSuper_R)が送られるようにした。左Altキーはそのままでもよかったのだけども、設定側がめんどうになりそうなので合わせた。

最初からAlt_L/Alt_Rになるようにすればよかったのだろうけど、Alt_Rキーがないのでリマップできなかった。設定ソフトウェアを使えばそのあたりもできるのだったかもしれないが、よくわからない。どっちにしろMS-Windows用のものしかなかったと思うし、まあ特に困ることでもないのでよしとする(最近はコンソールを使うこともほとんどないし)。

ついでにCaps LockキーによりAlt Grキーのキーコード(もともと送られていたISO_Level3_Shift)が送られるようにもした。その上でxmodmapでSuper_LとSuper_RをAlt_L/Meta_LとAlt_R/Meta_Rに見えるよう設定する。あとはISO_Level3_Shiftを適当に処理してMac側にOptionキーイベントが送られるようにすれば完成。だが、そこだけやり残している。また後で。

追記

Super_L/Super_RでOptionsキーになるようなので、上のリマップを止めた。XmodmapでISO_Level3_Shiftを置き換えて…… と思ったら、Alt_LにはなるけれどShiftキーといっしょに押してもMeta_Rにならない。しょうがないのでAlt GrキーでSuper_Rが、Caps LockキーでSuper_Lが、それぞれ送られるようキーボードでリマップした。その上でxmodmapでSuper_RをAlt_R/Meta_Rに見えるよう設定する。

さて、Caps LockキーがMac上でOptionキーになってくれるはずだが…… いまひとつよくわからない。キーコードは送られているようだけど、モディファイアキーとしては認識されていな感じがする。Synergyの設定だろうか。

追記2

xmodmapの変更を繰り返しているうちにどこかおかしくなっていたようだ。ログインしなおして、改めてxmodmapを整理したところ、Synergy側で特に設定をしなくてもCaps Lockキー=Super_LがOptionキーとして働くようになった。

追記3(2009-09-07)

今度はMac側のQuickSynergyがうんともすんともいわなくなってしまった。パケットがまったく出ていっていない状況で、何がどうなっているのやら。

切り分けをしようとしてsynergy-1.3.1やらsynergy-plus-1.3.4やらをbuildしてみようとしたのだが、-arch i386がいることやら、synergy-plusでは-Werrorを外さないとならないことやらを見付けるのに相当時間をかけてしまったあげく、synergyのほうはそれでもbuildできず、synergy-plusのほうはキーイベントが渡らないという結果を得る。ここらでめんどくさくなってきて、結局、macportsをsvn trunkから入れた上で、port install synergyによりsynergy 1.3.1をイントールした。ちゃんと動く。

ruby1.9*-full不要! Ruby 1.9.1をDebianにインストールする

投稿者 akira 2009-08-26 01:01:00 GMT

ruby1.9.1パッケージがDebian/sidに入った。いくつか考え込んでいるうちに作業を進めてもらってしまうことになってしまい、実質的に何もお手伝いできなかった。いくつか必要そうなパッチが出ているように思うので、そちらで協力していくのと、ruby1.9.2パッケージの準備のほうで、今度こそ貢献できるようにと考えている。

さて、ruby1.9.1パッケージの登場によりDebian/sidでも(ようやく)手軽にRuby 1.9.1を使えるようになった。とはいえ、DebianのRubyパッケージはいくつかのサブパッケージに分割され提供されている。そのためフルセットの環境を構築するのはめんどくさい…… と思われがちである。しかしながら、いまどきのaptitudeを使えば以下のコマンドラインで一括してインストールが可能だ。もうruby1.9.1-fullなんていうパッケージはいらない

$ sudo aptitude install '?source-package(^ruby1\.9\.1$)'

ちなみにruby1.9.1-elispパッケージを除くなら以下のようになる。

$ sudo aptitude install '?source-package(^ruby1\.9\.1$)!~n^ruby1\.9\.1-elisp$'

もちろんaptitudeの検索式はいろいろなところで使える。aptitude searchならリストアップが可能だし、aptitude removeやaptitude purgeに使えばまとめて削除ができる。ぱぱっとソラで書けるかというとそうでもなくて、ちょっと手間取りそうな記述ではある。ただ、そういうことができるということを覚えておくと何かのときに役立つだろう。

ruby*-fullのような依存関係を提供するメタパッケージはある面で便利なのはわかる。ただ柔軟性はまったくないので使える場面はかなり限られると思う。実際のところ最初のインストールのときだけあれば十分だという人が多いのではないだろうか(もっというなら、インストール後は自動的に消えてくれと思う人だっているだろう)。その点、上に書いたような方法であれば(あるいはgrep-dctrlを使うような方法であれば)応用が効いて使いでがあるはずだ。

分割パッケージをまるごとインストール

投稿者 akira 2009-06-19 01:17:00 GMT

今月のSoftware Design (ソフトウエア デザイン) 2009年 07月号 [雑誌]Software Design(2009/7号)はDebian特集であった。パラパラとながめていって、ふとパッケージ情報にアクセスするツールを調べ直したくなった。

といっても--helpしてみたり、manページを見たりといった程度。そんな中、grep-dctrlに便利な機能が加わっているのに気付いた(etchのころにはもうあったようだが気付いていなかった、とも言える)。その機能というのは-Sオプション。-Sオプションは-F Source:Packageの短縮形で、パッケージ情報にSourceフィールドがあればそれに対して、なければPackageフィールドに対してパターンマッチを行う。

各バイナリパッケージのパッケージ情報には、そのバイナリパッケージを作るもととなったソースパッケージが何であるかが含まれいることがある。一つのソースパッケージから複数のバイナリパッケージが生成されることがあるためで、ソースパッケージ名とバイナリパッケージ名が異なる場合にSourceフィールドが現れ、その値としてソースパッケージ名が記述される。

あるソースパッケージから生成されるすべてバイナリパッケージを探し出したいとするとき-Sオプションが便利だ。たとえば、ソースパッケージruby1.8から生成される、つまり、パッケージとして提供されるRuby 1.8の全部をインストールしたいとすると、次のようなコマンドラインが考えられる。

$ grep-aptavail -n -X -s Package -S ruby1.8 | xargs sudo aptitude install

(しばし余談)

ここで、-Sオプションではなく、-F Source,Packageでも実現できるのではないかと思える。「:」でなく「,」で区切った場合、そのうちのどれかにマッチしたものが出力されるからだ。だが、実際にやってみるとこれはうまくいかない。なぜかというと、あるソースパッケージの名前と同じ名前のバイナリパッケージを生成する別のソースパッケージというのが存在する可能性があるのだ。

$ grep-aptavail -X -s Package,Source -S libqt4-ruby
Package: libsmokeqt4-1
Source: libqt4-ruby

Package: libsmokeqt4-dev
Source: libqt4-ruby

$ grep-aptavail -X -s Package,Source -F Source,Package libqt4-ruby
Package: libsmokeqt4-1
Source: libqt4-ruby

Package: libsmokeqt4-dev
Source: libqt4-ruby

Package: libqt4-ruby
Source: kdebindings

libqt4-rubyは一例で他にもいくつかある。このような状態はリリース間でパッケージ構成が変わったなど、特別なケースであることが多いと思うが、そういうこともありうるという点には気を付けておいたほうがよいだろう。

(本題に戻る)

sarge以降(あえてsargeという :-)、apt-getではなくaptitudeが用いられていることと思うが、最近のaptitudeの検索パターンは実に充実していることにも気付いた。ソースパッケージruby1.8から生成されたパッケージを選び出してインストールしたければ、次のようにコマンド実行すればよい。

# aptitude install '?source-package(^ruby1\.8$)'

unable to create temporary sha1 filename .git/objects/96

投稿者 akira 2009-05-23 21:48:00 GMT

あるときgit pullしたら以下のようなエラーが返ってきた。

remote: Counting objects: 39, done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 27 (delta 19), reused 0 (delta 0)
error: unable to create temporary sha1 filename .git/objects/96: File exists

再試行しても状況が変わらない。どうしたものかと調べたところ.git/objects/96のオーナーが他のユーザになっていたためだった。どうやらsudoのオプションを間違えたことがあったようだ。

同様にオーナーが違っているディレクトリが他にもあったので修正。再びgit pullして今度はいつも通りに動作していることを確認できた。

最近のsudoと環境変数 2

投稿者 akira 2009-04-24 01:15:00 GMT

sudoの環境変数の扱い方が最近になって変わっていることに気付いた。最近といっても一〜二年はたっているかもしれない。

sudoを介してコマンド実行するとき、あらかじめ決められた環境変数以外は消し去されてしまう。このためたとえば次のようなコマンド実行は意図通りには動かない。

$ GEM_HOME=/tmp/GEM sudo gem install rails

従来、このようなときにはenvを使って回避というのが一つのやり方だったように思う。もちろんsudoersでenvの実行が許可されていなければならない。

$ sudo env GEM_HOME=/tmp/GEM gem install rails

sudo 1.6.9以降になると以下のような記述が可能となり、わざわざenvを使う必要がなくなった(バージョンは多少違うかもしれないが、少なくともDebian/etchの1.6.8p12ではこのような書き方はできない)。

$ sudo GEM_HOME=/tmp/GEM gem install rails

ただし、この書き方によって任意の環境変数を渡せるかどうかには条件がある。一つはsudo 1.6.9p8以降であること。もう一つは全コマンドを実行可能であること。

特定のコマンドの実行だけが許可されているユーザにおいては、通常の環境変数のフィルタリングルールが適用される。許可されない環境変数を与えようとするとエラーが起きてコマンドは実行されない。

もちろん全バージョンに共通してsudoersで明示的な許可があればそれで十分である。ここで述べた動作の変化はほぼデフォルトの設定のままで運用している環境に対して影響がある。