beanstalkでCGIを動かしてみた(AMIカスタマイズ編)

初期状態のAWS Elastic beanstalkでは、CGIを動かす事ができないので、動かせるようにしてみた。

準備

前回の記事を参考に、php5アプリケーションをdeployして環境を動かしておきます。

CGIを置いてみる

ひとまず試しにCGIファイルを置いてみます。

~/work/php5 $ cat test.cgi 
#!/usr/bin/perl
print <<EOF;
Content-type:text/plain

this is cgi test on beanstalk
EOF
~/work/php5 $ chmod +x test.cgi 
~/work/php5 $ ./test.cgi 
Content-type:text/plain

this is cgi test on beanstalk
~/work/php5 $ git add test.cgi
~/work/php5 $ git commit -m "add cgi"
[master 974051d] add cgi
 1 files changed, 7 insertions(+), 0 deletions(-)
 create mode 100755 test.cgi
~/work/php5 $ git aws.push
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 416 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)
remote: 
To https://ACCESSKEY:SIGNATURE@git.elasticbeanstalk.us-east-1.amazonaws.com/repos/70687035/php5test
   71d6bba..974051d  HEAD -> master

~/work/php5 $ curl http://php5test.elasticbeanstalk.com/test.cgi
#!/usr/bin/perl
print <<EOF;
Content-type:text/plain

this is cgi test on beanstalk
EOF

プログラムがそのまま出ちゃいました。どうやら、サーバ側でCGIが認識されないような設定になっているようです。.htaccessで追加してみましょう。

~/work/php5 $ cat .htaccess 
AddHandler cgi-script cgi
Options +ExecCGI
~/work/php5 $ git add .htaccess
~/work/php5 $ git commit -am "add ExecCGI"
[master ecaba42] add ExecCGI
 1 files changed, 1 insertions(+), 0 deletions(-)
~/work/php5 $ git aws.push
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 349 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: 
To https://ACCESSKEY:SIGNATURE@git.elasticbeanstalk.us-east-1.amazonaws.com/repos/70687035/php5test
   974051d..ecaba42  HEAD -> master
~/work/php5 $ curl http://php5test.elasticbeanstalk.com/test.cgi
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>
</head><body>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete
your request.</p>
<p>Please contact the server administrator,
 root@localhost and inform them of the time the error occurred,
and anything you might have done that may have
caused the error.</p>
<p>More information about this error may be available
in the server error log.</p>
<hr>
<address>Apache/2.2.22 (Amazon) Server at php5test.elasticbeanstalk.com Port 80</address>
</body></html>

少し前進。エラーメッセージが変わりました。Internal Server Errorになっているようです。実際にインスタンスにログインしてログを調べてみると...

# cat /var/log/httpd/application-error_log 
[Wed Apr 04 09:45:55 2012] [error] [client 10.209.199.0] Options ExecCGI is off in this directory: /var/www/html/test.cgi
[Wed Apr 04 09:48:36 2012] [error] [client 10.209.199.0] (13)Permission denied: exec of '/var/www/html/test.cgi' failed
[Wed Apr 04 09:48:36 2012] [error] [client 10.209.199.0] Premature end of script headers: test.cgi

oh, Permission deniedのようです。deploy前にchmod +xしたはずなのですが。

# ls -al /var/www/html/test.cgi 
-rw-r--r-- 1 elasticbeanstalk elasticbeanstalk 88 Apr  4 09:48 /var/www/html/test.cgi

なんてこったい、実行権限が落ちてます。色々と調べていると、deployの際にこんなスクリプトが呼ばれていました。

# grep chmod /tmp/php_deploy_app.sh 
/usr/bin/sudo /bin/chmod -Rf 0755 /tmp/php-elasticbeanstalk-deployment/application
/bin/find /tmp/php-elasticbeanstalk-deployment/application -type f -print0 | /usr/bin/xargs -0 /bin/chmod 0644

とりあえず755にしておいて、ファイルすべてを644にするという方法のようです。PHPなら644でも動きますので、一応理にかなってはいますが。
このスクリプトは、/opt/elasticbeanstalk/srv/hostmanager/lib/elasticbeanstalk/hostmanager/applications/phpapplication.rb で都度生成されるようですので、パッチ当てます(2つめの644にする部分をコメントアウト)。

~/work/php5 $ git diff
diff --git a/test.cgi b/test.cgi
index 4cb7af5..1c0375a 100755
--- a/test.cgi
+++ b/test.cgi
@@ -2,5 +2,5 @@
 print <<EOF;
 Content-type:text/plain
 
-this is cgi test on beanstalk
+this is cgi test on beanstalk!
 EOF
~/work/php5 $ git commit -am 'touch!'
[master 0b896e4] touch!
 1 files changed, 1 insertions(+), 1 deletions(-)
~/work/php5 $ git aws.push
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 271 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: 
To https://ACCESSID:SIGNATURE@git.elasticbeanstalk.us-east-1.amazonaws.com/repos/70687035/php5test
   ecaba42..0b896e4  HEAD -> master
~/work/php5 $ curl http://php5test.elasticbeanstalk.com/test.cgi
this is cgi test on beanstalk!

まずはこのインスタンスCGIが動くようになりました。

落とし穴

しかし、このインスタンスをTerminateして落としてしまうと、しばらくして別のインスタンスが自動的に起動して復旧するはするのですが、

~/work/php5 $ curl http://php5test.elasticbeanstalk.com/test.cgi
#!/usr/bin/perl
print <<EOF;
Content-type:text/plain

this is cgi test on beanstalk!
EOF

と、元の状態にもどってしまいます。これは、PHP5.3用のBeanstalk AMIを使用しているためとなります。そこで、カスタムAMIを作成します。

カスタムAMI作成

BeanstalkからだとAutoScaling経由となってしまうので、Beanstalkからではなく直接AMIを指定してカスタマイズ用のインスタンスを起動します。
64bitであれば、PHPBeanstalk64-2012.03.30 (ami-f759879e)が該当します。このAMIを利用してインスタンスを立ち上げ、上記のパッチ(cmod 0644を行う行をコメントアウト)を行い、CreateImageでAMIにします。

環境設定変更

Environmentの設定を変更し、カスタムAMIを使用するようにします。


しばらくするとインスタンスが入れ替わり、StatusがGREENに戻ったら確認します。

~/work/php5 $ curl http://php5test.elasticbeanstalk.com/test.cgi
this is cgi test on beanstalk!

無事に入れ替わりました!

環境設定保存

同じ設定を今後も使用したい場合に、この設定を保存する事ができます。


まとめ

今回は単にCGIを有効にしたいという物でしたが、色々なライブラリなどを追加したAMIが欲しい場合などには、このようにして作成してください。