AWS Elastic Beanstalk を使う その12

StandardSessionクラスがSerializableインタフェースを持っているので、Base64エンコードして直列化した文字列をSimpleDBに書き込むような流れになっています。

オブジェクトの文字列化に使ったのはこれ。
ちゃんとテストしていませんがw。
http://www.source-code.biz/base64coder/java/

道半ば。。

package jp.cm.aws.tomcat.session;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.catalina.Session;
import org.apache.catalina.Store;
import org.apache.catalina.session.StandardSession;
import org.apache.catalina.session.StoreBase;

import biz.source_code.base64Coder.Base64Coder;

import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.simpledb.AmazonSimpleDB;
import com.amazonaws.services.simpledb.AmazonSimpleDBClient;
import com.amazonaws.services.simpledb.model.Attribute;
import com.amazonaws.services.simpledb.model.DeleteAttributesRequest;
import com.amazonaws.services.simpledb.model.GetAttributesRequest;
import com.amazonaws.services.simpledb.model.GetAttributesResult;
import com.amazonaws.services.simpledb.model.Item;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.amazonaws.services.simpledb.model.SelectRequest;

public class SimpleDBStore extends StoreBase implements Store {

	private AmazonSimpleDB sdb = null;
	private String myDomain = "SessionPersistence";
	private String mySession = "Session";

	public SimpleDBStore() throws IOException {
		sdb = new AmazonSimpleDBClient(new PropertiesCredentials(
				SimpleDBStore.class
						.getResourceAsStream("AwsCredentials.properties")));

	}

	@Override
	public int getSize() throws IOException {
		String selectExpression = "select * from `" + myDomain + "`";
		SelectRequest selectRequest = new SelectRequest(selectExpression);
		int count = 0;
		for (Item item : sdb.select(selectRequest).getItems()) {
			System.out.println("  Item");
			System.out.println("    Name: " + item.getName());
			for (Attribute attribute : item.getAttributes()) {
				System.out.println("      Attribute");
				System.out.println("        Name:  " + attribute.getName());
				System.out.println("        Value: " + attribute.getValue());
			}
			count++;
		}
		return count;
	}

	@Override
	public String[] keys() throws IOException {
		String selectExpression = "select * from `" + myDomain + "`";
		SelectRequest selectRequest = new SelectRequest(selectExpression);

		List<Item> items = sdb.select(selectRequest).getItems();
		List<String> keyNames = new ArrayList<String>();

		for (Item item : items) {
			keyNames.add(item.getName());
		}
		return (String[]) keyNames.toArray();
	}

	@Override
	public Session load(String id) throws ClassNotFoundException, IOException {
		System.out.println("load : " + id);

		GetAttributesResult result = sdb
				.getAttributes(new GetAttributesRequest().withDomainName(
						myDomain).withItemName(id));

		List<Attribute> list = result.getAttributes();

		StandardSession session = null;
		for (int i = 0; i < list.size(); i++) {
			Attribute attribute = list.get(i);
			if (attribute.getName().equals(mySession)) {
				String value = attribute.getValue();
				session = (StandardSession) fromString(value);
			}
		}

		System.out.println(session.toString());

		return session;
	}

	@Override
	public void remove(String id) throws IOException {
		System.out.println("remove : " + id);

		sdb.deleteAttributes(new DeleteAttributesRequest().withDomainName(
				myDomain).withItemName(id));
	}

	@Override
	public void clear() throws IOException {
		System.out.println("clear");
	}

	@Override
	public void save(Session session) throws IOException {
		System.out.println(session.toString());
		System.out.println("save");

		String id = session.getId();

		sdb.putAttributes(new PutAttributesRequest()
				.withDomainName(myDomain)
				.withItemName(id)
				.withAttributes(
						new ReplaceableAttribute(mySession,
								toString((StandardSession) session), true)));

		System.out.println(toString((StandardSession) session));
	}

	private Object fromString(String s) throws IOException,
			ClassNotFoundException {
		byte[] data = Base64Coder.decode(s);
		ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
				data));
		Object o = ois.readObject();
		ois.close();
		return o;
	}

	private String toString(Serializable o) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(o);
		oos.close();
		return new String(Base64Coder.encode(baos.toByteArray()));
	}

}

AWS Elastic Beanstalk を使う その6

Beanstalkでインスタンス立ち上げると、次に思うのがTomcatのバージョン上げたり、server.xml編集したりいろいろやりたい!ってはず!?

ということで、方法が無いか調べたらあっさり分かりました。

まず、普通にBeanstalkでEnvironmentを作ります。
次にEC2タブのKey Pairsで事前に鍵を用意します。keysample
.pemとかね。

