funasaki memo

このブログ上の投稿は個人のものであり、所属する企業を代表する投稿ではありません。所属:AWSのSolutions Architect

AWS Security Token Serviceを使ってみる

AWS SDKやAWSコマンドラインツールを使う場合、Security Credentialsが必要になります。Security Credentialsの中にはアクセスキーとシークレットアクセスキーが含まれています。AWSのサービスやリソースをAPIを使って管理するときには、この2つのキーを使って認証します。

この2つのキーをどうやって保管するか?が本記事の目標とするところです。

2つのキーをソースコードやもしくはテキストファイル、DB等に格納して使うこともできますが、これだとキーの置き換えをするのが大変です。そこでAWSから提供されているSecurity Token Serviceというサービスを使って、キーの管理を安全に、かつ効率的に行うことを試してみました。

Security Token Serviceとは?
一時的な、かつ制限された特権を持つAWSアカウント、またはIAMユーザのCredential情報を取得可能にする機能です。Security Token Serviceは、以下の3つのアクションが可能です。

AWS SDKでSecurity Token Serviceより権限を取得できる。対応しているSDKは2013/04/16時点では以下。

http://docs.aws.amazon.com/STS/latest/UsingSTS/AccessingSTS.html

AWS SDK for Javaを使って、GetSessionTokenした例が以下。今回は取得した権限でS3のバケットリストを表示させている。

import java.io.IOException;
import java.util.List;

import com.amazonaws.AmazonWebServiceClient;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import com.amazonaws.services.securitytoken.model.Credentials;
import com.amazonaws.services.securitytoken.model.GetSessionTokenRequest;
import com.amazonaws.services.securitytoken.model.GetSessionTokenResult;


public class MySecurityTokenSample {

	public static void main(String[] args) throws IOException {
		
		//STSからトークンを取得するために必要なCredential情報
		AWSCredentials credentials = new PropertiesCredentials(
                MySecurityTokenSample.class.getResourceAsStream("AwsCredentials.properties"));
		
		//SecurityTokenServiceClientの設定
		AWSSecurityTokenServiceClient sts = new AWSSecurityTokenServiceClient(credentials);
		GetSessionTokenRequest req = new GetSessionTokenRequest();
		GetSessionTokenResult res = sts.getSessionToken(req);
		Credentials tmpCredentials = res.getCredentials();
		String accessKeyId = tmpCredentials.getAccessKeyId();
		String secretAccessKeyId = tmpCredentials.getSecretAccessKey();

		//取得したアクセスキー、シークレットアクセスキーでS3のバケットリストを表示してみる。
		BasicSessionCredentials c = new BasicSessionCredentials(tmpCredentials.getAccessKeyId(),
				tmpCredentials.getSecretAccessKey(), tmpCredentials.getSessionToken());
		AmazonS3Client s3Client = new AmazonS3Client(c);
		s3Client.setEndpoint("s3-ap-northeast-1.amazonaws.com");
					
		List<Bucket> list = s3Client.listBuckets();
		for(Bucket b : list) {
			System.out.println(b.getName());
		}
	}
}

こちらを実行すると、バケット名のリストが表示された。
トークンを取得するためには、やはりSecurity Credentialsの情報が必要。なので、システムの中に1台だけトークン管理サーバなるものを立てて、そこの中では唯一Credentials情報を持つ。他のサーバで一時的にCredentials情報が必要な場合は、このサーバが何かしらの安全な方法で配ってあげる形が良さそう。取得したトークンは、デフォルトで12時間まで有効。その時間が過ぎると無効になる。以下のように実行することで、その時間も変更できる。

getSessionTokenRequest.setDurationSeconds(7200); 

上記例では、AWSアカウントの権限を取得していたが、以下のようにgetFederatedTokenを使って指定したIAM Userの権限を取得もできる。

import java.io.IOException;
import java.util.List;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import com.amazonaws.services.securitytoken.model.Credentials;
import com.amazonaws.services.securitytoken.model.GetFederationTokenRequest;
import com.amazonaws.services.securitytoken.model.GetFederationTokenResult;
import com.amazonaws.services.securitytoken.model.GetSessionTokenRequest;
import com.amazonaws.services.securitytoken.model.GetSessionTokenResult;


