2012年1月25日水曜日

DynamoDBってなんじゃ?(SDK編)

前回は、AWSコンソールをつかってテーブルの作成まで行いました。
今回は、それらのテーブルにSDKをつかってアクセスしてみます。
ここでは、PHP SDKを使用してみます。

クラスの初期化
DynamoDBクラスの初期化は以下のように行います。
キーなどのパラメータは認証用のファイルに記載しておき省略することも可能です。
$ddb = new AmazonDynamoDB(
  array(
   'key' => 'xxxxxxxxxxxxxxx',
   'secret' => 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyy',
   'default_cache_config' => '/tmp/cache'));

データの投入
次に、前回作成した2つのテーブルにそれぞれデータを投入してみます。
値の指定は、DynamoDBの型名とstring値を紐付けた形で投入するようです。
//book
$books = array(
array('1', '978-4274066306', 'Joel on Software'),
array('2', '978-0321413093', 'Implementation Patterns'),
array('3', '978-1244865723', 'Agile Software Development'),
);
for($i=0; $i<count($books); $i++){
  $ddb->put_item(array(
    'TableName' => 'book',
    'Item' => array(
      'id'   => array(AmazonDynamoDB::TYPE_NUMBER => (string)$books[$i][0]),
      'isbn' => array(AmazonDynamoDB::TYPE_STRING => (string)$books[$i][1]),
      'name' => array(AmazonDynamoDB::TYPE_STRING => (string)$books[$i][2]),
     )
  ));
}

//comment
$comments = array(
  array('1', strtotime('-10 days'), 'memorycraft', 'i like this'),
  array('1', strtotime('-7 days'), 'hoge', 'i never like this'),
  array('2', strtotime('-9 days'), 'moge', 'this is awesome'),
);
for($i=0; $i<count($comments); $i++){
  $ddb->put_item(array(
    'TableName' => 'comment',
    'Item' => array(
      'book_id'    => array(AmazonDynamoDB::TYPE_NUMBER => (string)$comments[$i][0]),
      'posted_at'  => array(AmazonDynamoDB::TYPE_NUMBER => (string)$comments[$i][1]),
      'username'   => array(AmazonDynamoDB::TYPE_STRING => (string)$comments[$i][2]),
      'message'    => array(AmazonDynamoDB::TYPE_STRING => (string)$comments[$i][3]),
    )
  ));
}

