Fusic 平田です。
    とあるお客様のところにLinuxのサーバを納入しているのですが、今回はそのお話を。
    # 倍プッシュ編しかありませんので、そこはご容赦ください。

    このサーバ、普段はファイルサーバとして活用しているものです。
    で、今回別途USBの外付けHDDを2台追加することになりました。
    用途はSambaでアクセスできればいいよーだったのですが、問題がひとつ。
    他にも外付けHDDなどなど挿したりしてて、USBポートに余裕がないと。

    で、USBハブあるよーとのことなので挿してみました。
    さっくり動いてmountできたのでおー動く、と思ったのもつかの間。
    数分たったりUSBハブに他の機器を挿したりした瞬間に動かなくなりました。
    /var/log/messagesを見ると、以下のIO Errorがずらり。

    scsi 9:0:0:0 rejecting I/O to dead device

    これを解消すべく、以下の手順でいろいろやってみました。

    0. 前提

    サーバマシン: Linux(CentOS 5.3)の2Uサーバ
    元からあったUSB外付けHDD: 1台(IO-DATA)
    今回増やすUSB外付けHDD: 2台(IO-DATA)
    問題: USBポートが既にいっぱいいっぱい
    目標: 正常に動かす
    目標2: さらに増やす時に手間がかからないようにする

    1. /dev/***の部分を各HDDで固定する

    現象を見ていると、/dev/sd*の部分がころころ変わるようで。
    と言うか/dev/sd*の部分はudevで勝手に割り当てるので、再起動時なんかに変わってしまう可能性が大。
    これをまずは固定しようということでいろいろ調べたところ、↓を発見。
    http://fredericiana.com/2006/03/15/writing-udev-rules-short-notes/
    要はudevのruleを作成して、デバイスファイルを固定しようってことです。
    というわけでudevルールの書き方を読んでみると、

    > ユーザ指定のルールは、基本の/devレイアウトを作成するudevの初期設定を、事実上無効にしてしまいます。したがって、ユーザが記述するルールには、実用的である初期設定の名前とユーザ指定の名前両方を得るために、devfs形式の名前やシンボリックリンクも指定することをお勧めします。

    とあったので、/etc/udev/rules.d/98-local.rulesとして以下の内容のファイルを作成。

    BUS=="usb", KERNEL=="sd*", SYSFS{serial}="0010100740AABBCC", NAME="%k", SYMLINK="usbhda\n"
    BUS=="usb", KERNEL=="sd*", SYSFS{serial}="0010100740DDEEFF", NAME="%k", SYMLINK="usbhdb\n"
    BUS=="usb", KERNEL=="sd*", SYSFS{serial}="0010100740ABCDEF", NAME="%k", SYMLINK="usbhdc\n"

    # SYMLINKの値はこちらで決めていいので、”usbhd/****”とかにして別途まとめる形でもいいです。
    serialの調べ方ですが、1つずつ挿して/dev/sdbなりで認識されているのを確認した後に

    udevinfo -a -p $(udevinfo -q path -n /dev/sdb)

    と実行すると

    # udevinfo -a -p $(udevinfo -q path -n /dev/sdb)
     
    Udevinfo starts with the device specified by the devpath and then
    walks up the chain of parent devices. It prints for every device
    found, all possible attributes in the udev rules key format.
    A rule to match, can be composed by the attributes of the device
    and the attributes from one single parent device.
     
      looking at device '/block/sdb':
        KERNEL=="sdb"
        SUBSYSTEM=="block"
    ----- (中略) -----
      looking at parent device '/devices/pci0000:00/0000:00:03.1/usb3/3-1/3-1.4':
        ID=="3-1.4"
        BUS=="usb"
        DRIVER=="usb"
        SYSFS{configuration}==""
        SYSFS{serial}=="0010100740AABBCC"
    ----- (後略) -----

    てな感じでずらずら出てくる中から読み取れます。

    ruleを保存した後に再度挿すと、こんな感じになります。

    # ls -l /dev/usbhd*
    lrwxrwxrwx 1 root root 3  8月 20 17:57 /dev/usbhda -> sdb
    lrwxrwxrwx 1 root root 4  8月 20 17:57 /dev/usbhda1 -> sdb1

    複数台挿して/dev/sd*の順序がずれても、

    # ls -l /dev/usbhd*
    lrwxrwxrwx 1 root root 3  8月 20 17:57 /dev/usbhda -> sdb
    lrwxrwxrwx 1 root root 4  8月 20 17:57 /dev/usbhda1 -> sdb1
    lrwxrwxrwx 1 root root 3  8月 20 18:06 /dev/usbhdb -> sdd
    lrwxrwxrwx 1 root root 4  8月 20 18:06 /dev/usbhdb1 -> sdd1
    lrwxrwxrwx 1 root root 3  8月 20 18:05 /dev/usbhdc -> sdc
    lrwxrwxrwx 1 root root 4  8月 20 18:05 /dev/usbhdc1 -> sdc1

    といった感じできちんとアクセスできます。

    2. USBハブを変える

    使用したハブがそこそこ古いものだったので、外付けHDDを複数台挿すと途端に動かなくなります。
    デバイスファイルの問題は解決しているので、あとは単純にUSBハブの供給電流とかの問題だろうなと。
    # あとusb2.0に対応してなさそうだな、とか。
    # 型番を必死に調べたのですが、外観以外の情報がないので絞り込めませんでした。。。
    というわけで今回使用したのはこちら。
    ELECOM U2H-GM002BK
    PS3用じゃないか!とツッコミをいただいたりもしたのですが。
    > セルフパワー時/7ポート合計3500mA以内
    が非常に強力なので、これにしました。
    # 4ポートのELECOM U2H-TAP3420Sもあったのですが、口に余裕があったほうが困らないので今回は却下。
    # 7ポートのほうはマグネットが付いてたりするので、そういうの困るなって場合は後者がいいと思われます。

    というわけで設置、USBハブ電源スイッチオン、USB外付けHDDをざくざく挿入。
    きっちり稼働して万々歳です。
    以降定期的にちょこちょこ覗いてますが、特に問題も発生していないようです。

    同様の事象で困る例は非常に少ないと思いますが、備忘録がてらということでひとつ。
    何か後日談なんかが出てきた場合は、またこちらで紹介させていただきます。
    まあ後日談=十中八九トラブルなので、なるべく書かなくて済むことを祈りますが。。。

      またまた山本です。
      以前ご紹介した自社サービスのZENPREの反響が思いのほか大きく、とりあえずほっとしております。
      いいスタートダッシュは切れたので、引き続き新たな機能の実装を続けてまいります。

      今回はZENPREで使用している機能の1つを紹介させていただきます。

      ZENPREではアップロードされたMicrosoftOfficeのPowerPointのデータやPDFを画像変換することで、Flashを通しての配信を可能にしておりますが、
      この時のフローとしては、3つの段階を経ています。

      OpenOffice + JODConverterでppt,pptxファイルをpdfファイルへ変換(省略可)

      poppler(Xpdf)を使用して、pdfファイルをppmファイルへ変換

      ImageMagickを使用して、ppmファイルをjpgへ変換

      つい最近まで、OpenOfficeのバージョンは3.2.0でした。
      このバージョンでは、Office2007の形式である「pptx」も変換可能なのですが、
      1枚目に表示される「クリックしてサブタイトルを入力」というガイドまでも変換されてしまうというバグがありました。
      しかし、最近バージョンが3.2.1にあがりその問題が解消されましたので、晴れて「pptx」にも対応いたしました。

      開発段階においては、2番目のフローである「pdf→ppm」変換をせず、
      「pdf→jpg」変換を行っておりました。
      しかし、この変換方法だと生成される画像の解像度が低いという問題がありました。
      600×480ほどのサイズであれば問題なく、表示もそれに合わせればよいのですが、ZENPREの機能の一つにフルスクリーンモードというのがあり、
      それを使用すると利用者によってはとてつもなく大きいモニターで表示することになり、
      その場合、画像が引き伸ばされぼやけてしまうことになります。

      そこで着目したのがpopplerでした。
      popplerの前身はXpdfであり、pdfをppmという高解像度の画像へ変換することが可能です。

      以下は、ppmに変換せずに生成したjpgとppmに変換した上で生成したjpgの2ファイルです。
      ppm処理しないjpg
      ppm処理したjpg

      前者は粗さが目立ちますが、後者は文字の縁が滑らかなまま表示されています。
      もちろんファイルサイズが大きくなってしまいますが、大した負荷ではないので採用することにしました。

      インストールは、Redhat系をご使用であればyumインストールで使用可能なのですが、
      yumだと肝心のpdfをppmに変換する機能である、「pdftoppm」が含まれてません。

      情報が少なくて、pdftoppmを導入する方法がなかなかわからなかったのですが、
      popplerをyumインストールするのではなく、ソースからインストールすることで解決しました。
      Poppler

      課題としては、全体的に変換に時間がかかるということです。
      pdf変換においても結構時間がかかるのですが、その上にppm変換を挟んでいるのでどうしても短縮が困難です。
      pptの変換サービスとしては有名なところでSlideshareがあると思いますが、
      この変換速度はかなりなものだと思います。

      これに近づけたらと思います。

        こんにちは。
        最近、これから紹介するサービスの対応に追われ続けている山本です。

        8/3(火)に、Fusicの新サービス「ZENPRE」をOPENしました。
        今回は、そのZENPREのご紹介や特徴について書かせていただきます。

        ZENPREは、スライド資料と動画が同時に配信できるプレゼンテーションツールです。
        Ustreamが身近に使われるようになった昨今、全国で行われるイベントの模様がお気軽に配信・閲覧できるようになりました。
        勉強会やセミナーの様子も配信される機会も増え、主に都心部でしか行われない貴重な勉強会でも遠方にいながらにして擬似的に参加できるようになりました。
        しかし、専用のカメラ機材を使って中継される稀なケースを除き、配信される映像の解像度は低く、スクリーンに映し出された資料の解読が困難なことがなかったでしょうか。

        当サービス「ZENPRE」では、資料と動画を別画面に分けて表示します。そのため資料部分の可読性は一気に向上します。
        また、配信する方のページ操作がそのまま受信する方のページに反映されるため、リアルタイム性が保持されます。
        さらにチャット機能も搭載しておりますので、発表の際の気になった発言もすぐ質問ができ発表者や自分以外の参加者とのコニュニケーションが可能です。

        発表の際に、受信する方が見る画面サンプルを掲載いたします。

        画面は3つの領域に分かれます。
        左側が資料を表示する領域です。この部分が、発表者のページ操作に同期し自動でページが切り替わります。自分で操作することはできません。
        右側上部が動画再生領域です。Ustreamを通した現地の様子が閲覧できます。
        右側下部がチャット領域です。

        これらサービスの利用には、発表者に資料の登録をしてもらう必要があります。
        セミナー等で発表することが決まり、資料の作成も完了したらZENPREに資料を登録してください。
        また、動画を配信するために、UstreamのチャンネルIDも同時に登録しておきます。

        実際に発表の日時になり、自分の番になったらZENPREの配信用画面を会場のスクリーンに映し出します。
        配信用の画面サンプルは以下になります。

        ほぼ受信用の画面と同じですね。
        唯一違うのは、赤色で強調した部分のページ送りボタンが付いていることです。
        「次ページ」ボタンを押すことで、自身の画面のスライドが次ページへ移動するとともに、受信者の画面にも伝わり、次ページが表示されます。
        もちろん「前ページ」ボタンで前ページへ移動し、ページ数の指定もすることができます。
        また、配信用画面には動画は不要というケースもあるため、資料部分のみフルスクリーンで表示することも可能です。

        公開が終了した後は、受信者画面でもページの操作ができるようになり、後々の資料として活用することもできます。

        ページ操作に関しては、この配信用画面から操作する以外にもスマートフォンアプリを利用して行うことができます。
        OPENに合わせて、iPhone用アプリとAndroid用アプリを用意しました。
        どちらのアプリも全く同じ機能を持っているのですが、iPhoneアプリの画面を以下に掲載いたします。

        ページの操作はフリック(画面を指でスライドさせる動作)で行います。
        直感的に、かつ、リモコン感覚でページの操作が可能になります。

        他にも、
        ・新着ニュースの閲覧
        ・過去に配信した資料の閲覧
        がアプリで可能です。

        AppStore、もしくは、AndroidMarketで「ZENPRE」と検索してください。
        無料でダウンロード可能です。

        以上の機能が、すべて無料で利用できます。
        今後、より多くの人に参加してほしい勉強会やセミナーがございましたら、ぜひともZENPREをご活用ください。

        次回は、ZENPREを支えている技術についてご紹介したいと思います。

        ZENPRE
        http://zenpre.net

        Fusic によるZENPRE紹介
        http://fusic.co.jp/product/zenpre.html

        ZENPRE on twitter
        http://twitter.com/ZENPRE

          平田です。
          先日のFukuoka Perl Workshop #16で話したBeccoameについて、つらつらと。

          資料は英語ですが、喋りは全て日本語でした。

          Beccoame = Bogus elastic computing, like Amazon EC2 or Eucalyptus
          ざっくり訳すると「Amazon EC2やEucalyptusっぽい偽クラウド」。
          Eucalyptusを使っている上で
          ・-n 40とかで大量のインスタンスを一気に起動すると、処理が追いつかずにタイムアウト扱いになってしまう
          ・以前のEC2互換であるため、インスタンスの再起動ができない(停止=インスタンス消滅)
          などなど、ちょっと困ったなーの部分を解消できないもんかと思い。
          簡素化したもので構わないので、勉強ついでに作れないものかと考えたのが実装のきっかけです。
          で、libvirtまわりの調査がてらざっくり組んでみたというお話を。

          EucalyptusとAmazon EC2の関係を簡単に表すと、こうなります。

          これにBeccoameを挟むと、こんな感じです。

          で、今回はTatsumakiを採用しました。
          理由は単純で、僕が勉強がてらTatsumakiを触ってみたかっただけです。

          サーバ環境は以下になります。
          Dell PowerEdge T105
          CPU: Quad-core AMD Opteron 1354
          メモリ: 4GB
          HDD: 250GB 7,200rpm
          # 要するに、Eucalyptus環境の1台を使いまわしています1

          これにUbuntu 10.04 LTS Server(x86_64)をインストール。
          追加でKVMをapt-getでさくっとインストール。
          操作するためのlibvirtもインストールします。

          $ sudo apt-get install kvm libvirt

          libvirtは、Linuxの仮想化ライブラリです。
          いろんな仮想環境に対する操作を行うAPIを提供します。
          付属のvirshを用いれば、いろいろと操作が行えます。

          $ virsh
          virsh にようこそ、仮想化対話式ターミナルです。
           
          入力方法: 'help' コマンドに関するヘルプ
                    'quit' 終了します
           
          virsh # help
          コマンド:
           
              help            ヘルプの表示
              attach-device   XML ファイルからデバイスを追加
              attach-disk     ディスク装置の接続
              attach-interface ネットワークインターフェースを接続します
              autostart       ドメインの自動起動
          ...
          (以下略)
          ...
           
          virsh #

          で、libvirtのPerlバインディングがSys::Virtです。
          要は「PerlでKVMなどの仮想環境を操作できる」モジュールです。
          # 他の言語のバインディングについては、公式サイトをご覧ください。
          # PHPバインディングも存在するんですね。。。

          というわけで、必要なCPANモジュール群をインストール。

          $ sudo cpan install Tatsumaki
          $ sudo cpan install Sys::Virt
          ...
          (以下略)
          ...

          で、コードはこんな感じになります。
          # 久しぶりに書いたPerlなもので、いろいろ作法違いなどあってもご容赦ください。。。
          app.psgi

          use strict;
          use warnings;
           
          use Tatsumaki::Application;
          use RunInstancesHandler;
          use TerminateInstancesHandler;
          use DescribeInstancesHandler;
           
           
          package MainHandler;
          use base qw(Tatsumaki::Handler);
           
          sub get {
              my $self = shift;
              $self->write("Work well.\n");
          }
           
          package main;
          use File::Basename;
           
          my $app = Tatsumaki::Application->new([
                  '/' => 'MainHandler',
                  '/RunInstances' => 'RunInstancesHandler',
                  '/TerminateInstances' => 'TerminateInstancesHandler',
                  '/DescribeInstances' => 'DescribeInstancesHandler',
                  ]);
          return $app;

          RunInstancesHandler.pm

          # run instance handler
          package RunInstancesHandler;
           
          use parent qw(Tatsumaki::Handler);
          use strict;
          use warnings;
           
          use Sys::Virt;
          use XML::Simple;
          use Data::Dumper;
          use String::Random;
          use File::Basename;
          use File::Copy;
          use File::Spec;
           
          sub post {
              my $self = shift;
           
              # create XML::Simple object
              my $xs = new XML::Simple(forcearray => 1, KeyAttr => [], RootName => '');
           
              # receive XML request
              my $xmlRequestRef = $xs->XMLin($self->request->content);
              my $xmlRef = $xs->XMLin($self->request->content);
           
              my $currentDir = dirname(__FILE__);
           
              # image id (default: lucid)
              my $imageId = 'lucid';
           
              # image file name
              my $baseImageFileName = $currentDir . '/images/' . $imageId . '.qcow2';
           
              # base xml file name
              my $baseImageXmlFileName = $currentDir . '/images/xml/' . $imageId . '.xml';
           
              # generate MAC address script path
              my $genMacAddrPath = $currentDir . '/tools/gen_mac_addr.sh';
           
              # instance memory size (default: 121072)
              my $memorySize = '131072';
           
              # Open & read base XML file
              open my $fh, '<', $baseImageXmlFileName or die "Could not open file: $!";
              sysread $fh, my $baseImageXml, -s $fh;
           
              # variables
              my $instanceName, my $uuid, my $macAddress, my $imageFileName, my $imageXmlRef;
           
              # get max instance count from request
              my $maxCount = $xmlRef->{maxCount}->[0];
           
              # connect QEMU
              my $vmm = Sys::Virt->new(address => "qemu:///system");
              my $domain;
           
              my $responseXmlTemplate = $currentDir . '/xml/run_instances_response.xml';
              my $responseItemXmlTemplate = $currentDir . '/xml/item.xml';
           
              # Open & read base XML file
              open $fh, '<', $responseXmlTemplate or die "Could not open file: $!";
              sysread $fh, my $responseXml, -s $fh;
           
              # Open & read item XML file
              open $fh, '<', $responseItemXmlTemplate or die "Could not open file: $!";
              sysread $fh, my $responseItemXml, -s $fh;
           
              my $responseXmlRef = $xs->XMLin($responseXml);
           
              my $itemXmlRef;
              my $domainXmlRef;
           
              # create images
              for (my $i = 0; $i < $maxCount; $i++) {
           
                  # generate new instance name
                  $instanceName = 'i-' . String::Random->new->randregex('[a-f0-9]{8}');
           
                  # generate new UUID
                  $uuid = `uuidgen`;
           
                  # generate MAC address
                  $macAddress = `$genMacAddrPath`;
                  chomp($macAddress);
           
                  # copy image file
                  $imageFileName = File::Spec->rel2abs($currentDir . '/store/' . $instanceName . '.qcow2');
                  copy($baseImageFileName, $imageFileName);
           
                  # create XML Reference for booting
                  $imageXmlRef = $xs->XMLin($baseImageXml);
           
                  # change XML values
                  $imageXmlRef->{domain}->[0]->{name}->[0] = $instanceName;
                  $imageXmlRef->{domain}->[0]->{memory}->[0] = $memorySize;
                  $imageXmlRef->{domain}->[0]->{currentMemory}->[0] = $memorySize;
                  $imageXmlRef->{domain}->[0]->{uuid}->[0] = $uuid;
                  $imageXmlRef->{domain}->[0]->{devices}->[0]->{disk}->[0]->{source}->[0]->{file} = $imageFileName;
                  $imageXmlRef->{domain}->[0]->{devices}->[0]->{interface}->[0]->{mac}->[0]->{address} = $macAddress;
           
                  $itemXmlRef = $xs->XMLin($responseItemXml);
                  $itemXmlRef->{instanceId}->[0] = $instanceName;
                  $itemXmlRef->{instanceState}->[0] = 'pending';
                  $responseXmlRef->{RunInstancesResponse}->[0]->{item}->[0]->{instancesSet}->[0]->{item}->[$i] = $itemXmlRef;
                  $domainXmlRef = '';
           
                  # create domain
                  $domain = $vmm->create_domain($xs->XMLout($imageXmlRef));
              }
              $self->response->headers([ 'Content-Type' => 'text/xml; charset=utf-8' ]);
              $self->write($xs->XMLout($responseXmlRef));
              $self->finish;
          }
           
          1;

          # DescribeInstancesHandler.pmとTerminateInstancesHandler.pmは略。

          これをplackupで起動し、

          $ plackup &
          [1] 16392
          Twiggy: Accepting connections at http://0.0.0.0:5000/

          起動したサーバに対して、XMLでリクエストを送信します。
          run_instances.pl

          #!/usr/bin/perl -w
           
          use strict;
           
          use LWP::UserAgent;
          use HTTP::Request::Common;
          use File::Basename;
           
          my $userAgent = LWP::UserAgent->new(agent => 'perl post');
           
          my $requestXmlFile = dirname(__FILE__) . '/run_request.xml';
          my $requestUrl = 'http://localhost:5000/RunInstances';
           
          open my $fh, '<', $requestXmlFile or die "Could not open file: $!";
          sysread $fh, my $message, -s $fh;
           
          my $response = $userAgent->request(POST $requestUrl,
                  Content_Type => 'text/xml',
                  Content => $message);
           
          print $response->error_as_HTML unless $response->is_success;
           
          print $response->as_string;

          リクエストに使用するXMLは、EC2公式のAPIドキュメントのものに合わせています。

          <RunInstances xmlns="http://ec2.amazonaws.com/doc/2010-06-15/">
              <imageId>ami-60a54009</imageId>
              <minCount>1</minCount>
              <maxCount>3</maxCount>
              <keyName>example-key-name</keyName>
              <groupSet/>
              <placement>
                  <availabilityZone>us-east-1b</availabilityZone>
              </placement>
              <kernelId>aki-ba3adfd3</kernelId>
              <ramdiskId>ari-badbad00</ramdiskId>
              <blockDeviceMapping>
                  <item>
                      <virtualName>ami</virtualName>
                      <deviceName>sda1</deviceName>
                  </item>
                  <item>
                      <virtualName>root</virtualName>
                      <deviceName>/dev/sda1</deviceName>
                  </item>
                  <item>
                      <virtualName>instancestore0</virtualName>
                      <deviceName>sdb</deviceName>
                  </item>
                  <item>
                      <virtualName>instance1</virtualName>
                      <deviceName>sdc</deviceName>
                  </item>
              </blockDeviceMapping>
              <userData version="1.0" encoding="base64">
                  <data>"VGhpcyBpcyBiYXNlIDY0IQ==</data>
              </userData>
              <addressingType>public</addressingType>
              <monitoring>enabled</monitoring>
          </RunInstances>

          これを実行すると、

          $ perl run_instances.pl
          HTTP/1.0 200 OK
          Content-Type: text/xml; charset=utf-8
          Client-Date: Wed, 28 Jul 2010 02:56:47 GMT
          Client-Peer: 127.0.0.1:5000
          Client-Response-Num: 1
            <RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2006-10-01">
              <groupSet>
                <item>
                  <groupId>default</groupId>
                </item>
              </groupSet>
              <instancesSet></instancesSet>
              <item>
                <instancesSet>
                  <item>
                    <amiLaunchIndex>0</amiLaunchIndex>
                    <dnsName></dnsName>
                    <imageId>ami-60a54009</imageId>
                    <instanceId>i-ea19a11c</instanceId>
                    <instanceState>pending</instanceState>
                    <keyName>example-key-name</keyName>
                  </item>
                  <item>
                    <amiLaunchIndex>0</amiLaunchIndex>
                    <dnsName></dnsName>
                    <imageId>ami-60a54009</imageId>
                    <instanceId>i-e89ae6b5</instanceId>
                    <instanceState>pending</instanceState>
                    <keyName>example-key-name</keyName>
                  </item>
                  <item>
                    <amiLaunchIndex>0</amiLaunchIndex>
                    <dnsName></dnsName>
                    <imageId>ami-60a54009</imageId>
                    <instanceId>i-fb30dc5a</instanceId>
                    <instanceState>pending</instanceState>
                    <keyName>example-key-name</keyName>
                  </item>
                </instancesSet>
              </item>
              <ownerId>495219933132</ownerId>
              <reservationId>r-47a5402e</reservationId>
            </RunInstancesResponse>

          といった感じで、起動要求を投げたインスタンスの情報がXMLで返ってきます。
          レスポンスもEC2公式のAPIドキュメントに準拠する形にしています。
          # と言っても、すごく半端な実装です。
          # 起動時はmaxCountしか今のところ見てないですし。
          # 返ってくるXMLも、instanceIdしか書き換えていない状態です。

          実際に起動したかどうかは、virshで確認できます。

          $ virsh list
           Id 名前               状態
          ----------------------------------
           47 i-ea19a11c           実行中
           48 i-e89ae6b5           実行中
           49 i-fb30dc5a           実行中

          無事に起動できているようです。:-)

          と言った感じで、とりあえずここまで。
          次は処理を非同期化したり、エラー処理をきちんと行ったりといったところでしょうか。
          # 実は各インスタンスのIPアドレスを取得するのが、結構面倒だったり2 しますが。
          また、インストールした直後だとNATで構成されているので、これをBridgeに変えたり。
          そもそもの互換性がまだ低いので、勉強しながらちまちまと実装していく予定です。

          個人的な感想としては、
          ・TatsumakiがモダンなPerlを学ぶ上で非常によい教材になる
          ・しばらく仕事でPHPを書いていたので、php-funcref-in-perlが非常に役立った
          といったところです。

          なお今回、弊社の新サービスを用いてプレゼンを行ないました。
          # 終わってみたら、そっちに話を持って行かれて嬉しいやら寂しいやら。
          新サービスついては、おいおい当blogのほうで紹介させていただくと思います。

          1. 直前はCentOS5.5上でEucalyptus NCが動いていました。 []
          2. arpの結果から引っ張るくらいしか思いつかず。いい方法あったら教えてください。。。 []

            はじめまして。
            Fusicエンジニアの山本と申します。

            昨年、大阪のシステム会社より転職して参りまして、
            入社してからは主にruby(on Rails)を使っての開発に携わっています。

            初めての投稿の今回は、プロセス監視ツール「God」について取り上げたいと思います。

            みなさんはプロセス監視ツールは何をお使いでしょうか。
            代表格には、Daemontoolsやmonitがあるかと思います。

            近日公開する弊社のウェブサービスに監視ツールを導入するにあたって、そのサービスが他にない試みであるということもあり、今まで使ったことのない監視ツールを導入したいなと考えておりました。

            そんな中、名前がすごく特徴的で、rubyで動くという「God」に注目しました。

            God – A Process Monitoring Framework in Ruby
            http://god.rubyforge.org/

            トップのシルエットが印象的ですね。

            Daemontoolsやmonitと比べて優れている点、劣っている点はそれぞれあるようですが、
            ・監視の間隔の時間指定ができる
            ・障害時にメール送信できる
            ・一定のメモリ使用以上でリスタートできる
            という、必要最低限の機能は備えているようですし、すでにrubyを導入しているサーバーであったため、こちらを選択することにしました。

            あとで調べて分かったんですが、有名なレシピコミュニティーサイトのクックパッドさんでも導入されているんですね。
            動作サンプルはサイト上に掲載されていますが、以下の作業だけで導入することができます。
            gemの動作が必須となります。

            ・gemによるインストール
            # sudo gem install god

            ・設定ファイルの作成
            拡張子godのファイルを作成します。
            記述例は以下のとおり。

            # vim sample_ready.god

            God.watch do |w|
              w.name            = "sample_ready"  #この設定の名称
              w.interval        = 60.second  #監視時間間隔
              w.start           = "ruby #{File.dirname( __FILE__ ) + '/sample.rb'}"  #実際に動かすプログラム
              w.log             = "#{File.dirname( __FILE__ ) + '/sample.log'}"  #ログを残す場合の書き込み場所
             
              # プロセスが落ちいていた場合は起動
              w.start_if do |start|
                start.condition(:process_running) do |c|
                  c.running = false
                end
              end
             
              # メモリが一定上超えたら再起動
              w.restart_if do |restart|
                restart.condition(:memory_usage) do |c|
                  c.above = 10.megabytes
                end
              end
            end

            ・godの起動
            # god -c sample_ready.god

            これだけで監視の開始です。

            試しに、rubyで動かしているプロセスをkillして、60秒後に再度確認してみると起動しているのが確認できます。

            このGODの監視を止めるコマンドは

            # god stop sample_ready

            です。stopのあとに続く文字列は、ファイル名ではなく、w.nameで設定した名称でなければいけません。

            Deamontoolやmonitとの比較についても検証してみたいところですが、
            今回はここまでとさせていただきます。

              最近はこればかり聴いている小山です。

              今回は、つい先ほど1.0がリリースされたTransition Componentを紹介します。
              (CakePHPのバージョンは1.3.2を想定しています。)

              Transition Component

              Webシステムで、実装が面倒なものとして例えば「確認画面」というものがあります。
              ようは「ページ遷移をともなって完結するような機能」ですね。
              他にも「ウィザード」や「アンケート回答」や「カート」でもいいかもしれません。

              Transition Componentは、そのような「ページ遷移」管理を一手に引き受けてくれるComponentで、hiromi2424さんによって開発がされています。

              Transition Componentは、セッションと、主にCakePHPのモデルバリデーションの機能を利用してページ遷移を管理しており、
              使いこなすとページ遷移管理を非常にすっきりとしたコードで実現することができます。

              今回は簡単な登録機能に確認画面を実装してみます。

              登録機能の実装

              今回はcaketransitionというデータベースにpostsというテーブルを作成します。

              postsの登録機能のMVCは以下のようなソースコードで作成します。

              post.php

              posts/add.ctp

              posts_controller.php

              Post.titleにnotemptyのバリデーションがある簡単な登録機能です。
              ただ、これだとまだ確認画面はありません。

              Transition Componentを利用した確認画面の実装

              ではTransition Componentを利用して実際に確認画面付きの登録機能を実装してみます。
              Modelは特に変更はないので、VとCだけ作成します。

              posts/add.ctp

              posts/add_confirm.ctp

              posts_controller.php

              たった、これだけですっきりした形で確認画面付き登録機能が実装できました。

              ポイント

              ページ遷移を伴う機能を実装するにあたって必要なのは以下の点です。
              また、Transition Componentでは以下のメソッドでそれらを担っています。

              • 正しい操作後の次のページへの遷移と入力データの保持 [TransitionComponent::checkData(), ::automate()]
              • 正しいページを通って来たかどうかのチェック [TransitionComponent::checkPrev()]
              • 各ページで入力されたデータの取得 [TransitionComponent::mergedData(), ::allData()]

              posts_controller.phpを見ても、とても直感的でわかりやすいかと思います。

              まとめ

              今回はTransition Componentの導入として簡単な確認画面付き登録機能を実装してみました。
              本当に簡単な導入部分だけを紹介しましたが、実際に使いこなすと非常に強力な機能を提供してくれます。
              個人的にはTransition Componentはここ最近のNo.1ヒットなCakePHPライブラリです。

              ぜひ使ってみることをお勧めします。

              詳細はREADMEhiromi2424さんのブログを確認してみてください。

              お知らせ

              7月3日(土)に第2回CakePHP勉強会@福岡を開催します。

              メインセッションも県外からのスピーカーセッションや、
              CakePHPベースCMS ”BaserCMS“の開発者の方のセッションなどがあり
              非常に充実していています。

              CakePHPで語りたい皆様、ぜひ参加してください。Transition Componentの使い方の質問なども是非。

              第2回CakePHP勉強会@福岡

              日時 / DATE :2010/07/03 14:00 to 18:00
              定員 / LIMIT :20 人
              会場 / PLACE :Fusic Co., Ltd. (福岡県福岡市中央区大名2-4-22 新日本ビル9F)

              申し込みはこちら→第2回CakePHP勉強会@福岡

              • eucalyptus

              Fusic 平田です。
              前回の続きを書く前にUbuntu 10.04 LTS(Lucid Lynx)が登場しました。
              また前回「靭帯が切れた」と書きましたが、その後入院など挟みつつ。
              やっとこ復帰して記事を書ける状態になりましたので、10.04での設定などをつらつらと。
              構成は前回と同じですが、せっかくなのでFrontendは32bit機にしてみました。
              ついでついでと言うことで(?)、インストール作業は後輩君に任せてみました。

              インストール時の大きな違いとしては、コントローラ単位での選択式になりました。
              # 9.10の場合はCluster/Nodeの2択でした。
              # ClusterにNode Controller以外の全てがインストールされていたのですが、今回は選択可能です。

              このためStorage Controllerだけ別にするなども可能なので、構成の幅が大きく広がります。
              今回は同様の構成にしています。
              [Frontend] Cluster Controller他1 : 192.168.11.100/24
              [Backend] Node Controller: 192.168.11.101/24

              インストール後、まずは管理画面にアクセスします。
              https://[Frontend IP]:8443/
              ログイン画面
              まずadmin/passwordでログインし、パスワード設定と管理者メールアドレスを入力。
              管理画面はこんな感じです。
              管理画面

              UECがめっぽう楽な理由の一つ2 が「Store」の項目。
              Store
              Store2
              あらかじめ用意されている起動イメージを1クリックでインストールできます。
              以下が現時点で用意されているイメージの一覧。

              • Ubuntu 9.10 – Karmic Koala (i386)
              • MediaWiki Demo Appliance (i386)
              • Ubuntu 9.10 – Karmic Koala (amd64)
              • M/DB Appliance
              • Ubuntu 10.04 LTS – Lucid Lynx (i386)
              • Ubuntu 10.04 LTS – Lucid Lynx (amd64)

              とりあえず動かしてみたい!という方は是非使ってみてください。

              さて、Eucalyptusの操作は主にコマンド(Euca2ools)を使用して行います。
              というわけでまずは下準備。
              # 以下の流れは、9.10でも10.04でも変わりはありません。

              1. Frontendにsshでログイン
              2. euca_conf –get-credentialsで認証情報を取得

              gintama@gintama-front:~$ sudo euca_conf --get-credentials euca.zip
              [sudo] password for gintama:
              --2010-06-11 10:44:57--  https://localhost:8443/getX509?user=admin&code=dc4sfR3CSYk1V0G3qNvtyP2BL8vx4387zYPWk8K2NVDAz7SL5jkS8k7kDC2sBBMp7hcMES6wMLyJQU8ng1dg
              localhost をDNSに問いあわせています... ::1, 127.0.0.1
              localhost|::1|:8443 に接続しています... 失敗しました: Connection refused.
              localhost|127.0.0.1|:8443 に接続しています... 接続しました。
              警告: localhost の証明書(発行者: `/C=US/ST=CA/L=Santa Barbara/O=db/OU=Eucalyptus/CN=localhost')の検証に失敗しました:
                自己署名証明書です。
              HTTP による接続要求を送信しました、応答を待っています... 200 OK
              長さ: 5052 (4.9K) [application/zip]
              `euca.zip' に保存中
               
              100%[==================================================================================================================================>] 5,052       --.-K/s   時間 0s
               
              2010-06-11 10:44:58 (584 MB/s) - `euca.zip' へ保存完了 [5052/5052]

              3. 解凍してsourceで読み込む3

              gintama@gintama-front:~$ unzip euca.zip
              Archive:  euca.zip
              To setup the environment run: source /path/to/eucarc
                inflating: eucarc
                inflating: cloud-cert.pem
                inflating: jssecacerts
                inflating: euca2-admin-8de7c506-pk.pem
                inflating: euca2-admin-8de7c506-cert.pem

              これでeuca-****なコマンドを使っていろいろ操作できるようになりました。
              主に使うコマンドの説明をしつつ、一気にインスタンス起動まで話を進めます。

              ・euca-describe-availability-zones verbose
              クラスタの状態(起動できるイメージの数など)を表示します。

              gintama@gintama-front:~$ euca-describe-availability-zones verbose
              AVAILABILITYZONE        gintama-front   192.168.11.100
              AVAILABILITYZONE        |- vm types     free / max   cpu   ram  disk
              AVAILABILITYZONE        |- m1.small     0004 / 0004   1    192     2
              AVAILABILITYZONE        |- c1.medium    0004 / 0004   1    256     5
              AVAILABILITYZONE        |- m1.large     0002 / 0002   2    512    10
              AVAILABILITYZONE        |- m1.xlarge    0002 / 0002   2   1024    20
              AVAILABILITYZONE        |- c1.xlarge    0001 / 0001   4   2048    20

              ・euca-describe-images
              登録されている起動イメージの一覧を表示します。

              gintama@gintama-front:~$ euca-describe-images
              IMAGE   emi-E0851072    image-store-1276057589/image.manifest.xml       admin   available       public          x86_64  machine eki-F6F41100    eri-0B6B1169
              IMAGE   eki-F6F41100    image-store-1276057589/kernel.manifest.xml      admin   available       public          x86_64  kernel
              IMAGE   eri-0B6B1169    image-store-1276057589/ramdisk.manifest.xml     admin   available       public          x86_64  ramdisk

              emi-******が起動イメージ、eki-******がkernel、eri-******がramdiskです。
              Amazon EC2のami/aki/ariと同様だと考えていただければ結構です。

              ・euca-bundle-image, euca-upload-image, euca-register
              イメージ登録に使用するコマンド群。
              bundle→upload→registerの流れになります。
              これについてはEucalyptus 日本語 Wikiあたりを参考に。
              今回はStoreからインストールしたイメージを使用するので、この項目は省略します。

              ・euca-add-keypair [keypair_name] > keyfilename
              起動したインスタンスへのログインは、公開鍵認証を用います。
              起動時にkeypair名を指定し、対応した秘密鍵を用いて認証する流れになります。
              この元となるkeypairを作成するコマンドです。
              今回はsilverkeyというkeypairを作成、silverkey.privとして秘密鍵を保存しました。
              ついでにパーミッションも変更しておきます。

              gintama@gintama-front:~$ euca-add-keypair silverkey > silverkey.priv
              gintama@gintama-front:~$ chmod 600 ~/silverkey.priv

              ・euca-add-group, euca-describe-group
              細かい権限の設定はgroupという単位で管理されます。
              groupごとに通信を許可するポートの指定などが行えます。
              初期状態ではdefault groupのみが存在します。

              gintama@gintama-front:~$ euca-describe-groups
              GROUP   admin   default default group

              ・euca-run-instances
              インスタンスの起動を行います。
              必ず指定するのはgroup(-g)、keypair(-k)、image_id(emi-*******)の3つ。
              インスタンスのCPU数・メモリ容量・ディスク容量はtype(-t)で指定します。

              gintama@gintama-front:~$ euca-run-instances -g default -k silverkey -t m1.small emi-E0851072
              RESERVATION     r-3339074D      admin   admin-default
              INSTANCE        i-47D5088C      emi-E0851072    0.0.0.0 0.0.0.0 pending silverkey       0               m1.small        2010-06-11T02:35:00.451Z        gintama-front   eki-F6F41100        eri-0B6B1169

              しばらくしてeuca-descibe-instancesを実行すると、

              gintama@gintama-front:~$ euca-describe-instances
              RESERVATION     r-3339074D      admin   default
              INSTANCE        i-47D5088C      emi-E0851072    192.168.11.201  172.19.1.2      running silverkey       0               m1.small        2010-06-11T02:35:00.451Z        gintama-front       eki-F6F41100    eri-0B6B1169

              となり起動していることが確認できます。

              ・euca-authorize
              group単位でのアクセス許可設定です。
              Firewallの設定だと考えていただければ、分かりやすいかと思われます。
              例えば192.168.11.0/24に対してsshを許可するならこんな感じになります。

              gintama@gintama-front:~$ euca-authorize -P tcp -p 22 -s 192.168.11.0/24 default
              GROUP   default
              PERMISSION      default ALLOWS  tcp     22      22      FROM    CIDR    192.168.11.0/24

              前述の通り、sshでのログイン時は公開鍵認証を行います。
              # Storeに登録されているイメージの場合、ユーザIDはubuntuを使用します。

              gintama@gintama-front:~$ ssh -i silverkey.priv ubuntu@192.168.11.201
              Linux ip-172-19-1-2 2.6.32-21-server #32-Ubuntu SMP Fri Apr 16 09:17:34 UTC 2010 x86_64 GNU/Linux
              Ubuntu 10.04 LTS
               
              Welcome to the Ubuntu Server!
               * Documentation:  http://www.ubuntu.com/server/doc
               
                System information as of Fri Jun 11 02:50:13 UTC 2010
               
                System load: 0.17              Memory usage: 23%   Processes:       64
                Usage of /:  42.7% of 1.36GB   Swap usage:   0%    Users logged in: 0
               
                Graph this data and manage this system at https://landscape.canonical.com/
              ---------------------------------------------------------------------
              At the moment, only the core of the system is installed. To tune the
              system to your needs, you can choose to install one or more
              predefined collections of software by running the following
              command:
               
                 sudo tasksel --section server
              ---------------------------------------------------------------------
               
              0 packages can be updated.
              0 updates are security updates.
               
               
              The programs included with the Ubuntu system are free software;
              the exact distribution terms for each program are described in the
              individual files in /usr/share/doc/*/copyright.
               
              Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
              applicable law.
               
              To run a command as administrator (user "root"), use "sudo <command>".
              See "man sudo_root" for details.
               
              ubuntu@ip-172-19-1-2:~$

              起動したインスタンスに無事ログインすることができました。

              だいぶ駆け足でしたが、起動まではこんな感じです。
              インストール作業は基本お任せでやってもらったのですが、何の苦労もなく起動しました。
              もう少し苦戦するだろうと思っていたのですが。。。

              次回は各コマンドの追加説明や、GUIのツールなどについて説明しようと思います。

              1. Cloud Controler, Storage Controller, Warlus []
              2. もう一つはインストーラの手軽さ []
              3. .bashrcであらかじめ読み込むようにしておいたほうが便利です []

                最近CakePHPプラグインづいている小山です。

                今回はCakeDC謹製のSearch Pluginを紹介します。
                (CakePHPのバージョンは1.3.0を想定しています。)

                Search Plugin

                みなさんはCakePHPで検索機能を作るとき、どのように実装していますか?

                たとえば一般的な一覧画面(index)で検索機能を実装しようと思ったら、まずはformを作成して検索条件をPOSTで飛ばして利用すればいいですが、
                さらに最近デフォルトで実装されているページネーション機能と連携して、検索結果でページングを実現しようとするとちょっと面倒です。

                さらに細かい検索条件を実装しようと思ったら、もう考えたくありません。
                自分は新規案件のたびに毎回1からつくっていたような気がします。

                CakePHPのコアデベロッパーの75%を抱える(CakeDCのサイト情報)CakeDCでも、やはり面倒だと思っていたのか、Search Pluginという検索プラグインを作成して使っていたようです。

                最近いくつかのプラグインのソースが公開されたので自分も使ってみました。
                実際に触ってみると面白いくらいに簡単に検索機能が実装できます。

                CakePHPの初期設定

                どれくらい楽かがわかるように、CakePHPをダウンロードしてくるところから実施してみます。

                $ wget http://github.com/cakephp/cakephp1x/tarball/1.3.0
                $ tar zxvf cakephp-cakephp1x-1.3.0-0-g1c06478.tar.gz
                $ mv cakephp-cakephp1x-3bb7793/ cakesearch
                $ cd cakesearch

                次にデータベースを作成します。

                今回はcakesearchというデータベースにpostsというテーブルを作成します。

                次にCakePHPいつもの設定をします。

                appフォルダをそのまま使うつもりですが、app/config/*.phpをいじったりtmpフォルダのパーミッションの設定をするのが面倒なので、今回はbakeコマンドを利用してちょっと楽をします。

                $ php cake/console/cake.php bake

                bakeコマンドメニューの”[D]atabase Configuration”を使ってデータベースの設定をしたあと、”[P]roject”を使ってプロジェクトの設定をします。

                そこで、「What is the full path for this app including the app directory name?」と聞かれるので、ここであえてappフォルダのパスを指定します。

                [/var/www/cakesearch/app/myapp] > /var/www/cakesearch/app

                このあとは導かれるままにEnterを押していくと、app/config/core.phpのSecurity.saltやCakePHP1.3から新たに導入されたSecurity.cipherSeedの設定をしてくれます。app/tmpのパーミッション設定までしてくれています。

                つぎにbakeコマンドを使ってpostsテーブルのMVCのファイルを作成します。

                このとき、「Would you like to create some basic class methods」と聞かれたときにyを選択してindexアクションを作成しておいてください。

                Search Pluginの設定

                さて、ここまででCakePHP自体の設定は終わりです。

                ここからSearch Pluginを導入してみます。

                CakeDCのgithubリポジトリからSearchプラグインをダウンロードして設置します。

                $ cd app/plugins
                $ wget http://github.com/CakeDC/Search/tarball/master
                $ tar zxvf CakeDC-Search-xxxxxx.tar.gz
                $ mv CakeDC-Search-xxxxxx search

                これでSearch Pluginの設置は完了です。
                次にpostsの一覧画面(posts/index)にtitleで検索する機能を実装してみます。

                bakeコマンドで作成されたapp/models/post.phpを以下のように書き換えます。

                $filterArgsは大体想像できると思うのですが、「titleフィールドをLIKEで検索する」ための設定です。typeには他にも完全一致や、サブクエリなどをつかった条件指定などもできます。

                次にapp/controllers/posts_controller.phpを書き換えます。
                (簡単のためindexアクションまでを表示しています)

                $presetVarsは、検索フォーム内のデータを管理するための設定値です。

                $this->Prg->commonProcess()は検索条件のデータのハンドリングを行っています。例えば検索条件自体のバリデーションなどもすることが可能です。

                $this->Post->parseCriteria()は$this->passedArgsと$this->Post->filterArgsを利用して$this->paginateに渡す条件を作成します。

                次にapp/views/posts/index.ctpを書き換えます。
                (簡単のため書き加えた部分周辺のみを表示しています)

                これでbakeコマンドで生成したファイルの修正はすべて終了です。

                なんとこれだけです。
                たったこれだけの修正で、ページネーションと連携したり、検索した条件が保持されたりする検索機能を実装できました。

                まとめ

                今回は、CakeDC謹製 Search Pluginの簡単な導入方法を紹介しました。

                もう少し込み入った使い方などはREADMEなどに詳細に書かれていますので、是非参考にしてみてください。

                • eucalyptus

                Fusic 平田です。
                「次回は」と書きつつ間が開きすぎて申し訳ありません。
                靭帯が切れたりしていたということで、ご容赦ください。。。

                というわけで、前回の続きでEucalyptusインストールのお話です。

                マシンとネットワーク

                今回使用するマシンのスペックは以下になります。
                Dell PowerEdge T105
                CPU: Quad-core AMD Opteron 1354
                メモリ: 4GB
                HDD: 250GB 7,200rpm
                CPUがAMD-V対応であることを条件に選定しています。
                これを2台使用し、それぞれFrontendとBackendとして使用します。

                ネットワーク構成としては、前回の記事にあった
                ネットワーク構成図
                の構成で組むことにします。

                IPアドレスはそれぞれ以下の通り。
                [Frontend] Cluster Controller他1 : 192.168.11.100/24
                [Backend] Node Controller: 192.168.11.101/24

                仮想インスタンスには、内部IPとして自動的に1つのIPアドレスが割り当てられます。
                これはインスタンス同士、あるいはEucalyptus内部の通信に用いられます。
                これとは別に、外部からの通信用に別途IPアドレスを割り当てることが可能です。
                この「仮想インスタンスが外部とのやりとりに使用するIP」がPublic IPです。
                今回はPublic IPとして192.168.11.201-220/24を割り当てます。

                インストール

                Ubuntu公式サイトからUbuntu 9.10 serverのISOファイルをダウンロードし、インストールCDを作成します。
                作成したCDから起動すると、
                言語の選択
                言語の選択が表示されるので「日本語」を選択します。

                Ubuntu 9.10 Serverから、インストール項目に
                インストール画面
                「Ubuntu エンタープライズ クラウドをインストール」が追加されているので、これを選択します。

                以降は通常のUbuntuインストール手順ですが、途中いくつか異なる点があります。
                Cluster選択
                ClusterとNode、どちらとしてインストールするかを選択。
                Clusterの場合は「Cluster」を、
                Node選択
                Nodeの場合は「Node」を選択します。

                ここで注意点をひとつ。
                Ubuntuでは全体、もしくはホームディレクトリの暗号化が可能です。
                ただし、暗号化したファイルシステムを使用した場合は起動imageが正常に動作しないので、今回は暗号化しません。2
                ディスクガイド
                ホームディレクトリ暗号化

                Cluster側は、さらにいくつか設定項目があります。

                Cluster名入力
                Cluster名の入力。
                任意のCluster名を入力してください。

                Public IP入力
                Public IPの入力。
                今回は「192.168.11.201-220」と入力しました。

                以上でインストールは完了です。

                なお、前回の記事で仮想化技術に対応していないCPUのマシンをNodeにしようとした場合は
                Nodeインストール時の警告画面
                こんなのが出ると書きましたが、これが出るのはインストールの最後です。
                結構げんなりすること請け合いですので、Node側のマシン選定にはご注意ください。
                ちなみにCluster側は出ません。3

                インストールはこれで完了です。
                設定まで含めようと思ったのですが、長くなったので次回に回します。

                1. Cloud Controler, Storage Controller, Warlusが一緒に入ります。 []
                2. ホームディレクトリ上で作業する事が多かったので、ホームディレクトリも暗号化していません。 []
                3. 試しに余ったマシンにClusterを入れてみたところ、仮想インスタンスの起動までは動作しました。 []

                  はじめまして。Fusicでエンジニアをしている小山です。
                  普段はPHP(主にCakePHP)とJavaScriptを使って開発を行っています。

                  皆さんは開発を行う時エディタは何を使っていますか?

                  Fusicではエディタについて特に指定はなく、みんなそれぞれ好きなものを使用しています。
                  NetBeansにはじまりEclipseやTextMate、Emacs、Vim。Visual Studioを使うメンバもいます。
                  そして自分はEmacsを愛用しています。ちなみに社内のEmacsユーザはマイノリティです。

                  個人的にはプログラマにとってエディタは料理人にとっての包丁、大工にとってのノミと同じものと思っています。
                  そういう意味でEmacsは、Emacs Lispを利用してかなり自由度をもったカスタマイズができる特徴をもっており、自分にあった環境を作ることができます。

                  ただ、逆にいうと初期設定のEmacsは若干使いにくいのは否めません。

                  そこで、今回はEmacs上に簡単なPHPの開発環境を作成してみます。
                  Emacsのバージョンは22を想定します。

                  .emacs、.emacs.d/の作成

                  Emacsの設定は.emacsファイルなどに記述することで出来ます。
                  この設定ファイルの作り方、書き方にはいろいろな方法があるのですが、
                  今回は以下のようにホームディレクトリに.emacsファイルと.emacs.dディレクトリを作成し
                  その中にelispディレクトリを作成します。

                  ~/
                  |-- .emacs
                  `-- .emacs.d
                      `-- elisp

                  load-pathの設定

                  .emacsや.emacs.dディレクトリだけでなく、elispディレクトリ内にインストールするEmacs Lispを読み込んでもらうためにload-pathの追加をします。
                  .emacsに以下の設定を記述します。

                  (setq load-path
                        (append
                         (list
                          (expand-file-name "~/.emacs.d/elisp/"))
                         load-path))

                  読み込むディレクトリを増やしたい場合(例えば~/.emacs.d/confディレクトリ)は以下のように追加していきます。

                  (setq load-path
                        (append
                         (list
                          (expand-file-name "~/.emacs.d/conf/") ;追加
                          (expand-file-name "~/.emacs.d/elisp/"))
                         load-path))

                  これで最低限の設定は完了しました。
                  M-x load-fileコマンドで.emacsファイルを再読み込みするかEmacsを再起動すると設定が反映されます。

                  本当はここからフォントの設定や文字コードの設定などが必要な場合があるのですが、今回は割愛します。
                  ちなみに自分の設定は以下です。

                  (set-language-environment "Japanese")
                  (set-default-coding-systems 'utf-8)
                  (set-terminal-coding-system 'utf-8)
                  (set-buffer-file-coding-system 'utf-8)
                  (prefer-coding-system 'utf-8-unix)
                  (set-keyboard-coding-system 'utf-8)
                  (setq default-buffer-file-coding-system 'utf-8)

                  auto-install.elのインストール

                  auto-install.elはEmacs Lispのインストールを簡単にするためのEmacs Lispです。
                  大抵のEmacs Lispはauto-install.elで簡単にインストールすることが可能になります。

                  まず、auto-install.elをダウンロードして~/.emacs.d/elisp/ディレクトリに設置します。
                  そして、.emacsに以下の設定を記述します。

                  ;; auto-install
                  (require 'auto-install)
                  (setq auto-install-directory "~/.emacs.d/elisp/") ;Emacs Lispをインストールするディレクトリの指定
                  (auto-install-update-emacswiki-package-name t)
                  (auto-install-compatibility-setup) ;install-elisp.elとコマンド名を同期

                  これでauto-install.elの設定は完了です。

                  Anythingのインストール

                  Anythingは候補選択フレームワークと呼ばれるEmacs Lispです。
                  名前のとおり「何でも」選択候補にあげてくれて選択したものに対していろいろな操作をすることができるEmacs Lispです。
                  Anything環境の構築にはいくつかのEmacs Lispをインストールする必要があるのですが、
                  auto-install-batchを利用して一気にインストールすることができます。

                  M-x auto-install-batchでanythingを選択します。
                  するとEmacsWikiから各種必要なEmacs Lispを取得しインストールが開始されます。
                  途中でインストールを継続するためにC-c C-cと入力していきます。

                  インストール後M-x anythingでAnythingを起動できます。
                  何も設定していない状況では

                  • バッファ
                  • カレントディレクトリのファイル
                  • コマンドの履歴

                  を選択できるようになっています。
                  それぞれに対して

                  • バッファを選択 → そのバッファを表示
                  • カレントディレクトリのファイルを選択 → そのファイルを開く
                  • コマンドの履歴を選択 → コマンドを再実行

                  ができるようになっています。
                  これが「同じインターフェースで何でも選択して、何でも操作する」Anythingの醍醐味です。

                  簡単にanythingを実行できるようにキーバインドを(例えば)C-x bに割り当てておきます。
                  .emacsに以下の設定を記述します。

                  ;; anything
                  (global-set-key (kbd "C-x b") 'anything)

                  今回は詳しい説明は割愛しますが是非使いこなしてみてください。

                  Auto Complete Modeのインストール

                  Auto Complete Modeはインライン上での補完フレームワークです。
                  よくNetBeansやEclipseなどのIDEでソースコード入力中に補完候補を出して選択できるアレです。
                  Auto Complete Modeもauto-install-batchを利用して一気にインストールすることができます。

                  M-x auto-install-batchでauto-complete development versionを選択します。

                  .emacsに以下の設定を記述します。

                  ;; auto-complete
                  (require 'auto-complete)
                  (require 'auto-complete-config)
                  (global-auto-complete-mode t)
                  (setq ac-auto-start t)

                  設定反映後、.emacsのファイル上で文字列を入力すると補完候補がインライン上に表示されると思います。
                  Auto Complete ModeもAnythingと同様フレームワークですので、様々な拡張が可能です。
                  (こちらも詳しい説明は割愛します)

                  PHP Modeのインストール

                  PHP ModeはPHPの開発用のメジャーモードです。
                  PHPのソースコードのシンタックスハイライトやインデント等のサポートをしてくれます。
                  これもauto-install.elを利用してインストールをします。

                  M-x auto-install-from-urlでhttp://php-mode.svn.sourceforge.net/svnroot/php-mode/tags/php-mode-1.5.0/php-mode.elをセットします。
                  (ちなみにM-x install-elispでも構いません)

                  .emacsに以下の設定を記述します。

                  ;; php-mode
                  (require 'php-mode)
                   
                  (setq php-mode-force-pear t) ;PEAR規約のインデント設定にする
                  (add-to-list 'auto-mode-alist '("\\.php$" . php-mode)) ;*.phpのファイルのときにphp-modeを自動起動する

                  php-completionのインストール

                  php-completionはPHP開発用のマイナーモードです。
                  AnythingやAuto Complete Modeのインターフェースを利用してさらにPHPの開発をサポートしてくれます。

                  これもauto-install.elを利用してインストールをします。

                  M-x auto-install-batchでphp-completionを選択します。

                  Auto Complete Modeの設定も合わせて.emacsに以下の設定を記述します。

                  ;; php-mode-hook
                  (add-hook 'php-mode-hook
                            (lambda ()
                              (require 'php-completion)
                              (php-completion-mode t)
                              (define-key php-mode-map (kbd "C-o") 'phpcmp-complete) ;php-completionの補完実行キーバインドの設定
                              (make-local-variable 'ac-sources)
                              (setq ac-sources '(
                                                 ac-source-words-in-same-mode-buffers
                                                 ac-source-php-completion
                                                 ac-source-filename
                                                 ))))

                  これで今回のPHPの開発環境設定は完了です。

                  実際にPHPファイルを開いてみてソースを書いてみたり、
                  C-x bC-oといったキーバインドも実行してみてください。
                  どのような動きをするか体感できると思います(そして是非体感してみてください)。

                  今回紹介した開発環境の設定はほんの一例です。
                  是非さらに自分にあったカスタマイズをしてみてください。

                  これからも、Emacsを普及させるべくPHPに限らず他にも便利なEmacs Lispや設定例を紹介していきたいと思います。