public class MySecurityTokenSample2 {

public static void main(String[] args) throws IOException {
		
		//STSからトークンを取得するために必要なCredential情報
		AWSCredentials credentials = new PropertiesCredentials(
                MySecurityTokenSample.class.getResourceAsStream("AwsCredentials.properties"));
		
		//SecurityTokenServiceClientの設定
		AWSSecurityTokenServiceClient sts = new AWSSecurityTokenServiceClient(credentials);
		GetFederationTokenRequest req = new GetFederationTokenRequest();
		req.setName("TVMUser1");
		req.setPolicy("{\"Statement\": [{\"Effect\": \"Allow\",\"Action\": \"s3:*\",\"Resource\": \"*\"}]}");
		GetFederationTokenResult res = sts.getFederationToken(req);
		Credentials tmpCredentials = res.getCredentials();
		
		//取得したアクセスキー、シークレットアクセスキーでS3のバケットリストを表示してみる。
		BasicSessionCredentials c = new BasicSessionCredentials(tmpCredentials.getAccessKeyId(), 
				tmpCredentials.getSecretAccessKey(), tmpCredentials.getSessionToken());
		AmazonS3Client s3Client = new AmazonS3Client(c);
		s3Client.setEndpoint("s3-ap-northeast-1.amazonaws.com");
					
		List<Bucket> list = s3Client.listBuckets();
		for(Bucket b : list) {
			System.out.println(b.getName());
		}
	}
}

TVMUser1というIAM Userで、S3のみにアクセス可能なポリシーをJSONで書いたものを使ってGetFederationTokenしている。
req.setPolicyでは以下のJSONデータを引数に入れている。

{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": "*"
    }
  ]
}

このように、Security Token Serviceを使えば、一時的なCredentials情報を取得できることがわかった!

リンク

DynamoDBでscanを実行してみる

DynamoDBのテーブル名が SampleTable, AttributeがIdとNameのみのテーブルに対してScanを実行した。

AWS SDK for Javaで以下のように実行してみた。

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.dynamodb.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodb.model.AttributeValue;
import com.amazonaws.services.dynamodb.model.ComparisonOperator;
import com.amazonaws.services.dynamodb.model.Condition;
import com.amazonaws.services.dynamodb.model.GetItemRequest;
import com.amazonaws.services.dynamodb.model.GetItemResult;
import com.amazonaws.services.dynamodb.model.Key;
import com.amazonaws.services.dynamodb.model.PutItemRequest;
import com.amazonaws.services.dynamodb.model.PutItemResult;
import com.amazonaws.services.dynamodb.model.ScanRequest;
import com.amazonaws.services.dynamodb.model.ScanResult;


public class DynamoDBLoadGenerator {

	static AmazonDynamoDBClient dynamoDB;
	
	public static void main(String[] args) throws IOException {
		//Credentialsの設定
		AWSCredentials credentials = new PropertiesCredentials(
                DynamoDBSample.class.getResourceAsStream("AwsCredentials.properties"));

		//リクエストのパラメータの設定
                dynamoDB = new AmazonDynamoDBClient(credentials);
                dynamoDB.setEndpoint("http://dynamodb.ap-northeast-1.amazonaws.com");
                String tableName = "SampleTable";
        
         

                //ScanFilterConditionの設定
                Condition scanFilterCondition = new Condition()
    	               .withComparisonOperator(ComparisonOperator.LT.toString())   //〇〇よりも小さい
    	               .withAttributeValueList(new AttributeValue().withN("500")); //500
        
                Map<String, Condition> conditions = new HashMap<String, Condition>();
                conditions.put("Id", scanFilterCondition);
        
    	        ScanRequest scanRequest = new ScanRequest()
    		       .withTableName(tableName)
    		       .withScanFilter(conditions)
    		       .withAttributesToGet(Arrays.asList("Id")); //Idに対してScanFilterを実行

    	       //Scan実行
    	       ScanResult scanResult = dynamoDB.scan(scanRequest);
    
               //結果表示
               for (Map<String, AttributeValue> item : scanResult.getItems()){
        	     System.out.println(item.get("Id"));
               }
	}
}