データアクセス
続いて、先程データを投入したテーブルに対して、値の取得を行なってみます。
Hashのプライマリキーで一意に取得できる場合は、下記のようにget_itemで行います。
//Hashプライマリキーで完全一致
echo 'get_item (1) ' .
print_r(
  $ddb->get_item(
    array(
      'TableName' => 'book',
      'Key' => array('HashKeyElement' => array(AmazonDynamoDB::TYPE_NUMBER => '1')
    )
  )->body->Item->to_json(),
  true
) . "\n";
出力は以下のようになります。
get_item (1) {"id":{"N":"1"},"isbn":{"S":"978-4274066306"},"name":{"S":"Joel on Software"}}

複合プライマリキーを使い、Hashキーを指定し、Rangeキーで絞るような場合は、queryを使用します。
//複合キーで検索
echo 'query ' .
print_r(
  $ddb->query(
    array('TableName' => 'comment',
      'HashKeyValue' => array(AmazonDynamoDB::TYPE_NUMBER => '1'),
      'ConsistentRead' => true,
      'RangeKeyCondition' => array(
        'ComparisonOperator' => AmazonDynamoDB::CONDITION_GREATER_THAN_OR_EQUAL,
        'AttributeValueList' => array(array(AmazonDynamoDB::TYPE_NUMBER => (string)strtotime('-8 days')))
      )
    )
  )->body->Items->to_json(),
  true
) . "\n";
出力は以下のようになります。
query {"0":{"book_id":{"N":"1"},"message":{"S":"i never like this"},"posted_at":{"N":"1326880572"},"username":{"S":"hoge"}}}

また、キー値以外で検索を行う場合は、scan関数を利用します。
//キー以外で検索
echo 'scan ' .
print_r(
  $ddb->scan(
    array(
      'TableName' => 'comment',
      'AttributeToGet' => array('username', 'message'),
      'ScanFilter' => array(
        'username' => array(
          'ComparisonOperator' => AmazonDynamoDB::CONDITION_EQUAL,
          'AttributeValueList' => array(
            array(AmazonDynamoDB::TYPE_STRING => 'memorycraft')
          )
        )
      )
    )
  )->body->Items->to_json(),
  true
) . "\n";
出力は以下のとおりです。
scan {"0":{"book_id":{"N":"1"},"message":{"S":"i like this"},"posted_at":{"N":"1326621372"},"username":{"S":"memorycraft"}}}

テーブルの作成
ちなみにテーブルの作成は以下のように行います。
//book
$ddb->create_table(array(
        'TableName' => 'book',
        'KeySchema' => array(
                'HashKeyElement' => array(
                        'AttributeName' => 'id',
                        'AttributeType' => AmazonDynamoDB::TYPE_NUMBER
                )
        ),
        'ProvisionedThroughput' => array(
                'ReadCapacityUnits' => 50,
                'WriteCapacityUnits' => 10
        )
));

//comment
$ddb->create_table(array(
        'TableName' => 'comment',
        'KeySchema' => array(
                'HashKeyElement' => array(
                        'AttributeName' => 'book_id',
                        'AttributeType' => AmazonDynamoDB::TYPE_NUMBER
                ),
                'RangeKeyElement' => array(
                        'AttributeName' => 'posted_at',
                        'AttributeType' => AmazonDynamoDB::TYPE_NUMBER
                )
        ),
        'ProvisionedThroughput' => array(
                'ReadCapacityUnits' => 50,
                'WriteCapacityUnits' => 10
        )
));

この際、テーブルの作成には時間が多少かかるので、テーブルを作成したあとに続けてデータ追加処理など行う場合は、以下のように待機します。
foreach(array('book', 'comment') as $table_name){
  $count = 0;
  echo $table_name . " : status ";
  do {
    sleep(1);
    $count++;
    $res = $ddb->describe_table(array(
      'TableName' => $table_name
    ));
    $status = (string)$res->body->Table->TableStatus;
    echo ($status === 'ACTIVE' ? $status . "\n" : '.');
  }
  while ((string) $res->body->Table->TableStatus !== 'ACTIVE');
}
出力は以下のようになります。
book : status ...........................ACTIVE
comment : status ACTIVE


テーブルの削除
テーブルの削除は以下のように行います。
foreach(array('book', 'comment') as $table_name){
        $ddb->delete_table(
                array('TableName' => $table_name)
        );
}


RDBとは違うので、データの構成などに工夫が必要ですが、RDBとの使い分けで非常に高い効果を発揮すると思います。
東京リージョンへの展開が待ち遠しいですが、US-Eastに立てたインスタンスからはRTTがないので、ハイパフォーマンスを体験できます。

以上です。

DynamoDBってなんじゃ?(AWSコンソール編)

AWSがDynamoDBというサービスをリリースしました。リリースペース早すぎですね。
DynamoDBは高可用で超柔軟なスケーラビリティをもつNoSQLサービスです。

あれ?SimpleDBはどうしたの?と思ってしまいますが、SimpleDBよりも更に柔軟でスケーラブルです。

DyanmoDBはSimpleDBと比べて以下のような利点があります。
  • SimpleDBでは、1つのドメイン(DBでいうテーブル)につき10GBというデータ量制限がありましたが、DynamoDBでは無制限で、ドメイン制限を超えた場合のスケーリングがアプリケーションレイヤーの設計にまで影響していたのが解消され、カスタマイズされたConsistentHashing法により自動的にスケーリングが行われます。
  • DynamoDBではスループットを設定できるため、アクセス数が増加しても低レイテンシが保証されます。
  • SimpleDBではマシン時間での課金でしたが、DynamoDBではスループットによる課金です。ユーザーはより費用の見積もりがしやすくなりました。
  • SimpleDBではすべてのアトリビュート(カラム)にインデックスが貼られていました。DynamoDBではシングルプライマリキーもしくはコンポジットプライマリキーにのみインデックスを貼ることで高パフォーマンスを図っています。


それではさっそく触ってみます。

AWSコンソールをみると、左はじにDynamoDBのタブが見えます。





これをクリックするとDynamoDBのダッシュボードが表示されます。
「Create Table」をクリックして、テーブルの設定を行います。




まず、テーブル名とプライマリキーを設定します。
プライマリキーは単一のHashキーかHashとRangeの複合キーが設定できます。
ここではbookというテーブル名でシングルHashキーを設定して「Continue」をクリックします。




次に必要なスループットを設定します。
Read CapacityとWrite Capacityの値を設定しますが、
それぞれ1秒に読み書きされる回数の見積もりと1アイテム(DBでいうところの行)の平均データサイズで決まります。
つまり

Read Capacity:1秒間に読み込みされる回数 × 1つのアイテムの平均サイズ
Write Capacity:1秒間に書き込みされる回数 × 1つのアイテムの平均サイズ

という計算のもと設定します。




また、「Help me calculate ,,,」というチェックを入れると、読み込み回数やデータの平均サイズなどを入力して求めることもできます。




「Continue」をクリックすると、Alarmの設定画面に移ります。
ここでは上記で設定したスループットの何割を超えたら通知するかを設定できます。設定したスループット以上の性能はでないため、これで性能を監視し、必要に応じてスループットをアップするような運用になります。




適宜設定して「Create Table」をクリックするとテーブルが作成されます。



これでテーブルの作成が終わりました。
作成されたテーブルが一覧画面に表示され、行を選択すると、プロパティ情報や現在のスループットやレイテンシなどが表示されています。
またCloudWatchのメトリクスやアラームの情報なども確認できます。



追加で、book_idとposted_atを複合ハッシュキーにもつcommentというテーブルも作成します。



とりあえずテーブルまでできました。
次回はSDKからDynamoDBにアクセスしてみます。

今回は以上です。


2012年1月6日金曜日

S3ってなんじゃ?(オブジェクトの自動削除の設定)

S3でオブジェクトのライフサイクルが設定できるようになりました。
これにより特定のルールで自動削除ができます。

さっそく触ってみます。

左ペインのバケット一覧の中で、バケット名を右クリックし、「Properties」を選択し、下ペインにバケットの設定を表示させます。




ここでは例として、expire-testというバケットに下のようなファイル群があるとします。




下部ペインのバケット設定の一番右に「Lifecycle」というタブがあるので、クリックします。
ここで、オブジェクトの自動削除の設定を追加できます。
設定項目は

  • Enabled  :有効フラグ、この設定を有効にするか無効にするかのチェックです。
  • Name   : 設定名、設定が複数あるときに判別しやすくする為です。
  • Prefix   :削除対象のオブジェクトのキー(パス名)に対するプリフィックス。空白の場合はすべてのオブジェクトが対象になります。
  • Expiration :有効期限、オブジェクトが作成された日からの日数です。

になります。
ここでは下記のように設定しました。

設定1:

  • Name   :Expiration1
  • Prefix   :*.jpg
  • Expiration :1

設定2:

  • Name   :Expiration1
  • Prefix   :Blog
  • Expiration :1

設定3:

  • Name   :Expiration1
  • Prefix   :capture
  • Expiration :1 




1日後、確認すると、以下のようになっています。



設定1で「*.jpg」というパターン表記をしましたが、kabegami_336.jpgが削除されていません。このPrefixはあくまでプリフィクスで、ワイルドカードやオブジェクトキーの正規表現は使用できないということになります。
設定2で指定した「Blog」に前方一致したBlogs-1.png,Blogs-2.png,Blogs-3.pngが正常に削除されました。
設定3で指定した「capture」に前方一致したcaptureフォルダとその中身が正常に削除されました。

細かいコントロールを望むのであれば、オブジェクトキーの正規表現ができれば嬉しいですが、これだけでも十分便利になりますね。

以上です。

2012年1月1日日曜日

VPCってなんじゃ?(ENI編)

今回は新しく追加されたENI(Elastic Network Interface)について調べてみました。

ENI(Elastic Network Interface)とは、EC2のNICにあたるもので、いままでインスタンスに直接付与されていたIPアドレスなどのネットワーク情報を、ENIに付与させることでより柔軟なネットワーク構成を実現するためのものだそうです。ENIはVPCでのみ使用出来ます。

コンソールのEC2タブをクリックすると左ペインのメニュー下部に「Network Interface」という項目があります。





これをクリックすると以下のようなENIの一覧画面が表示されます。
すでにVPCインスタンスを起動している場合は、VPCインスタンスにデフォルトでセットされているeth0のENIが表示されています。



新たにVPCインスタンスを起動してみます。
VPCとサブネットは以下のとおりです。

・VPC
10.0.0.0/16


・Subnet
publicサブネット:10.0.0.0/24
      privateサブネット:10.0.1.0/24




ENIの画面で「Create Network Interface」をクリックします。




ENIの設定ダイアログが表示されるので、publicサブネットで10.0.0.12のIPで登録します。




するとENIの一覧に新しくENIが追加されます。
ENIに設定できるSecurityGroupはEC2のものではなくVPCのセキュリティグループになります。

次に、EC2タブでVPCインスタンスを起動します。
Subnetはprivateサブネット(10.0.1.0/24)にします。




INSTANCE DETAILのフェーズで、ダイアログ下部にVPCのIPアドレスを設定できます。
ここで、「IP Address」の欄にプライベートIPを設定できます。ここで指定するIPはVPCにデフォルトでセットされているeth0のプライベートIPアドレスです。eth0は取り外しできず、基本のIPとなるため。ここに所属しているサブネットのレンジ内のIPアドレスを設定します。
ここでは、10.0.1.12を指定します。

また、「Additional Network Interface」という項目があり、ここに2枚目のENIを指定できます。選択肢から未使用の既存のENIを選べるので、ここで先程作成した、publicのENI(10.0.0.12)を指定します。




すると、起動したVPCインスタンスのプロパティ画面で、「Network Interface」欄にeth0, eth1と2つのENIが設定されていることがわかります。これはまさにNICが2枚挿されているのと同じ状態です。




 privateとpublicのENIを逆にしても同じように設定できますし、eth0とeth1に両方publicのIPを設定することもできます。

また、ENIに付与するプライベートIPアドレスはVPCインスタンスと同様、サブネットの範囲内のIPアドレスしか付与できません。






また、ElasticIPをENIに付与することができます。ただし、2つのENIに2つのEIPを設定することは現状できません。




最初に追加ENIなしで、あとからAttachもできます。




しかし、ifconfigをみると、
eth0      Link encap:Ethernet  HWaddr 02:3D:6E:63:F7:40 
          inet addr:10.0.0.20  Bcast:10.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::3d:6eff:fe63:f740/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:551 errors:0 dropped:0 overruns:0 frame:0
          TX packets:527 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:58037 (56.6 KiB)  TX bytes:53007 (51.7 KiB)
          Interrupt:10

lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

と、2枚目が認識されていません。
2枚目のENIはどうやら自分でLinuxに設定をする必要があるようです。


 次に、EC2 API ToolsでVPCインスタンスを起動してみます。 最新バージョンのec-run-instanceには、以下のようにENIに関するオプションが用意されているようです。
     -a, --network-interface NETWORKINTERFACE
          Specifies the network interface for the launched instance.
          The format of the NETWORKINTERFACE definition is as follows:
           - For an existing NETWORKINTERFACE - <eni>:<dev index>
           - For a new NETWORKINTERFACE - :<dev index>:<subnet>[:<description>[:<priv IP>[:<SGs>[:<DOT>]]]]
          where SGs is a comma separated list of security group IDs and DOT is
          either true or false, denoting whether to delete the interface on terminate.



ここで、パブリックサブネットで以下のようにeth0とeth1に既存のENIを設定してみます。
$ ec2-run-instances ami-0644f007 -t m1.small -a eni-37ae7e5e:0 -a eni-76e73a1f:1 --region ap-northeast-1 -z ap-northeast-1a -s subnet-10a57379
RESERVATION r-97f20997 821635308497 
INSTANCE i-632dfa63 ami-0644f007   pending  0  m1.small 2012-01-21T11:50:36+0000 ap-northeast-1a aki-ec5df7ed   monitoring-disabled  10.0.0.109 vpc-18a57371 subnet-10a57379 ebs     paravirtual xen  sg-53afbc3f default
NIC eni-5de73a34 subnet-10a57379 vpc-18a57371 821635308497 in-use 10.0.0.109  true
NICATTACHMENT eni-attach-22a9504b 0 attaching Sat Jan 21 20:50:36 JST 2012 true
GROUP sg-53afbc3f default



、、、が、どちらのENIもアタッチできていません。




またeth0だけでもアタッチできず、
$ ec2-run-instances ami-0644f007 -t m1.small -a eni-37ae7e5e:0 --region ap-northeast-1 -z ap-northeast-1a -s subnet-10a57379
RESERVATION r-dff60ddf 821635308497 
INSTANCE i-0d28ff0d ami-0644f007   pending  0  m1.small 2012-01-21T12:31:27+0000 ap-northeast-1a aki-ec5df7ed   monitoring-disabled  10.0.0.117 vpc-18a57371 subnet-10a57379 ebs     paravirtual xen  sg-53afbc3f default
NIC eni-37e13c5e subnet-10a57379 vpc-18a57371 821635308497 in-use 10.0.0.117  true
NICATTACHMENT eni-attach-40a85129 0 attaching Sat Jan 21 21:31:27 JST 2012 true
GROUP sg-53afbc3f default



IP指定+eth1も無理なようでした。。
ec2-run-instances ami-0644f007 -t m1.small --private-ip-address 10.0.0.12 -a eni-76e73a1f:1 --region ap-northeast-1 -z ap-northeast-1a -s subnet-10a57379

指定の仕方が間違っているのか、デフォルトで自動にプライベートIPが割り当てられているようでした。 
これは宿題にしたいと思います。 以上です。

VPCってなんじゃ?(public subnet編)

あけましておめでとうございます。本年もよろしくお願いいたします。
今年の一発目は今さらながらVPCをさわってみたいと思います。

VPCはAWS内にプライベートなネットワークを構成でき、インスタンスレベルではなくネットワークレベルでのセキュリティや経路の制御を行うことができるサービスです。これによって、いままでデータセンターでやっていたようにサブネットの構成やVPNなどを扱うことが可能になります。VPCのネットワーク空間の中にEC2インスタンスなどを配置することによって、そのインスタンス自身はネットワークのIn/Outをあまり気にすることなく使用できます。

VPCでは用途に応じたネットワーク空間をつくるために、複数のサブネット、Inbound,OutboundのIPとポートの制御、VPNやインターネットへのゲートウェイ、ルーティングテーブルなどが用意されています。
今回は、パブリックなサブネットをもつVPCを作ってみたいと思います。

コンソールのVPCタブを押すと、VPCのダッシュボードが表示され、「Get started creating a VPC」という大きなボタンがあるので、それをクリックします。


すると、ダイアログが開き、VPCのタイプが選択できます。
これはいくつかの典型的なVPCの用途に合わせてゲートウェイやルーティングテーブルなどのプリセットを用意できるように対話式で進んでいけるようになっています。
ここでは一番上の「VPC with a Single Public Subnet Only」を選択してみます。


パブリックサブネットはインターネットに直面するサブネットになるので、内部に作成したEC2インスタンスはVPCを使用しないときと大きくは変わりませんが、プライベートIPを自由に設定できたり、インスタンスとインターネットの間のルーティングを制御できるなどのメリットがあります。

デフォルトの設定が表示されます。
CIDRは10.0.0.0/16となっています。



各項目の右側の「Edit〜」でデフォルト設定を変更できます。例えばPublicサブネットのAZを指定する場合は、以下のように変更します。



作成が完了すると、ダッシュボードに作成されたVPCの各オブジェクトの個数が表示されます。
Subnetは今回はPublic Subnetがひとつなので1つになります。


ここまでで、VPCの作成が完了しました。
次に、このVPC内にEC2インスタンスを1つ作成してみたいと思います。

EC2タブで「Launch Instance」をクリックすると、AMIの選択画面が表示されます。
今回はAmazon Linux AMIを選択します。



インスタンスパラメータの設定ダイアログが開きます。
VPCではt1.smallは使用できないので、m1.smallを選択します。
すると、「Launch Instance」のアコーディオン内の「Launch Into」の項目にVPCのタブが使用できるようになるので、VPCを選択します。自動的に先ほど作成したSubnetが選択されています。この状態で「Continue」をクリックします。



次にインスタンスの詳細設定をします。
VPCで特徴的なのは下段の「VPC Advanced Options」という項目です。
ここで、サブネット内でのこのインスタンスのプライベートIPアドレスを自由に指定することができます。
ここでは、10.0.0.8を指定し、「Continue」をクリックします。



インスタンス名をつけ、「Continue」をクリックします。



キーペアを作成します。ここでは既存のキーペアを指定して「Continue」をクリックします。



セキュリティグループを指定します。ここで指定したり作成したりするセキュリティグループは通常のEC2のセキュリティグループではなくVPC内で使用する専用のセキュリティグループです。
VPC内のセキュリティグループではInboundのみではなく、Outboundも制御することができます。
ここでは、public1というグループをつくり、特定のIPからSSHを受け入れるようにしました。



「Continue」をクリックすると、すべての設定の確認画面が表示されます。
変更があれば各項目の右側のリンクやBackリンクで修正をします。問題なければ「Launch」ボタンをクリックして、操作を完了します。



これでVPC内にEC2インスタンスが起動されました。
インスタンス情報にもVPCの情報が記載されていることがわかります。



次にインスタンスにEIPを割り当てます。
まずEIPを確保するために「Allocate Address」をクリックします。



ここで、VPC用に割り当てるのか通常のEC2用に割り当てるのかを選択します。
VPCを選択して、「Yes,Allocate」をクリックします。



EIPを確保できたら、次にEIPを選択した状態で、インスタンスに割り当てるために「Associate Address」をクリックします。



するとインスタンスに割り当てるか、ネットワークカード(ENI)に割り当てるかを選択します。
ENIはEC2インスタンスのネットワークカードで、2枚挿しなどもでき、eth1であれば抜き差しも可能です。
ここでは、Network Interface(ENI)を選択します。Network Interfaceでは、先程立ち上げたEC2インスタンスのeth0が選択できます。eth0なので抜き差しできないためインスタンスに直接割り当てているのと変わりないと思いますが、新しい機能なので使ってみます。
ここで、「Yes,Associate」をクリックすると、EC2インスタンス(のENI)にEIPが割り振られます。



これで、ひと通りの設定が完了しました。
次にSSHでEC2インスタンスに接続してみます。
$ ssh -i /Users/memorycraft/Development/cloudpack/myfirstcloud/keys/myfirstcloudkey.pem ec2-user@103.4.12.204
The authenticity of host '103.4.12.204 (103.4.12.204)' can't be established.
RSA key fingerprint is 40:cb:40:9d:39:9b:b2:d0:b9:47:43:fb:1d:db:d8:d0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '103.4.12.204' (RSA) to the list of known hosts.

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

See /usr/share/doc/system-release/ for latest release notes.

無事接続することができました。
自分のIPの情報を見てみます。
[ec2-user@ip-10-0-0-8 ~]$ ifconfig
eth0      Link encap:Ethernet  HWaddr 02:3D:4D:9C:4E:4D 
          inet addr:10.0.0.8  Bcast:10.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::3d:4dff:fe9c:4e4d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2516 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1961 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2159794 (2.0 MiB)  TX bytes:146611 (143.1 KiB)
          Interrupt:10

lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:24 errors:0 dropped:0 overruns:0 frame:0
          TX packets:24 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:2343 (2.2 KiB)  TX bytes:2343 (2.2 KiB)

10.0.0.8が割り振られているのがわかります。
このようにプライベートIPを指定できることで、より柔軟な構成を組むことができます。

今回はここまで。

VPCってなんじゃ?(private subnet編)

前回に引き続き、VPCです。
今回はpublicに加えてprivate subnetも作成してみます。

まず、前回と同様に、VPCを作成するために「Get started creating a VPC」もしくは「Create Another VPC」をクリックします。
そして今回は2番目の「VPC with Public and Private Subnets」を選択します。



すると、各項目がデフォルトで設定された状態で表示されます。
VPCが10.0.0.0/16、Publicが10.0.0.0/24、Privateが10.0.1.0/24と設定されています。
また、ここで「One NAT Instance with an Elastic IP Address」という項目があるのがわかります。
これはNATインスタンスと呼ばれる、PrivateとPublicの橋渡しをするための専用EC2インスタンスで、この設定ではNATインスタンスが起動されるようになっています。

ここでは今回は2つのサブネットのAZをaゾーンに設定して「Create VPC」をクリックします。



すると、作成が完了し、VPCのダッシュボードに作成された各オブジェクトが表示されます。




ここで「2 Subnets」もしくは左ペインのメニューにある「Subnets」をクリックして、サブネットの一覧を見てみます。すると設定にあった通り、10.0.0.0/24, 10.0.1.0/24の2つのサブネットがあります。

このうち、Public(10.0.0.0/24)の行を選択すると、下部ペインにルーティング情報が表示され、10.0.0.0/16が
local、0.0.0.0/0がigw-xxxxxというインターネットゲートウェイにルーティングされていることがわかります。



一方、Private(10.0.1.0/24)では、10.0.0.0/16がlocal、0.0.0.0/0がNATインスタンスにルーティングされているのがわかります。つまり、Privateから外部への通信はすべてNATインスタンスを経由することになります。




またNATインスタンスは以下のように、ElasticIPが割り振られており、PublicSubnet内にNATインスタンス専用のAMIから起動されていることがわかります。NATインスタンスだとわかるようにnatと名前をつけておきます。





ここで、PublicとPrivateにそれぞれEC2インスタンスを作成してみます。
まずはPublicのインスタンスです。
Subnetに10.0.0.0/24を選択し、IPを10.0.0.4として、public4という名前で起動します。
また、publicという名前のVPCセキュリティグループを新規作成します。





 また、このインスタンスは外部に面しているので、ENIにEIPを割り振ります。



 同じようにPrivateにもIPが10.0.1.4でprivate4という名前でインスタンスを起動します。EIPは振りません。
privateという名前のVPCセキュリティグループをつけて新規作成します。

VPCのセキュリティグループを見てみます。
defaultと、先程作成したpublic,privateの計3つのセキュリティグループがあります。
このうち、defaultはNATインスタンスに自動的に割り当てられています。



・defaultセキュリティグループでは、privateからアクセスされるnatインスタンスのためのグループなので、

  • Inbound - ALL:10.0.1.0/24
  • Outbound - ALL:0.0.0.0/0

とします。INとOUTで使用されるポートが決まっていたらポートも指定しますが、ここではALLとします。




・publicセキュリティグループは、インターネットからアクセスされ、またprivateサブネットへの踏み台とするため、ここではSSHで接続すると仮定して

  • Inbound - 22番ポート:接続するオフィスのIPアドレス
  • Outbound - ALL:0.0.0.0/0

とします。

もしWEBサーバーを置くなら、Inboundに80番ポート:0.0.0.0/0(ALL)を追加しますが、ここではOutboundを便宜上ALL:0.0.0.0/0としています。
(SSHの踏み台専用のインスタンスを用意するのであれば、publicセキュリティグループには22番ポートを加えずに、踏み台専用のセキュリティグループにオフィスからの22番のInboundとprivateに対しての22番のOutboundを用意します。)




・privateセキュリティグループでは、publicサブネットからのアクセスのみを受付けるため、

  • Inbound - 22番ポート:10.0.0.0/24
  • Outbound - ALL:0.0.0.0/0

とします。
(もし、踏み台専用のインスタンスを用意するのであれば、InboundのSourceをそのインスタンスのプライベートIPに固定します。)






ここまで設定したら、nat, public,privateの各インスタンスにSSHでアクセスしてみます。

natインスタンスにSSH

$ ssh -i /Users/memorycraft/Development/cloudpack/myfirstcloud/keys/myfirstcloudkey.pem ec2-user@103.4.12.222

ssh: connect to host 103.4.12.222 port 22: Operation timed out
タイムアウトしました。
NATインスタンスにはdefaultセキュリティグループが割り当てられており、外部からのアクセスを許可していないので、当然接続できません。



publicインスタンスにSSH

$ ssh -i ~/Development/cloudpack/myfirstcloud/keys/myfirstcloudkey.pem ec2-user@103.4.12.232
Last login: Wed Jan  4 19:22:54 2012 from 219.117.233.241.static.zoot.jp

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

See /usr/share/doc/system-release/ for latest release notes.
[ec2-user@ip-10-0-0-4 ~]$

接続できました。
publicサブネットはインターネットゲートウェイからルーティングされており、publicセキュリティグループでSSHを許可しているので、接続できます。


privateインスタンスにSSH

privateインスタンスはEIPがないのでそもそも接続できません。
ここではpublicインスタンス内からアクセスしてみます。

[ec2-user@ip-10-0-0-4 ~]$ ssh ec2-user@10.0.1.4
The authenticity of host '10.0.1.4 (10.0.1.4)' can't be established.
RSA key fingerprint is 51:f5:d1:f6:96:76:f0:8f:23:95:61:80:32:d1:50:51.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.0.1.4' (RSA) to the list of known hosts.
Permission denied (publickey).

通信はできるようですが、キーファイルがないために接続できないようです。
privateインスタンスの作成時にも既存のキーペアの設定を行った為です。
ここで、ローカルマシンのpemファイルを開いて、内容をコピーしpublicインスタンス内にpemファイルを作成します。

[ec2-user@ip-10-0-0-4 ~]$ vi ~/.ssh/myfirstcloudkey.pem
[ec2-user@ip-10-0-0-4 ~]$ chmod 600 ~/.ssh/myfirstcloudkey.pem

作成したpemファイルを用いてSSHアクセスします。
[ec2-user@ip-10-0-0-4 ~]$ ssh -i ~/.ssh/myfirstcloudkey.pem ec2-user@10.0.1.4

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

See /usr/share/doc/system-release/ for latest release notes.
[ec2-user@ip-10-0-1-4 ~]$

接続できました。
privateインスタンスではpublicサブネットからのSSHアクセスだけを受け付けているため、このように接続することができます。


また、つぎにpublic, privateからwww.google.comに対してtracerouteしてみます。

publicインスタンスからtraceroute
$ traceroute www.google.com
traceroute to www.google.com (74.125.235.113), 30 hops max, 60 byte packets
 1  ec2-175-41-192-56.ap-northeast-1.compute.amazonaws.com (175.41.192.56)  0.494 ms  0.478 ms  0.458 ms
 2  27.0.0.146 (27.0.0.146)  1.621 ms  1.608 ms  1.584 ms
 3  27.0.0.134 (27.0.0.134)  1.653 ms  1.636 ms  1.609 ms
 4  15169.tyo.equinix.com (203.190.230.31)  1.691 ms  1.667 ms  1.646 ms
 5  72.14.239.202 (72.14.239.202)  1.991 ms  1.961 ms  2.034 ms
 6  209.85.251.39 (209.85.251.39)  3.411 ms  3.547 ms  3.639 ms
 7  nrt19s02-in-f17.1e100.net (74.125.235.113)  2.219 ms  2.148 ms  2.372 ms

privateインスタンスからtraceroute
$ traceroute www.google.com
traceroute to www.google.com (74.125.235.180), 30 hops max, 60 byte packets
 1  10.0.0.133 (10.0.0.133)  0.441 ms  0.555 ms  0.535 ms
 2  ec2-175-41-192-58.ap-northeast-1.compute.amazonaws.com (175.41.192.58)  1.022 ms  0.996 ms  0.976 ms
 3  27.0.0.164 (27.0.0.164)  0.931 ms  0.993 ms  0.963 ms
 4  27.0.0.146 (27.0.0.146)  2.147 ms  2.262 ms  2.233 ms
 5  27.0.0.134 (27.0.0.134)  3.154 ms  3.259 ms  3.226 ms
 6  15169.tyo.equinix.com (203.190.230.31)  3.273 ms  2.876 ms  3.125 ms
 7  72.14.239.202 (72.14.239.202)  2.643 ms  2.480 ms  2.598 ms
 8  209.85.241.133 (209.85.241.133)  4.273 ms  4.365 ms  4.475 ms
 9  nrt19s12-in-f20.1e100.net (74.125.235.180)  3.596 ms  3.574 ms  3.664 ms

privateインスタンスからの場合、10.0.0.133(NATインスタンス)を経由しているのがわかります。
前出のルーティングテーブルと、セキュリティグループが機能していることがわかります。

上述のセキュリティグループでは使用するミドルウェアや要件によって、より詳細な設定をすべきです。今回はALLで許可をしましたが、WEBサーバーやDBサーバーなどを登場させた場合、80ポートや3306ポートなど、必要なポートにのみ許可を与えることでセキュリティレベルを高めるようにする必要があります。

また、セキュリティグループはインスタンスレベルでのファイアーウォール機能です。ネットワークレベルでのセキュリティにはNetwork ACLというものがVPCにありますので、次の機会に紹介したいと思います。

以上です。