2011年8月16日火曜日

Web Application Components and Interfaces

ここのところ、xSGIもの(WSGI,Rack,JSGI,PSGI,...)を確認中で、ついでに、Webアプリを構成するものとインタフェースを絵(言語ねたを別にした絵) にしてみようと思ってみたけど、難しいなあ。とりあず思いついたやつの、とりあえず0.21版。ちまちま書き変えようかなあ、と。



--
以上

2011年8月15日月曜日

PHP版WSGIを簡単に試してみる(AppServer)

最近、xSGIもの(WSGI,Rack,JSGI,PSGI,...)を確認中で、PHP版WSGIを簡単に試してみるメモです。

ubuntu11で、AppServerを使います。Kelpieというのもあるらしいけど。

・php, pearの環境を準備する。
apt-get install php-pear

・AppServerを準備する。
pear channel-discover pear.symfony-project.com
pear channel-discover pear.indeyets.pp.ru
pear install indeyets/AppServer

・自前のアプリケーションHelloWorldApp.class.phpを準備する。

<?php

class HelloWorldApp{
    public function __invoke($env) {
        return array(200, array('Content-type', 'text/plain'), 'Hello world');
    }
}
bodyの戻り値がただの文字列なのが、AppServerの、ちょっと変わってるところ。

・設定ファイルaip.yamlを準備する。

apps:
  -
    app: &HelloWorldApp
      class: HelloWorldApp
      file: ./HelloWorldApp.class.php
      middlewares: []

servers:
  -
    protocol: HTTP
    socket: 'tcp://0.0.0.0:8090'
    min-children: 5
    max-children: 10
    app: *HelloWorldApp

・実行する。
aip app aip.yaml

・ブラウザから、「http://ご自分のサーバー:8090/」としてみる(ポート番号は設定ファイルのもの)と、「Hello World」と表示される。

--
以上

Rack(ruby版WSGI)を簡単に試してみる(mod_passenger)

最近、xSGIもの(WSGI,Rack,JSGI,PSGI,...)を確認中で、Rack(ruby版WSGI)を簡単に試してみるメモです。

(A) Apache + mod_passenger(mod_rack)で試す。

Apacheで、/に来たリクエストを、自前のrubyスクリプトに任せる設定。UbuntuでApacheとmod_passenger(mod_rack)を使います。

・ubunru 11で、apache2やmod_passenger一式を入れる。
apt-get install libapache2-mod-passenger

・自前のスクリプト一式の置き場所/usr/local/www/rack-scripts/を準備する。

mkdir /usr/local/www/rack-scripts/
mkdir /usr/local/www/rack-scripts/public
mkdir /usr/local/www/rack-scripts/tmp

・自前のスクリプトapplication.wsgiを準備する。
/usr/local/www/rack-scripts/application.rbとして、
class HelloWorldApp
  def call(env)
    [ 200, { 'Content-Type' => 'text/plain' }, ['Hello world'] ]
  end
end

・自前の設定ファイルconfig.ruを準備する。
/usr/local/www/rack-scripts/config.ruとして、
require 'application.rb'
run HelloWorldApp.new

・apacheの設定をする。/に来たリクエストを、mod_passengerに任せる設定。
/etc/apache2/conf.d/rack-rootとして、
<Virtualhost *:80>
    DocumentRoot /usr/local/www/rack-scripts/public
    RackBaseURI /
    <Directory /usr/local/www/rack-script>
      Allow from all
      Options -MultiViews
    </Directory>
</VirtualHost>
(DocumentRootはpublicディレクトリを指定するところが特徴かも)

・apacheをリスタートし

/etc/init.d/apache2 restart

・ブラウザから、「http://ご自分のサーバー/」としてみると、「Hello World」と表示される。


(B) Apacheを使わずに試す。

・ubuntu11で、librack-rubyとruby一式を入れる。

apt-get install librack-ruby1.9.1
※ ruby1.8ならlibrack-ruby1.8