実行結果は以下のように出力される。

{N: 251, }
{N: 187, }
{N: 154, }
{N: 7, }
{N: 115, }
{N: 286, }
{N: 361, }
{N: 380, }
{N: 117, }
{N: 401, }
{N: 47, }
{N: 184, }
{N: 403, }
{N: 304, }
{N: 156, }
{N: 122, }
{N: 273, }
以下省略

IDが500以下のデータが出力された。
また今回使用したScanFilterConditionでComparisonOperatorで、BETWEENやBEGIN WITHやCONTAINなどいろいろ指定できる。今回使ったのはLT(おそらくはLess Thanのことだと思う)。これでscanするフィルターをいろいろ設定できそう。

試しにNameが"Book 500"とイコールであるIdをFilterConditionで指定したのが以下。

        //ScanFilterConditionの設定
        Condition scanFilterCondition = new Condition()
    	.withComparisonOperator(ComparisonOperator.EQ.toString())
    	.withAttributeValueList(new AttributeValue().withS("Book 500"));


以下はComparisonOperatorのJavaDoc
[http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodb/model/ComparisonOperator.html:title=
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodb/model/ComparisonOperator.html]

AWS OpsWorksで起動されたインスタンスの中身を見てみる

AWS OpsWorksを使ってHAProxyのレイヤーを追加し、HAProxyインスタンスを立ち上げてみる。

自分のkeypairを使うように設定すれば、SSHでログインすることができる。

早速ログインしてみる。
ec2-userでログインができた。

OpsWorksの動作に関連しそうなものは以下のディレクトリにあった。

[ec2-user@stratus aws]$ sudo ls opsworks/current/bin
chef-client               gli             opsworks-agent-cli        restclient
chef-solo                 knife           opsworks-agent-installer  s3curl.pl
convert_to_should_syntax  lockrun         opsworks-agent-updater    shef
edit_json.rb              nokogiri        prettify_json.rb          thor
erubis                    ohai            rake
extract                   opsworks-agent  rake2thor

chef-soloやchef-client, opsworks-agent-cliなどがある。
AWSのドキュメントには、それぞれのインスタンスでchef-soloが動いていると書かれていた。
以下抜粋

Here's how it works: Chef Solo runs on every instance, and AWS OpsWorks sends commands to each instance to run recipes that set up, configure, and shut down the instance. You can extend these actions with your own custom recipes. You can also run your custom recipes on a specific instance or on all instances in your stack. 

さらにopsworks-agent-cliで以下のようなコマンドも実行できる。

  • agent_report
  • get_json
  • instance_report
  • list_commands
  • run_command
  • show_log
  • stack_state

詳細は以下。
http://docs.aws.amazon.com/opsworks/latest/userguide/agent.html

試しにget_jsonコマンドを実行してみた。(環境をまるさらしだが、すぐ消すので良しとしよう。。)

