FastCGI with mod_fastcgi
mod_fcgidとmod_fastcgiは別物という事実にショックを受けつつ、気を取り直してmod_fastcgiをインストールしてみる。
インストール
既にyumからapacheをinstallしているので、DSOでインストールする。
ちなみにDSOはDynamic Shared Objectの略で、実行時にLoadModuleディレクティブで読み込めるApacheモジュールのこと。そしてapxsはAPache eXtenSion toolのことである。
wget http://www.fastcgi.com/dist/mod_fastcgi-2.4.6.tar.gz tar zxfv mod_fastcgi-2.4.6.tar.gz cd mod_fastcgi-2.4.6
apache 1.3なら以下でOKらしいが、apache2だとうまくいかない...
# for apache 1.3... apxs -o mod_fastcgi.so -c *.c apxs -i -a -n fastcgi mod_fastcgi.so
INSTALL.AP2を見ると、以下のように書かれているので、これに従う。
$ cd <mod_fastcgi_dir> $ cp Makefile.AP2 Makefile $ make $ make install
ただし、top_dirを自分のinstallディレクトリに合わせる必要あるので、下記の通り書き直した。
#top_dir = /usr/local/apache2 top_dir = /usr/lib/httpd
/etc/httpd/conf/httpd.confを確認する。無事インストールされている模様。
LoadModule fastcgi_module /usr/lib/httpd/modules/mod_fastcgi.so
設定
まずは単純なfastcgiスクリプトとして動かそう、ということで/etc/httpd/conf.d/fastcgi.confに以下を記述してapache再起動する。なお、kotaro:kotaro(user:group)でhttpdが動作してる前提。
ScriptAlias /fcgi/ /home/kotaro/fcgi/
fcgiスクリプト
以下をScriptAlias設定した、ディレクトリ/home/kotaro/fcgiにhello.fcgiというファイル名で置く。実行権限はちゃんと付けておく。
#!/usr/bin/perl use CGI::Fast; while (my $q = CGI::Fast->new) { print("Content-Type: text/plain\n\n"); foreach $var (sort(keys(%ENV))) { $val = $ENV{$var}; $val =~ s|\n|\\n|g; $val =~ s|"|\\"|g; print "${var}=\"${val}\"\n"; } }
http://localhost/fcgi/hello.fcgi
で動いた!!!
ただし、これだと単なるCGIスクリプトと何も変わらない。プロセス常駐してこそFastCGIの意味があるのだが、方法はstatic, dynamic, externalの3つがある。まずはstaticからトライ。
static
/etc/httpd/conf.d/fastcgi.confを以下に設定
Alias /fcgi/ /home/kotaro/fcgi/ FastCgiServer /home/kotaro/fcgi/hello.fcgi -processes 5
これだと動かないので、/var/log/httpdのpermission変更する。
chmod o+x /var/log/httpd
確認すると...
[root@mdev1 ~]# ps aux | grep fcgi kotaro 1758 0.0 0.1 9976 1896 ? S 19:33 0:00 /usr/sbin/fcgi- kotaro 1759 0.0 0.3 5004 3148 ? S 19:33 0:00 /usr/bin/perl /home/kotaro/fcgi/hello.fcgi kotaro 1769 0.0 0.2 4812 2852 ? S 19:33 0:00 /usr/bin/perl /home/kotaro/fcgi/hello.fcgi kotaro 1770 0.0 0.2 4812 2820 ? S 19:33 0:00 /usr/bin/perl /home/kotaro/fcgi/hello.fcgi kotaro 1771 0.0 0.2 4812 2812 ? S 19:33 0:00 /usr/bin/perl /home/kotaro/fcgi/hello.fcgi kotaro 1772 0.0 0.2 4812 2816 ? S 19:33 0:00 /usr/bin/perl /home/kotaro/fcgi/hello.fcgi
ちゃんとfcgiのプロセスが動いてますね〜。ふぅ。
PSGI/Plackに挑戦
CGI/FastCGIの仕組みがわかり、ようやくPlackにチャレンジ。
インストール
これでPlack関連のモジュールをまとめてinstallできる。
cpanm Task::Plack
Hello PSGI!
まずはPSGIの基本形をやろう、ということで以下のコードリファレンスをhello.psgiとして保存。
use strict; my $app = sub { my $env = shift; return [ 200, [ 'Content-Type' => 'text/plain' ], [ "Hello PSGI!" ], ]; };
これをplackupすると、PSGIアプリケーションが起動する。HTTPサーバは指定してないのでHTTP::Server::PSGIが自動的に選ばれた。
kotaro@mdev1:~> plackup psgi/hello.psgi HTTP::Server::PSGI: Accepting connections at http://0:5000/
http://localhost:5050/にアクセスすると、「Hello PSGI!」と表示される
Hello PSGI with FastCGI
今度はFastCGIをサーバにして、PSGIアプリを動かしてみる。
FastCGIはExternalにし、Unixドメインソケットを通して、PSGIアプリとやり取りする。
FastCgiExternalServer /var/www/html/hello.fcgi -socket hello.sock
- plackup
kotaro@mdev1:~> plackup -s FCGI --listen /var/log/httpd/fastcgi/hello.sock psgi/hello.psgi
Unixドメインソケットがlistenになってるか調べると、確かにlistenステータス。
kotaro@mdev1:~> netstat --unix -l | grep hello.sock unix 2 [ ACC ] STREAM LISTENING 111707 /var/log/httpd/fastcgi/hello.sock
この状態で、http://localhost/hello.fcgi/にアクセスすれば、「Hello PSGI!」と表示された。
一度理解すれば大したことじゃないけど、辿り着くにはだいぶ時間かかりました。。
サーバプロセス数を増やす
Plack::Handler::FCGIのSYNOPSISみてたら、--nprocオプションが使えるみたい
kotaro@mdev1:~> plackup -s FCGI --listen /var/log/httpd/fastcgi/hello.sock psgi/hello.psgi --nproc 5 FastCGI: manager (pid 13481): initialized FastCGI: server (pid 13482): initialized FastCGI: manager (pid 13481): server (pid 13482) started FastCGI: server (pid 13483): initialized FastCGI: manager (pid 13481): server (pid 13483) started FastCGI: server (pid 13484): initialized FastCGI: manager (pid 13481): server (pid 13484) started FastCGI: manager (pid 13481): server (pid 13485) started FastCGI: server (pid 13485): initialized FastCGI: server (pid 13486): initialized FastCGI: manager (pid 13481): server (pid 13486) started
Apache + CGI再入門
いつもフレームワークの上でしか書いてないので、きちんと理解したい。
CGI Specification
http://httpd.apache.org/docs/2.0/en/howto/cgi.html
The CGI (Common Gateway Interface) defines a way for a web server to interact with external content-generating programs, which are often referred to as CGI programs or CGI scripts. It is the simplest, and most common, way to put dynamic content on your web site. This document will be an introduction to setting up CGI on your Apache web server, and getting started writing CGI programs.
つまり、CGIというのは外部プログラムとの協調方法を定義するもの(=仕様)
http://www.ietf.org/rfc/rfc3875.txt
The CGI defines the abstract parameters, known as meta-variables,
which describe a client's request. Together with a concrete
programmer interface this specifies a platform-independent interface
between the script and the HTTP server.The server is responsible for managing connection, data transfer,
transport and network issues related to the client request, whereas
the CGI script handles the application issues, such as data access
and document processing.
'meta-variable'
A named parameter which carries information from the server to the
script. It is not necessarily a variable in the operating
system's environment, although that is the most common
implementation.'script'
The software that is invoked by the server according to this
interface. It need not be a standalone program, but could be a
dynamically-loaded or shared library, or even a subroutine in the
server. It might be a set of statements interpreted at run-time,
as the term 'script' is frequently understood, but that is not a
requirement and within the context of this specification the term
has the broader definition stated.'server'
The application program that invokes the script in order to
service requests from the client.
単純化すれば、CGIはリクエストをmeta-variablesで表現し、HTTPサーバはリクエストを処理し、CGI scriptをinvokeし、データをクライアントに戻す責務を持つ、と。
で、Apacheのドキュメントを再度みてみる。
http://httpd.apache.org/docs/2.0/ja/howto/cgi.html
サーバとクライアント間のもう一つの通信は、標準入力 (STDIN)と標準出力 (STDOUT) を通じて行なわれます。通常の文脈において、STDIN はキーボードやプログラムが動作するために与えられるファイルを意味し、 STDOUT は通常コンソールまたはスクリーンを意味します。
ウェブフォームから CGI プログラムへPOST したとき、フォームのデータは特別なフォーマットで束ねられ、 STDIN を通して、CGI プログラムに引き渡されます。 プログラムはデータがキーボード もしくはファイルから来ていたかのように処理することができます。
なるほど。完全に理解。
exec CGI
CentOS + ApacheでperlとpythonのCGI scriptを試してみる。
まず、/etc/httpd/conf/httpd.confにScriptAliasを設定する
ScriptAlias /cgi-bin/ /home/kotaro/cgi-bin/
次いで、/home/kotaro/cgi-binにperl.cgiとpython.cgiを作成。もちろんpermissionは適切に設定する。
- perl.cgi
#!/usr/bin/perl print "Content-type: text/html\n\n"; for my $key (keys %ENV) { printf "%s => %s<br>", $key, $ENV{$key}; }
- python.cgi
#!/usr/bin/python import os print "Content-type: text/html\n\n" for k, v in os.environ.iteritems(): print "%s: %s<br>\n" % (k, v)
これでhttp://localhost/cgi-bin/perl.cgi, http://localhost/cgi-bin/python.cgiにアクセスすれば、環境変数が表示される。
まとめ
- CGIはHTTPリクエストに対して、CGI scriptをinvokeし、環境変数と標準入力を渡す
- 環境変数にはREQUEST_URI, QUERY_STRINGなどが入り、標準入力にはPOSTデータが入る
- CGI scriptはContent-TypeとHTTP Bodyを標準出力に出す
FastCGI with mod_fcgid
mod_fcgidというApacheモジュールがあるので、これでFastCGIを動かせるものかと思ってやってみる。
手順はhttp://www.movabletype.jp/documentation/developer/server/fastcgi.htmlにほぼ沿ってる。
インストール
# 必要なCPANモジュール cpanm FCGI cpanm CGI # ライブラリ インストール sudo su - yum install httpd-devel wget http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz tar zxfv fcgi-2.4.0.tar.gz -C /usr/local/src/ cd /usr/local/src/fcgi-2.4.0 ./configure make make install # mod_fcgid インストール wget http://ftp.riken.jp/net/apache/httpd/mod_fcgid/mod_fcgid-2.3.5.tar.gz tar zxvf mod_fcgid-2.3.5.tar.gz -C /usr/local/src/ cd /usr/local/src/mod_fcgid-2.3.5/ ./configure.apxs make make install
httpd.conf
- /etc/httpd/conf.d/fcgid.conf
ScriptAlias /fcgi/ /home/kotaro/fcgi/ <IfModule mod_fcgid.c> AddHandler fcgid-script .fcgi SocketPath /tmp/fcgid_sock/ IPCConnectTimeout 20 MaxProcessCount 8 DefaultMaxClassProcessCount 2 TerminationScore 10 SpawnScore 80 IdleTimeout 300 </IfModule>
fcgi script
mkdir /home/kotaro/fcgi vi fcgi/hello.fcgi
http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.htmlから拝借したスクリプトを置く
#!/usr/bin/perl use lib '/home/kotaro/perl5/lib'; use lib '/home/kotaro/perl5/lib/perl5/i386-linux-thread-multi'; use CGI::Fast; while (my $q = CGI::Fast->new) { print("Content-Type: text/plain\n\n"); foreach $var (sort(keys(%ENV))) { $val = $ENV{$var}; $val =~ s|\n|\\n|g; $val =~ s|"|\\"|g; print "${var}=\"${val}\"\n"; }
あとはpermissionを設定し、http://localhost/fcgi/hello.fcgiすれば動く!
が、ここまで来て、
http://www.mail-archive.com/mod-fcgid-users@lists.sourceforge.net/msg00222.html
> Is "FastCgiExternalServer" supported by mod_fcgid?
mod_fastcgi and mod_fcgid are totally different modules and don't even
share a common codebase. They have only the FastCGI protocol in common.
Thus, Apache Directives are totally different. Besides, mod_fcgid has an
adaptive-spawning design and does not support "Static" servers or
External servers.I guess the short answer is : no, and not planned.
という文章を見つけて凹む。。。