以下、一つのディレクトリ内で、

・自前のスクリプトapplication.rbを準備する。

class HelloWorldApp
  def call(env)
    [ 200, { 'Content-Type' => 'text/plain' }, ['Hello world'] ]
  end
end

・設定ファイルconfig.ruを準備する。

require 'application.rb'
run HelloWorldApp.new

・実行する。

rackup1.9.1 -I .
※ ruby1.8ならrackup1.8

・ブラウザから、「http://ご自分のサーバー:9292/」(ポート番号はコンソール表示を確認)としてみると、「Hello World」と表示される。

・おまけ

ポート番号を変更したい場合は、
rackup1.9.1 -I . -p 8080

オプション-s mongrelとすると、Webアプリケーションサーバーをmongrelに変更できる(デフォルトはWEBrick)はずです。

というかヘルプは、
rackup1.9.1 --help

--
以上

PSGI(Perl版WSGI)を簡単に試してみる

最近、xSGIもの(WSGI,Rack,JSGI,PSGI,...)を確認中で、PSGI(perl版WSGI)を簡単に試してみるメモです。

・ubuntu11で、libplack-perl一式を入れる。

apt-get install libplack-perl

以下、一つのディレクトリ内で、

・自前のスクリプトapplication.psgiを準備する。

sub {
  my $env = shift;
  return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello world" ] ];
};

・実行する。

plackup application.psgi

・ブラウザから、「http://ご自分のサーバー:5000/」(ポート番号はコンソール表示を確認)としてみると、「Hello World」と表示される。

--
以上

JSGI(JavaScript版WSGI)を簡単に試してみる(jack)

最近、xSGIもの(WSGI,Rack,JSGI,PSGI,...)を確認中で、JSGI(JavaScript版WSGI)を簡単に試してみるメモです。

ubuntu11上で、Narwhal(A general purpose JavaScript platform)とJackを使って、試してみます。

ここでは、簡単のために/root/js/ディレクトリ内で操作しています。

・Javaを入れておく

apt-get install openjdk-6-jdk

・narwhalを入れる。ダウンロードして展開するだけ。

https://github.com/280north/narwhalからダウンロードし、出来たディレクトリを、/root/js/narwhalと名前変更する。

パスを通しす。
export PATH=$PATH:/root/js/narwhal/bin

・Jackを入れる。

tusk install jack

・自前のスクリプトjackconfig.jsを準備する。
exports.app = function(env) {
  return { status : 200, headers : {"Content-Type":"text/plain", "Content-Length":"11"}, body : ["Hello worLd"] };
}
※手元の環境ではContent-Lengthが無いとエラーだったので、つけてみました。

・Webアプリケーションサーバーをスタート
jackup

・ブラウザから、「http://ご自分のサーバー:8080/」としてみる(ポート番号はコンソール表示を確認)と、「Hello World」と表示される。

--
以上

2011年8月13日土曜日

WSGIを簡単に試してみる(mod_wsgi)

最近、WSGI系のWebアプリケーションのインタフェース(WSGI,Rack,JSGI,PSGI)に興味があるので、WSGIを簡単に試してみるメモです。Apacheとmod_wsgiを使う例です。

1. Apache + mod_wsgiで簡単に試す

Apacheで、/に来たリクエストを、自前のWSGI/pythonスクリプトに任せる設定。UbuntuでApacheとmod_wsgiを使う。

・ubunru 11で、apache2やmod_wsgi一式を入れる。
apt-get install libapache2-mod-wsgi

・自前のスクリプトapplication.wsgiを準備する。
/usr/local/www/wsgi-scripts/application.wsgiとして、
def application(env, start_response):
  start_response('200 OK', [('Content-type', 'text/plain')])
  return ['Hello world']

・apacheの設定をする。/に来たリクエストを、自前のプログラムapplication.wsgiに任せる設定。
/etc/apache2/conf.d/wsgi-rootとして、
<Virtualhost *:80>
    WSGIScriptAlias / /usr/local/www/wsgi-scripts/application.wsgi

    <Directory /usr/local/www/wsgi-scripts>
    Order allow,deny
    Allow from all
    </Directory>