$ sudo opsworks/current/bin/opsworks-agent-cli get_json
{
  "recipes": [
    "opsworks_custom_cookbooks::load",
    "opsworks_ganglia::configure-client",
    "ssh_users",
    "agent_version",
    "haproxy::configure",
    "opsworks_stack_state_sync",
    "opsworks_custom_cookbooks::execute",
    "test_suite",
    "opsworks_cleanup"
  ],
  "opsworks_bundler": {
    "version": "1.0.10",
    "manage_package": null
  },
  "opsworks_rubygems": {
    "version": "1.8.24"
  },
  "opsworks": {
    "deployment": null,
    "valid_client_activities": [
      "reboot",
      "stop",
      "setup",
      "configure",
      "update_dependencies",
      "install_dependencies",
      "update_custom_cookbooks",
      "execute_recipes"
    ],
    "applications": [
      {
        "application_type": "php",
        "slug_name": "php_app",
        "name": "php-app"
      }
    ],
    "ruby_version": "1.8.7",
    "activity": "configure",
    "ruby_stack": "ruby_enterprise",
    "stack": {
      "name": "SampleStack3"
    },
    "instance": {
      "ip": null,
      "id": "3d9fc521-1bfa-4d82-b74c-f0761383394c",
      "private_ip": "10.132.159.132",
      "aws_instance_id": "i-d75147d4",
      "backends": 5,
      "layers": [
        "lb"
      ],
      "public_dns_name": null,
      "hostname": "stratus",
      "region": "ap-northeast-1",
      "instance_type": "m1.small",
      "availability_zone": "ap-northeast-1a",
      "private_dns_name": "ip-10-132-159-132.ap-northeast-1.compute.internal",
      "architecture": "i386"
    },
    "agent_version": "104",
    "layers": {
      "lb": {
        "id": "f64dc03e-0c01-4f41-b588-b8289e03deca",
        "name": "Load Balancer",
        "instances": {
          "stratus": {
            "ip": null,
            "elastic_ip": "54.249.245.56",
            "private_ip": "10.132.159.132",
            "aws_instance_id": "i-d75147d4",
            "created_at": "2013-03-13T06:38:58+00:00",
            "status": "online",
            "booted_at": "2013-03-13T06:40:49+00:00",
            "backends": 5,
            "public_dns_name": null,
            "region": "ap-northeast-1",
            "instance_type": "m1.small",
            "availability_zone": "ap-northeast-1a",
            "private_dns_name": "ip-10-132-159-132.ap-northeast-1.compute.internal"
          }
        }
      },
      "php-app": {
        "id": "c38c9a7f-90eb-4764-8ebd-3b48592f57cb",
        "name": "PHP Application Server",
        "instances": {
          "altocumulus": {
            "ip": "54.249.207.244",
            "elastic_ip": null,
            "private_ip": "10.162.54.166",
            "aws_instance_id": "i-2b5d4b28",
            "created_at": "2013-03-13T06:48:12+00:00",
            "status": "online",
            "booted_at": "2013-03-13T06:49:30+00:00",
            "backends": 5,
            "public_dns_name": "ec2-54-249-207-244.ap-northeast-1.compute.amazonaws.com",
            "region": "ap-northeast-1",
            "instance_type": "m1.small",
            "availability_zone": "ap-northeast-1a",
            "private_dns_name": "ip-10-162-54-166.ap-northeast-1.compute.internal"
          },
          "stratocumulus": {
            "ip": "54.249.153.134",
            "elastic_ip": null,
            "private_ip": "10.152.46.168",
            "aws_instance_id": "i-07405604",
            "created_at": "2013-03-13T07:30:05+00:00",
            "status": "online",
            "booted_at": "2013-03-13T07:31:22+00:00",
            "backends": 5,
            "public_dns_name": "ec2-54-249-153-134.ap-northeast-1.compute.amazonaws.com",
            "region": "ap-northeast-1",
            "instance_type": "m1.small",
            "availability_zone": "ap-northeast-1a",
            "private_dns_name": "ip-10-152-46-168.ap-northeast-1.compute.internal"
          }
        }
      }
    },
    "sent_at": 1363160598,
    "rails_stack": {
      "name": null
    }
  },
  "opsworks_custom_cookbooks": {
    "recipes": [

    ],
    "enabled": false
  },
  "deploy": {
    "php_app": {
      "memcached": {
        "host": null,
        "port": 11211
      },
      "rails_env": null,
      "migrate": false,
      "ssl_certificate_ca": null,
      "auto_bundle_on_deploy": true,
      "ssl_support": false,
      "domains": [
        "php_app"
      ],
      "database": {
        "reconnect": true,
        "host": null,
        "database": "php_app",
        "password": null,
        "username": "root"
      },
      "ssl_certificate": null,
      "symlink_before_migrate": {
        "config/opsworks.php": "opsworks.php"
      },
      "application_type": "php",
      "symlinks": {
      },
      "mounted_at": null,
      "restart_command": "echo 'restarting app'",
      "document_root": null,
      "sleep_before_restart": 0,
      "application": "php_app",
      "deploy_to": "/srv/www/php_app",
      "scm": {
        "user": null,
        "repository": "git://github.com/funasaki/helloworld-php.git",
        "password": null,
        "revision": null,
        "scm_type": "git",
        "ssh_key": null
      },
      "ssl_certificate_key": null
    }
  },
  "haproxy": {
    "static_applications": {
    },
    "health_check_method": "GET",
    "rails_applications": {
    },
    "nodejs_backends": [

    ],
    "php_applications": {
      "php_app": {
        "domains": [
          "php_app"
        ],
        "application_type": "php",
        "mounted_at": null
      }
    },
    "enable_stats": true,
    "nodejs_applications": {
    },
    "php_backends": [
      {
        "ip": "10.162.54.166",
        "backends": 10,
        "name": "altocumulus"
      },
      {
        "ip": "10.152.46.168",
        "backends": 10,
        "name": "stratocumulus"
      }
    ],
    "rails_backends": [

    ],
    "stats_url": "/haproxy?stats",
    "static_backends": [

    ],
    "stats_password": "mypassword",
    "stats_user": "opsworks",
    "health_check_url": "/"
  },
  "ssh_users": {
  }
}