Environmentのコンフィグ画面から先ほど作ったKey Pairを指定します。
これで、普通のEC2インスタンスとしてSSHでログインできるようになります。

こんな感じで入れましたよー。

       __|  __|_  )  Amazon Linux AMI
       _|  (     /     Beta
      ___|\___|___|

ちなみにログインIDは、ec2-user です。rootじゃ入れません。
root系コマンドはsudoでどうぞー。

sudo su -

ログインすれば普通のLinuxですからserver.xmlを修正するとかして、DataSourceの設定とか、セキュリティロールの設定なんかをすればいい。

これで念願のSession Clusteringが実現できるのでは!?と。
基本的にはスティッキーセッションロードバランシングで処理先を固定にしておいて、万が一インスタンスが落ちた際には、他のインスタンスでセッション内容を引き継ぐと。

MySQLをHttpSessionの永続化先にしておけば、オートスケール、ロードバランサー、フェイルオーバーに対応したお気楽クラウド生活が!!

各種設定とか必要なアプリのインストールが終わったらログアウトして、
オリジナルのAMIを作成します。Custom AMI ですね。

最後にBeanstalkのEnvironmentコンフィグ画面で先ほど作成したCustom AMI IDを指定しましょう。

最初っからオリジナルのAMIを使いたいって人もいると思うんですが、AWSとしてはAmazon AMIにはTomcat の再起動や、WARファイルの配備、ログの取得など裏で色々やっているので、Beanstalkで使うにはAmazon AMIからコピーしてほしいってさ。



Editing server.xml, logging in as root
https://forums.aws.amazon.com/thread.jspa?threadID=58723&tstart=0

JVM/Tomcat config questions
https://forums.aws.amazon.com/thread.jspa?threadID=58744&tstart=0

AWS Elastic Beanstalk を使う その7

Tomcatを管理するための設定と等々がされているBeanstalk用のAMIの中身を探っています。

そこで驚愕の事実が!?(大げさかも)

なんと、Tomcatを管理するBeanstalkの肝といえる部分(Host Managerっていうのかな)がRuby1.9.1で書かれています。設定ファイルはYamlで記述されている。他データはSqlite3に保存されているみたい。

Tomcatの死活監視にはbluepillっていうツールが使われているみたい。
ここらへんも勉強になるなぁ。

いいものはどんどん取り入れると。

bluepill
https://github.com/arya/bluepill

AWS Elastic Beanstalk を使う その8

Beanstalkでどうやったらセッションレプリケーションしようかって悩んで調べていたんですがカンタンなやり方が分かりました。Tomcatの基本を知らないオイラが馬鹿だったw。

rootで入ってserver.xmlを設定する必要なかったんですw。
配備するアプリケーション(後でwar化するやつ)にMETA-INFフォルダを作って、
context.xmlを記述すれば反映されることが分かりました。

Beanstalkがどうのこうのではなく、ただのTomcatに配備するアプリ側の設定だけでいけるんですね。

ということは、Beanstalkに配備するアプリの設定だけで、ファイルオーバー対応するためのセッションレプリケーション指定(JDBCStore)できるわけですね。

もー、Beanstalk最強じゃんw。

Tomcat 6 Session Persistence through JDBCStore
http://www.intelligrape.com/blog/2010/07/21/tomcat-6-session-persistence-through-jdbcstore/

Tomcatでフェイルオーバー
http://syo.cocolog-nifty.com/freely/2007/05/tomcat.html

Tomcat 5.5 で session persistence (using JDBCStore)
http://d.hatena.ne.jp/stdcall/20070102/1167688088

ActionScript API for AWS (Amazon Web Services)

出す出すと言ってだいぶ時間が経ってしまいましたが、、、
GitHubにアップしました。

ActionScript からカンタンにAWSへアクセスするためのAPI群です。

とりあえずswcが必要な方はこちらへ

[cmawslib.swc](https://github.com/satoshi7/ActionScript-API-for-AWS-Amazon-Web-Services-/blob/master/bin/cmawslib.swc)

    • 操作できるAPI

Amazon Web Services Query API が提供しているものはほぼ全ての操作に対応しています。

      • EC2 - Amazon Elastic Compute Cloud
      • RDS - Amazon Relational Database Service
      • SQS - Amazon Simple Queue Service
    • 使い方

本コードは Adobe Flex Library Project で作っています。
ご使用の際には Adobe Flash Builder などでプロジェクトのインポートを行い、
アプリケーション側の設定画面からライブラリ追加をしてご利用ください。

    • 開発の仕方

以下のように短いコードを書いて頂ければカンタンにAWSを操作できます。

      • Amazon Elastic Compute Cloud
	var ec2:EC2 = new EC2();
	ec2.setAWSCredentials(AWSKey.key,AWSKey.sec);
	ec2.addEventListener(AWSEvent.RESULT,awsHandler);
	ec2.executeRequest(EC2.DESCRIVE_REGIONS);
	var emr:EMR = new EMR();
	emr.setAWSCredentials(AWSKey.key,AWSKey.sec);
	emr.addEventListener(AWSEvent.RESULT,awsHandler);
	emr.executeRequest(EMR.DESCRIBE_JOB_FLOWS);
      • Amazon Relational Database Service
	var rds:RDS = new RDS();
	rds.setAWSCredentials(AWSKey.key,AWSKey.sec);
	rds.addEventListener(AWSEvent.RESULT,awsHandler);
	rds.executeRequest(RDS.DESCRIBE_DB_INSTANCES);
      • Amazon Simple Notification Service
	var sns:SNS = new SNS();
	sns.setAWSCredentials(AWSKey.key,AWSKey.sec);
	sns.addEventListener(AWSEvent.RESULT,awsHandler);
	sns.executeRequest(SNS.LIST_TOPICS);

	var sdb:SDB = new SDB();
	sdb.setAWSCredentials(AWSKey.key,AWSKey.sec);
	sdb.addEventListener(AWSEvent.RESULT,awsHandler);
	sdb.executeRequest(SDB.LIST_DOMAINS);
	var sqs:SQS = new SQS();
	sqs.setAWSCredentials(AWSKey.key,AWSKey.sec);
	sqs.addEventListener(AWSEvent.RESULT,awsHandler);
	sqs.executeRequest(SQS.LIST_QUEUES);
	var acw:ACW = new ACW();
	acw.setAWSCredentials(AWSKey.key,AWSKey.sec);
	acw.addEventListener(AWSEvent.RESULT,awsHandler);
	acw.executeRequest(ACW.LIST_METRICS);

	var iam:IAM = new IAM();
	iam.setAWSCredentials(AWSKey.key,AWSKey.sec);
	iam.addEventListener(AWSEvent.RESULT,awsHandler);
	iam.executeRequest(IAM.LIST_ACCESS_KEYS);
      • AWS Elastic Beanstalk
	var ebt:EBT = new EBT();
	ebt.setAWSCredentials(AWSKey.key,AWSKey.sec);
	ebt.addEventListener(AWSEvent.RESULT,awsHandler);
	ebt.executeRequest(EBT.DESCRIBE_APPLICATIONS);
	public function awsHandler(event:AWSEvent):void{
		var data:Object = event.data;
		//XML形式のテキストが取得されます。
		ta.text += data.toString();
	}
    • 注意

本ライブラリを使うには、AWSと契約を行って頂き、発行される Access Key ID と Secret Access Key を使用します。
事前にご準備ください。

    • コントリビュータ

[@sato_shi](http://twitter.com/sato_shi/) - Classmethod,Inc. http://classmethod.jp/(http://classmethod.jp/)]


ActionScript API for AWS (Amazon Web Services)
https://github.com/satoshi7/ActionScript-API-for-AWS-Amazon-Web-Services-

AWS Elastic Beanstalk を使う その4

Beanstalk の System.getProperties()で取得できるキーと値一覧

KEY : java.runtime.name VALUE : OpenJDK Runtime Environment
KEY : AWS_ACCESS_KEY_ID VALUE :
KEY : sun.boot.library.path VALUE : /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/i386
KEY : java.vm.version VALUE : 19.0-b06
KEY : shared.loader VALUE :
KEY : java.vm.vendor VALUE : Sun Microsystems Inc.
KEY : java.vendor.url VALUE : http://java.sun.com/
KEY : AWS_SECRET_KEY VALUE :
KEY : path.separator VALUE : :
KEY : tomcat.util.buf.StringCache.byte.enabled VALUE : true
KEY : java.util.logging.config.file VALUE : /usr/share/tomcat6/conf/logging.properties
KEY : java.vm.name VALUE : OpenJDK Client VM
KEY : file.encoding.pkg VALUE : sun.io
KEY : sun.java.launcher VALUE : SUN_STANDARD
KEY : user.country VALUE : US
KEY : sun.os.patch.level VALUE : unknown
KEY : java.vm.specification.name VALUE : Java Virtual Machine Specification
KEY : user.dir VALUE : /usr/share/tomcat6
KEY : java.runtime.version VALUE : 1.6.0_20-b20
KEY : java.awt.graphicsenv VALUE : sun.awt.X11GraphicsEnvironment
KEY : java.endorsed.dirs VALUE :
KEY : os.arch VALUE : i386
KEY : java.io.tmpdir VALUE : /var/cache/tomcat6/temp
KEY : line.separator VALUE :
KEY : java.vm.specification.vendor VALUE : Sun Microsystems Inc.
KEY : java.naming.factory.url.pkgs VALUE : org.apache.naming
KEY : java.util.logging.manager VALUE : org.apache.juli.ClassLoaderLogManager
KEY : os.name VALUE : Linux
KEY : sun.jnu.encoding VALUE : UTF-8
KEY : java.library.path VALUE : /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/i386/client:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/i386:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib
KEY : java.specification.name VALUE : Java Platform API Specification
KEY : java.class.version VALUE : 50.0
KEY : sun.management.compiler VALUE : HotSpot Client Compiler
KEY : os.version VALUE : 2.6.34.7-56.40.amzn1.i686
KEY : user.home VALUE : /usr/share/tomcat6
KEY : catalina.useNaming VALUE : true
KEY : user.timezone VALUE : Universal
KEY : java.awt.printerjob VALUE : sun.print.PSPrinterJob
KEY : file.encoding VALUE : UTF-8
KEY : java.specification.version VALUE : 1.6
KEY : catalina.home VALUE : /usr/share/tomcat6
KEY : JDBC_CONNECTION_STRING VALUE :
KEY : java.class.path VALUE : :/usr/share/tomcat6/bin/bootstrap.jar:/usr/share/tomcat6/bin/tomcat-juli.jar:/usr/share/java/commons-daemon.jar
KEY : user.name VALUE : tomcat
KEY : java.naming.factory.initial VALUE : org.apache.naming.java.javaURLContextFactory
KEY : package.definition VALUE : sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
KEY : java.vm.specification.version VALUE : 1.0
KEY : java.home VALUE : /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre
KEY : sun.arch.data.model VALUE : 32
KEY : user.language VALUE : en
KEY : java.specification.vendor VALUE : Sun Microsystems Inc.
KEY : java.vm.info VALUE : mixed mode
KEY : java.version VALUE : 1.6.0_20
KEY : java.ext.dirs VALUE : /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/ext:/usr/java/packages/lib/ext
KEY : sun.boot.class.path VALUE : /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/resources.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/rt.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/jsse.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/jce.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/charsets.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/netx.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/plugin.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/rhino.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/modules/jdk.boot.jar:/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/classes
KEY : server.loader VALUE :
KEY : java.vendor VALUE : Sun Microsystems Inc.
KEY : catalina.base VALUE : /usr/share/tomcat6
KEY : file.separator VALUE : /
KEY : java.vendor.url.bug VALUE : http://java.sun.com/cgi-bin/bugreport.cgi
KEY : common.loader VALUE : ${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
KEY : sun.io.unicode.encoding VALUE : UnicodeLittle
KEY : sun.cpu.endian VALUE : little
KEY : PARAM5 VALUE :
KEY : package.access VALUE : sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.
KEY : PARAM4 VALUE :
KEY : PARAM3 VALUE :
KEY : PARAM2 VALUE :
KEY : PARAM1 VALUE :
KEY : sun.cpu.isalist VALUE :

AWS Elastic Beanstalk を使う その5

Ruby on Rails を Beanstalk で動かしてみましょう。
まずはじめにgemで環境を整えます。

>gem update
>gem update --system
>gem install rails --version '<3'
>gem install warbler
>gem install jruby-openssl
>gem install rake
>gem install activerecord-jdbcmysql-adapter
>gem install jruby
>gem install jruby-rack

railsをローカルで動かしてみましょう。

>rails -v
Rails 2.3.10
>ruby -v
ruby 1.8.7
>rails railssample
>cd railssample
>ruby script/generate scaffold person name:string age:integer
>rake db:migrate
>ruby script/server

ブラウザでRailsのデフォ画面を表示します。

次にrailsからwarファイルを吐き出すwarblerの手続きです。これいいね。

さっそく

>warble config
>warble war

で完成するはずですが、コケる。。。。只今調査中。。



gemsからのRailsインストール †
http://takeoba.com/index.php?gems%A4%AB%A4%E9%A4%CERails%A5%A4%A5%F3%A5%B9%A5%C8%A1%BC%A5%EB

Warblerでwarファイルを作る
http://rubyist.g.hatena.ne.jp/muscovyduck/20090205/p1

JRuby on Rails on Amazon Elastic Beanstalk
http://blog.headius.com/2011/01/jruby-on-rails-on-amazon-elastic.html