</VirtualHost>

・apacheをリスタートし
/etc/init.d/apache2 restart

・ブラウザから、「http://ご自分のサーバー/」としてみると、「Hello World」と表示される。

2. もう少しWebアプリケーションっぽく

・Query Stringをエコー(危険)するapplication.wsgi例
def application(env, start_response):
  start_response('200 OK', [('Content-type', 'text/html')])
  return ['insecure query string echo', '<hr>', env['QUERY_STRING'], '<hr>']

ブラウザから、「http://ご自分のサーバー/?test1=hello&test2=world」とかしてみる。query string一式"test1=hello&test2=world"がまるっと表示される。

・いわゆるGET値の取得(ついでに返信時にescapeしてみる)するapplication.wsgi例
from cgi import parse_qs, escape

def application(env, start_response):
  q = parse_qs(env['QUERY_STRING'])
  start_response('200 OK', [('Content-type', 'text/html')])
  return ['hello', '<hr>',escape(q.get('test1', [''])[0]), '<hr>']

ブラウザから、「http://ご自分のサーバー/?test1=hello&test2=world」とかしてみる。test1の値"hello"が、表示される。

ちなみにPOSTは、wsgi.inputを介して受け取るので、少し面倒です。

まじめにアプリケーションを作るには、WSGIの高級なフレームワーク(Djangoなど)を使うのがいいんでしょう。

2011年8月12日金曜日

Webアプリケーションのインタフェース(WSGI, Rack, JSGI, PSGI)

WebアプリケーションのインタフェースxSGI(WSGI, Rack, JSGI, PSGI)のメモ。

Webアプリケーションのインタフェースといっても、いろいろな切り口があるとは思いますが、アプリケーションとサーバー(実行環境)間のインタフェース。PythonのWSGIと、その仲間(Ruby版, Javascript版, Perl版)のこと。シンプルなCGI/Fast CGI/SCGIとも異なるし、古風なxSP系(PHP/ASP/JSP)とも違う感じ。(ここのインタフェースは、それにあわせることで、Webアプリケーションを作る人はいろんなところで動かせる、Webアプリケーション実行環境を作る人はいろいろな人に使ってもらえる、と言うことになります。例えば、WSGIのpythonアプリは、自前のApacheでもクラウドのGoogle App Engineでも、動かせる、みたいな。さらに、中間のフレームワークも、DjangoはWSGIだし、RailsもRackでも。)

1. 簡単なサンプル

text/plainの、Hello Worldを、正常(200)に返す、Webアプリケーションの例(コード断片)。

・WSGI(Python) spec

def application(env, start_response):
  start_response('200 OK', [('Content-type', 'text/plain')])
  return ['Hello world']

・Rack(ruby) spec

class HelloWorldApp
  def call(env)
    [ 200, { 'Content-Type' => 'text/plain' }, ['Hello world'] ]
  end
end

・JSGI(javascript) spec, spec

function(env) {
  return { status : 200, headers : {"Content-Type":"text/plain"}, body : ["Hello world"] };
}

・PSGI(perl) spec

sub {
  my $env = shift;
  return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ] ];
};

・PHP版 (ここでは、kelpieの例)

class HelloWorldApp{
    public function call($env){
        return array(200, array("Content-Type" => "text/plain"), array("Hello world"));
    }
}

2. 使い方(入出力)概要