さらにログファイルも当然だがあった。

$ ls /var/log/aws/opsworks
installer.log           opsworks-agent.log  user-data.log
opsworks-agent-cli.log  updater.log

Amazon RDS(MySQL)のログファイル出力について

Amazon RDSでログファイルにアクセス可能になりました。

【AWS発表】Amazon RDS - より簡単にログファイルにアクセス可能に

今まではRDS MySQLのgeneral logなどはRDSのテーブル内に出力していました。
上記機能により、テーブルではなくファイルのみに出力させることが可能となっています。

f:id:kenjifunasaki:20130313143806p:plain

TABLEかFILEか、どちらかを選択する形です。

ファイルの出力先の場所はgeneral_log_fileの場合は、/rdsdbdata/log/general/mysql-general.logですが、こちらの出力先の場所を変更することは出来ないようです。

また、ログファイルのサイズが大きくなりすぎてしまい、DBのパフォーマンスに影響が出てしまうのを避けるため、以下の条件になったときにログファイルが自動的にrotateされます。

  • When disk space usage is greater than 90% of the allocated space and a log uses either more than 10% of the allocated storage or the log uses greater than 5 GB.
  • If a log uses more than 20% of the allocated storage or a log uses greater than 10 GB, regardless of total disk usage.

参照
http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.Concepts.MySQL.html

GitマスターサーバをAmazon Linuxにインストールしてみる

Gitマスターサーバにgitをインストールする。

$ sudo yum install git git-all git-daemon
$ git --version
git version 1.7.4.5

xinetdを使ってgitサーバを起動する

sudo /etc/init.d/xinetd start

gitの設定ファイルでdisable = no に変更

sudo vi /etc/xinedt.d/git
# default: off
# description: The git damon allows git repositories to be exported using \
#       the git:// protocol.

service git
{
        disable         = no
        socket_type     = stream
        wait            = no
        user            = nobody
        server          = /usr/libexec/git-core/git-daemon
        server_args     = --base-path=/var/lib/git --export-all --user-path=publ
ic_git --syslog --inetd --verbose
        log_on_failure  += USERID
}

xinetdをrestartする。

sudo /etc/init.d/xinetd restart

リポジトリを作成する。

cd /var/lib/git
sudo mkdir test
cd test
sudo git --bare init --shared
sudo chmod 777 -R test

次にリモートのGitクライアントの設定
Gitをインストールする。

sudo yum install git

サンプルテキストの作成

mkdir ~/test
cd ~/test
vi test.txt
aiueo

作成したテキストをcommitする

git init
git add .
git commit -m "First Commit"

リモートのGitマスターサーバに接続するためのSSHの設定をする