Requestからの入力値(いわゆるGET値/POST値のもとを含む)は、上記の例ではいずれもenv辞書に入っています。
envの中身は、おおむね以下です。
- CGIでもらえそうなもの:REQUEST_METHOD, SCRIPT_NAME, PATH_INFO, QUERY_STRING, SERVER_NAME, SERVER_PORT, HTTP_Variables
- その他:wsgi.version, wsgi.url_scheme, wsgi.input, wsgi.errors, wsgi.multithread, wsgi.multiprocess, wsgi.run_once等(左はWSGIの例で、Rack/JSGI/PSGIなら、wsgi.の代わりに、rack./jsgi./psgi.で始まる名前で)が、入っています。(wsgi.inputを使うと、Requestのbodyにアクセスできます。input streamとしてアクセスできるので大きなRequestに対応できます。)
(いわゆるGET値はQUERY_STRINGから、POST値はwsgi.inputから、求めることになります。)

Response(出力)は、
- Responseのheaderは、ざっと、文字列・文字列の辞書で、返します。
- Responseのbodyは、おおむね、文字列のリストみたいなもので、返します。(受け取った方が、繰り返し(each)、文字列として取り出せるもの。大きなResponseは、それを生成するようなオブジェクトを返す感じでしょうか。)

アプリケーション自体は、
- WSGIでは、a callable object that accepts two arguments.
- Rackでは、an Ruby object (not a class) that responds to call
- JSGIでは、a JavaScript function
- PSGIでは、a Perl code reference. It takes exactly one argument, the environment and returns an array reference of exactly three values.
として作ることになります。

3. 簡単に試す方法

- WSGIをApache + mod_wsgiで試す例は、こちら
- RackをApache + mod_passenger(mod_rack)で試す例は、こちら
- JSGIをJackで試す例は、こちら
- PSGIを試す例は、こちら
- PHP版のWSGIをAppServerで試す例は、こちら

4. 実行環境例

- WebサーバーとCGI/FastCGI
- Webサーバーとmod_*: mod_wsgi, mod_rack(Phusion Passenger)
- uWSGI(uWSGI単体や、uWSGI+Webサーバー)
- それぞれの言語特有のもの WEBRrick, mongrel, ...
- Google App Engine

※ ここで、Webサーバーは、ApacheやNginx, lighttpd等などいろいろ

5. 利用者例など

エンドユーザが自前のアプリを作るのもありですが、各種フレームワークがxSGIにあわせて作られていたりします。
- WSGI(python): Django, web2py
- Rack(ruby): Rails, Sinatra, Redmine

Javascriptも、JSGI 0.3 Adapter for Nodeなんてのもあります。

--
以上

2011年8月8日月曜日

CentOS6のインストールサーバー

OS/アプリケーションを、一度に、たくさんのサーバーに、入れることがちょいちょいあります。そのときに必要なインストール用のサーバーのメモ。

このインストール用のサーバーがあると、
空のサーバー機(VMでも)に、簡単に(CDメディアとか無しで)、CentOS6をインストールすることが出来るようになります。

1つのサーバーに、
1-1. CentOS6のローカルリポジトリ(http)と、
1-2. PXEブート用のサーバー(dhcpd, tftpd)を、
設定します。(1-1だけ、1-2だけでも、別途利用方法があります)

ここでは、サーバーのIPアドレスは10.0.0.1とします。

1. CentOS6のローカルリポジトリ
1-0. できあがり目標

こんな感じでアクセスできるCentOSのリポジトリができます。
http://10.0.0.1/centos/6/os/x86_64
(本記事は、64bitの場合。32bitなら以下、x86_64をi386に読み替えればいいはず。)

/var/www/html/centos
+-- 6
+-- os
| +-- x86_64 (←ここはDVDまるコピー)
| +-- CentOS
| +-- NOTES
| :
+-- updates
+-- x86_64

使い方
・PXEブートを仕込むと、メディアDVD無しでインストールできます。
・PXEブート+Kickstartファイルを仕込むと、メディアも対話も無しでインストールできます。
・PXEブートを仕込まなくても、netbootのCDメディアからインストールできます。

1-1. 準備
・SELinuxをOFFにしてしまう。
echo 0 > /selinux/enforce
/etc/selinux/configを変更:SELINUX=disabled

1-2. 静的なリポジトリ部分をDVDからのコピー
(ここでCentOS6.0のisoを、/centos/6/osディレクトリへ)

mkdir -p /var/www/html/centos/6/os

1-3. コピー元のDVD(iso)を準備
ここでは以下2ファイルを/var/tmpに配置
CentOS-6.0-x86_64-bin-DVD1.iso
CentOS-6.0-x86_64-bin-DVD2.iso

確認
sha256sum /var/tmp/CentOS-6.0-x86_64-bin-DVD1.iso
期待されるハッシュ値: 3399d1f7bdfb0690a7d5f09e5fe1ec30380646d732ab15e1e5bd9653698ead2c
sha256sum /var/tmp/CentOS-6.0-x86_64-bin-DVD2.iso
期待されるハッシュ値: 46631ac6719fa042c25fa607ac776a654a840606703015b554393ca19371cba9

1-4. CentOS 6.0をコピー

コピー先を作成
mkdir /var/www/html/centos/6/os/x86_64/

DVD1枚目をコピー
mount -o loop /var/tmp/CentOS-6.0-x86_64-bin-DVD1.iso /mnt
cp -vr /mnt/* /var/www/html/centos/6/os/x86_64/
umount /mnt

DVD2枚目をコピー
mount -o loop /var/tmp/CentOS-6.0-x86_64-bin-DVD2.iso /mnt
cp -vruf /mnt/* /var/www/html/centos/6/os/x86_64/
umount /mnt

1-5. updateリポジトリの同期と定期更新設定
updateリポジトリは定期更新することにします。

コピー先ディレクトリを作成
mkdir -p /var/www/html/centos/6/updates/x86_64
mkdir -p /var/www/html/centos/6/extras/x86_64
mkdir -p /var/www/html/centos/6/centosplus/x86_64
mkdir -p /var/www/html/centos/6/contrib/x86_64

コマンドを準備
yum -y install yum-utils createrepo

コピー用スクリプトを作成
cat << EOF > /etc/cron.daily/syncrepo
#!/bin/sh

reposync -r updates -n -p /var/www/html/centos/6/updates/x86_64
cd /var/www/html/centos/6/updates/x86_64
createrepo -d .

reposync -r extras -n -p /var/www/html/centos/6/extras/x86_64
cd /var/www/html/centos/6/extras/x86_64
createrepo -d .

reposync -r centosplus -n -p /var/www/html/centos/6/centosplus/x86_64
cd /var/www/html/centos/6/centosplus/x86_64
createrepo -d .

reposync -r contrib -n -p /var/www/html/centos/6/contrib/x86_64
cd /var/www/html/centos/6/contrib/x86_64
createrepo -d .
EOF

chmod +x /etc/cron.daily/syncrepo

とりあえず手動で一回同期
/etc/cron.daily/syncrepo

1-6. http server
yum -y install httpd


cat << EOF > /etc/httpd/conf.d/centos-repository-mirror.conf
<Directory /centos >
Options +Indexes
Order deny,allow
Deny from all
Allow from 127.0.0.1
Allow from 10.0.0.0/255.255.255.0
</Directory>
EOF

chkconfig httpd on
service httpd start

動作確認
適当なブラウザから、
http://10.0.0.1/centos/6/os/x86_64/RELEASE-NOTES-en-US.html
を閲覧してみる。


2. PXEブートサーバー

2-0. サーバーをPXEブートさせるためのサーバーの設定。

PXEブートは、HDDにOS入っていなくても、CD/DVD/USBのOSを持っていなくてもブートできます。
今時、大抵のサーバーはPXEブートできるはず。

dhcpサーバーとtftpサーバーからなる。

2-1. firewall
面倒だからとりあえず止める

2-2. tftp server
2-2-1. install
yum -y install tftp-server
chkconfig tftp on
chkconfig --list | grep tftp
tftp: on

2-2-2. pxeブート用ファイル

/var/lib/tftpbootディレクトリ
CentOS6.0 x86_64用
(CentOS5は/tftpbootだった)
(設定は、/etc/xinetd.d/tftpのserver_args = -s の後ろのディレクトリ)

mkdir -p /var/lib/tftpboot/cent60x64/pxelinux.cfg

pxelinux.0, vmlinuz, initrd.imgの3ファイルが必要

・pxelinux.0
(rpmから)
cd /var/tmp/
wget http://ftp.jaist.ac.jp/pub/Linux/CentOS/6.0/os/x86_64/Packages/syslinux-3.86-1.1.el6.x86_64.rpm
rpm2cpio syslinux-3.86-1.1.el6.x86_64.rpm | cpio -ivr "*/pxelinux.0"
rename ./usr/share/syslinux/pxelinux.0 ->
とでたら、/var/lib/tftpboot/cent60x64/pxelinux.0