vi ~/.ssh/config
Host ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com
User ec2-user
IdentityFile ~/.ssh/xxxxxx.pem
sudo chmod 600 /home/ec2-user/.ssh/config
sudo chmod 600 /home/ec2-user/.ssh/xxxxxx.pem

リモートのマスターを追加する

$ git remote add origin ssh://ec2-user@ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com/var/lib/git/test

リモートのマスターのリポジトリにpushする。

$ git push origin master

これで、マスター側の該当ディレクトリを見ると

$ ls -F
branches/  config*  description*  HEAD*  hooks/  info/  objects/  refs/

branchesディレクトリ等いろいろできている。

まだ確認できることはありそうだけど、今回はここまで。

ElastiCacheを使ってみる

Amazon ElastiCacheはインストール、構築不要のmemcachedクラスタ
現状はMemcached 1.4.5, 1.4.14 に対応しているようです。

使ってみて気づいたことは以下です。

  • ElastiCacheへはEC2(VPC)インスタンスからのみアクセスが可能。
    • ElastiCacheのセキュリティグループの設定により、指定したセキュリティグループを持ったインスタンスしかアクセスを許さない。
  • Management ConsoleでJavaPHPのクライアントアクセスライブラリを取得可能

それではElasticCacheを起動して、Java Clientからアクセスしてみます。

まずは、作成・起動。
Management Consoleから、
f:id:kenjifunasaki:20130214180429p:plain
ElastiCacheを起動します。
f:id:kenjifunasaki:20130214180450p:plain
起動画面で名前、Node Type(インスタンスのタイプ)、Nodeの数、等を指定します。
f:id:kenjifunasaki:20130214180725p:plain
Cache Security Groupを指定します。ここで指定するものは事前に作成しておいたものを利用します。Cache Security Groupの中では、EC2のどのセキュリティグループ(を持つインスタンス)をアクセス許可するかを指定します。
f:id:kenjifunasaki:20130214180814p:plain
確認してLaunch Cache Clusterします。
f:id:kenjifunasaki:20130214181134p:plain
これで起動完了すれば、エンドポイントおよびデフォルトポート11211番を使ってアクセスできるようになります。

ただ、上記にもあるようにEC2のセキュリティグループを持ったインスタンスしかアクセスできないため、ローカルのPCからElastiCacheクラスタノードに直接アクセスできません。(試したかったのですが。)

なので、今回はEC2インスタンス上で以下のJavaソースコードを作成して、コンパイルしたものでアクセスしてみました。

import java.io.IOException;
import java.net.InetSocketAddress;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.BinaryConnectionFactory;
import net.spy.memcached.ClientMode;
import net.spy.memcached.MemcachedClient;


public class ElastiCacheSample {

        public static void main(String[] args) {
                String hostname = "cachecluster2.wfisum.cfg.apne1.cache.amazonaws.com";
                int portNum = 11211;
                String hostnamePort = hostname + ":11211";
                String key = "12345";

                try {
                        MemcachedClient c = new MemcachedClient(new InetSocketAddress(hostname, portNum));
                        // Store a value (async) for one hour
                        c.set("key1", 3600, key);
                        // Retrieve a value.
                        Object myObject=c.get("key1");
                        c.shutdown();
                } catch (IOException e) {
                        e.printStackTrace();
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
}

今回はMemcachedClientのshutdown()メソッドを呼び出して、終了するようにしています。

こちらを実行すると

$ java -cp ".:./AmazonElastiCacheClusterClient-1.0.jar" ElastiCacheSample

2013-02-14 18:20:25.826 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/10.160.135.101:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2013-02-14 18:20:25.837 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@5ca46701
2013-02-14 18:20:25.858 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/10.160.135.101:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2013-02-14 18:20:25.859 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/10.160.83.93:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2013-02-14 18:20:25.865 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@42704baa
2013-02-14 18:20:25.866 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@5a77a7f9
2013-02-14 18:20:25.915 INFO net.spy.memcached.MemcachedConnection:  Shut down memcached client

以上のようにmemcachedに指定したkeyが追加され、取得も無事できました。