(他には)
http://www.kernel.org/pub/linux/utils/boot/syslinux/

・vmlinuz, initrd.img
OSのDVDから取り出す
mount -o loop /var/tmp/CentOS-6.0-x86_64-bin-DVD1.iso /mnt
cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/cent60x64/
cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/cent60x64/
umount /mnt

デフォルトのブート設定ファイル(別途、MACアドレス毎、MACアドレスの上位桁毎に、設定できます)
cat << EOF > /var/lib/tftpboot/cent60x64/pxelinux.cfg/default
default cent6

label cent6
kernel vmlinuz
append load initrd=initrd.img ksdevice=eth0 devfs=nomount
EOF

例)
MACアドレス01-00-0c-29-17-b3-d4のサーバーが読み込む設定ファイル
/tftpboot/cent60x64/pxelinux.cfg/01-00-0c-29-17-b3-d4

MACアドレス01-00-0c-29-??-??-??のサーバーが読み込む設定ファイル
/tftpboot/cent60x64/pxelinux.cfg/01-00-0c-29

2-2-3. tftpスタート(xinetd経由)
service xinetd start

2-3. dhcp server

2-3-1. インストール
yum -y install dhcp
chkconfig dhcpd on
chkconfig --list | grep dhcpd
dhcpd 0:off 1:off 2:on 3:on 4:on 5:on 6:off

2-3-2. 設定ファイル
cat << EOF > /etc/dhcp/dhcpd.conf
ddns-update-style interim;
ignore client-updates;

subnet 10.0.10.0 netmask 255.255.255.0 {
option routers 10.0.0.254;
option subnet-mask 255.255.255.0;
option domain-name "example.com";
option domain-name-servers 10.0.0.1;
range dynamic-bootp 10.0.0.100 10.0.0.200;
default-lease-time 21600;
max-lease-time 43200;
filename "/cent60x64/pxelinux.0";
next-server 10.0.0.1;
}
EOF
※ CentOS5は/etc/dhcpd.confだったと思う。

※ next-serverがリポジトリサーバー

2-3-3. スタート
service dhcpd start

3. Kickstart

Kickstartファイル(あらかじめOSインストール設定を書いたファイル)を準備すると、
対話無しでインストールできます。

OSの基本設定はもちろん、自由なscriptも、書けるので、
アプリケーションとその設定も、自動で入れてしまえます。

例えば、

基本的な設定
・ネットワークの設定、セキュリティの設定
・sshのログイン用のkey設定
・yumで使うリポジトリを、ローカルリポジトリサーバーを使うようにする設定
などなど。

アプリケーションなら、
・たくさんの、Hadoopのノードの設定
・たくさんの、Webサーバー/アプリケーションサーバーの設定
などなど

4. クライアント、というか、このインストールサーバーを使ったOSインストール

4-1. とりあえず、PXEブートだけ、リポジトリだけ、使うのもあり。
PXEブートする。
Installation Methodで、
いまいちど
http://10.0.0.1/centos/6/os/x86_64
とする。

4-2. PXEブート、リポジトリ、Kickstart設定を、あわせて楽にインストール

Kickstart例を、おいおいメモしておこう...

--